// virtual LLXMLNodePtr LLFlyoutButton::getXML(bool save_children) const { LLXMLNodePtr node = LLComboBox::getXML(); node->setName(LL_FLYOUT_BUTTON_TAG); LLXMLNodePtr child; for (child = node->getFirstChild(); child.notNull();) { if (child->hasName("combo_item")) { child->setName(LL_FLYOUT_BUTTON_ITEM_TAG); //setName does a delete and add, so we have to start over child = node->getFirstChild(); } else { child = child->getNextSibling(); } } return node; }
void LLUICtrlFactory::setupPaths() { std::string filename = gDirUtilp->getExpandedFilename(LL_PATH_SKINS, "paths.xml"); LLXMLNodePtr root; BOOL success = LLXMLNode::parseFile(filename, root, NULL); sXUIPaths.clear(); if (success) { LLXMLNodePtr path; for (path = root->getFirstChild(); path.notNull(); path = path->getNextSibling()) { LLUIString path_val_ui(path->getValue()); std::string language = LLUI::getLanguage(); path_val_ui.setArg("[LANGUAGE]", language); if (std::find(sXUIPaths.begin(), sXUIPaths.end(), path_val_ui.getString()) == sXUIPaths.end()) { sXUIPaths.push_back(path_val_ui.getString()); } } } else // parsing failed { std::string slash = gDirUtilp->getDirDelimiter(); std::string dir = "xui" + slash + "en-us"; llwarns << "XUI::config file unable to open: " << filename << llendl; sXUIPaths.push_back(dir); } }
void replaceSubstitutionStrings(LLXMLNodePtr node, StringMap& replacements) { //llwarns << "replaceSubstitutionStrings" << llendl; // walk the list of attributes looking for replacements for (LLXMLAttribList::iterator it=node->mAttributes.begin(); it != node->mAttributes.end(); ++it) { std::string value = it->second->getValue(); if (value[0] == '$') { value.erase(0, 1); // trim off the $ std::string replacement; StringMap::const_iterator found = replacements.find(value); if (found != replacements.end()) { replacement = found->second; //llinfos << "replaceSubstitutionStrings: value: \"" << value << "\" repl: \"" << replacement << "\"." << llendl; it->second->setValue(replacement); } else { llwarns << "replaceSubstitutionStrings FAILURE: could not find replacement \"" << value << "\"." << llendl; } } } // now walk the list of children and call this recursively. for (LLXMLNodePtr child = node->getFirstChild(); child.notNull(); child = child->getNextSibling()) { replaceSubstitutionStrings(child, replacements); } }
bool LLXUIParser::writeF64Value(const void* val_ptr, const name_stack_t& stack) { LLXMLNodePtr node = getNode(stack); if (node.notNull()) { node->setDoubleValue(*((F64*)val_ptr)); return true; } return false; }
bool LLXUIParser::writeUUIDValue(const void* val_ptr, const name_stack_t& stack) { LLXMLNodePtr node = getNode(stack); if (node.notNull()) { node->setStringValue(((LLUUID*)val_ptr)->asString()); return true; } return false; }
bool LLXUIParser::writeU32Value(const void* val_ptr, const name_stack_t& stack) { LLXMLNodePtr node = getNode(stack); if (node.notNull()) { node->setUnsignedValue(*((U32*)val_ptr)); return true; } return false; }
// static LLView* LLComboBox::fromXML(LLXMLNodePtr node, LLView *parent, LLUICtrlFactory *factory) { std::string name("combo_box"); node->getAttributeString("name", name); std::string label(""); node->getAttributeString("label", label); LLRect rect; createRect(node, rect, parent, LLRect()); BOOL allow_text_entry = FALSE; node->getAttributeBOOL("allow_text_entry", allow_text_entry); S32 max_chars = 20; node->getAttributeS32("max_chars", max_chars); LLUICtrlCallback callback = NULL; LLComboBox* combo_box = new LLComboBox(name, rect, label, callback, NULL); combo_box->setAllowTextEntry(allow_text_entry, max_chars); combo_box->initFromXML(node, parent); const std::string& contents = node->getValue(); if (contents.find_first_not_of(" \n\t") != contents.npos) { llerrs << "Legacy combo box item format used! Please convert to <combo_item> tags!" << llendl; } else { LLXMLNodePtr child; for (child = node->getFirstChild(); child.notNull(); child = child->getNextSibling()) { if (child->hasName("combo_item")) { std::string label = child->getTextContents(); std::string value = label; child->getAttributeString("value", value); combo_box->add(label, LLSD(value) ); } } } combo_box->selectFirstItem(); return combo_box; }
bool LLNotificationTemplates::loadTemplates() { LL_INFOS() << "Reading notifications template" << LL_ENDL; // Passing findSkinnedFilenames(constraint=LLDir::ALL_SKINS) makes it // output all relevant pathnames instead of just the ones from the most // specific skin. std::vector<std::string> search_paths = gDirUtilp->findSkinnedFilenames(LLDir::XUI, "notifications.xml", LLDir::ALL_SKINS); std::string base_filename = search_paths.front(); LLXMLNodePtr root; BOOL success = LLXMLNode::getLayeredXMLNode(root, search_paths); if (!success || root.isNull() || !root->hasName( "notifications" )) { LL_ERRS() << "Problem reading XML from UI Notifications file: " << base_filename << LL_ENDL; return false; } clearTemplates(); for (LLXMLNodePtr item = root->getFirstChild(); item.notNull(); item = item->getNextSibling()) { 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")) { LL_WARNS() << "Unexpected entity " << item->getName()->mString << " found in notifications.xml [language=]" << LLUI::getLanguage() << LL_ENDL; continue; } } return true; }
bool LLFontRegistry::initFromXML(LLXMLNodePtr node) { LLXMLNodePtr child; for (child = node->getFirstChild(); child.notNull(); child = child->getNextSibling()) { std::string child_name; child->getAttributeString("name",child_name); if (child->hasName("font")) { LLFontDescriptor desc; bool font_succ = fontDescInitFromXML(child, desc); LLFontDescriptor norm_desc = desc.normalize(); if (font_succ) { // if this is the first time we've seen this font name, // create a new template map entry for it. const LLFontDescriptor *match_desc = getMatchingFontDesc(desc); if (match_desc == NULL) { // Create a new entry (with no corresponding font). mFontMap[norm_desc] = NULL; } // otherwise, find the existing entry and combine data. else { // Prepend files from desc. // A little roundabout because the map key is const, // so we have to fetch it, make a new map key, and // replace the old entry. string_vec_t match_file_names = match_desc->getFileNames(); match_file_names.insert(match_file_names.begin(), desc.getFileNames().begin(), desc.getFileNames().end()); LLFontDescriptor new_desc = *match_desc; new_desc.getFileNames() = match_file_names; mFontMap.erase(*match_desc); mFontMap[new_desc] = NULL; } } } else if (child->hasName("font_size")) { std::string size_name; F32 size_value; if (child->getAttributeString("name",size_name) && child->getAttributeF32("size",size_value)) { mFontSizes[size_name] = size_value; } } } return true; }
bool LLXUIParser::writeColor4Value(const void* val_ptr, const name_stack_t& stack) { LLXMLNodePtr node = getNode(stack); if (node.notNull()) { LLColor4 color = *((LLColor4*)val_ptr); node->setFloatValue(4, color.mV); return true; } return false; }
//static LLView* LLFlyoutButton::fromXML(LLXMLNodePtr node, LLView *parent, LLUICtrlFactory *factory) { std::string name = "flyout_button"; node->getAttributeString("name", name); std::string label(""); node->getAttributeString("label", label); LLRect rect; createRect(node, rect, parent, LLRect()); LLUICtrlCallback callback = NULL; LLFlyoutButton* flyout_button = new LLFlyoutButton(name, rect, label, callback, NULL); std::string list_position; node->getAttributeString("list_position", list_position); if (list_position == "below") { flyout_button->mListPosition = BELOW; } else if (list_position == "above") { flyout_button->mListPosition = ABOVE; } flyout_button->initFromXML(node, parent); LLXMLNodePtr child; for (child = node->getFirstChild(); child.notNull(); child = child->getNextSibling()) { if (child->hasName("flyout_button_item")) { std::string label = child->getTextContents(); std::string value = label; child->getAttributeString("value", value); flyout_button->add(label, LLSD(value) ); } } flyout_button->updateLayout(); return flyout_button; }
bool LLXUIParser::writeUIColorValue(const void* val_ptr, const name_stack_t& stack) { LLXMLNodePtr node = getNode(stack); if (node.notNull()) { LLUIColor color = *((LLUIColor*)val_ptr); //RN: don't write out the color that is represented by a function // rely on param block exporting to get the reference to the color settings if (color.isReference()) return false; node->setFloatValue(4, color.get().mV); return true; } return false; }
bool LLNotificationTemplates::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()) { 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; } } return true; }
LLView* LLScrollableContainerView::fromXML(LLXMLNodePtr node, LLView *parent, LLUICtrlFactory *factory) { std::string name("scroll_container"); node->getAttributeString("name", name); LLRect rect; createRect(node, rect, parent, LLRect()); BOOL opaque = FALSE; node->getAttributeBOOL("opaque", opaque); LLColor4 color(0,0,0,0); LLUICtrlFactory::getAttributeColor(node,"color", color); // Create the scroll view LLScrollableContainerView *ret = new LLScrollableContainerView(name, rect, (LLPanel*)NULL, opaque, color); LLPanel* panelp = NULL; // Find a child panel to add LLXMLNodePtr child; for (child = node->getFirstChild(); child.notNull(); child = child->getNextSibling()) { LLView *control = factory->createCtrlWidget(panelp, child); if (control && control->isPanel()) { if (panelp) { llinfos << "Warning! Attempting to put multiple panels into a scrollable container view!" << llendl; delete control; } else { panelp = (LLPanel*)control; } } } if (panelp == NULL) { panelp = new LLPanel(std::string("dummy"), LLRect::null, FALSE); } ret->mScrolledView = panelp; ret->initFromXML(node, parent); return ret; }
//static LLView* LLFlyoutButton::fromXML(LLXMLNodePtr node, LLView* parent, LLUICtrlFactory* factory) { std::string label(""); node->getAttributeString("label", label); LLRect rect; createRect(node, rect, parent, LLRect()); LLFlyoutButton* flyout_button = new LLFlyoutButton("flyout_button", rect, label); std::string list_position; node->getAttributeString("list_position", list_position); if (list_position == "below") { flyout_button->mListPosition = BELOW; } else if (list_position == "above") { flyout_button->mListPosition = ABOVE; } if (LLFontGL* font = selectFont(node)) flyout_button->mActionButton->setFont(font); flyout_button->initFromXML(node, parent); for (LLXMLNodePtr child = node->getFirstChild(); child.notNull(); child = child->getNextSibling()) { if (child->hasName(LL_FLYOUT_BUTTON_ITEM_TAG)) { std::string label(child->getTextContents()); child->getAttributeString("label", label); std::string value(label); child->getAttributeString("value", value); flyout_button->add(label, LLSD(value)); } } flyout_button->updateLayout(); return flyout_button; }
void LLPanel::initChildrenXML(LLXMLNodePtr node, LLUICtrlFactory* factory) { LLXMLNodePtr child; for (child = node->getFirstChild(); child.notNull(); child = child->getNextSibling()) { // look for string declarations for programmatic text if (child->hasName("string")) { std::string string_name; child->getAttributeString("name", string_name); if (!string_name.empty()) { mUIStrings[string_name] = child->getTextContents(); } } else { factory->createWidget(this, child); } } }
bool fontDescInitFromXML(LLXMLNodePtr node, LLFontDescriptor& desc) { if (node->hasName("font")) { std::string attr_name; if (node->getAttributeString("name",attr_name)) { desc.setName(attr_name); } std::string attr_style; if (node->getAttributeString("font_style",attr_style)) { desc.setStyle(LLFontGL::getStyleFromString(attr_style)); } desc.setSize(s_template_string); } LLXMLNodePtr child; for (child = node->getFirstChild(); child.notNull(); child = child->getNextSibling()) { std::string child_name; child->getAttributeString("name",child_name); if (child->hasName("file")) { std::string font_file_name = child->getTextContents(); desc.getFileNames().push_back(font_file_name); } else if (child->hasName("os")) { if (child_name == currentOsName()) { fontDescInitFromXML(child, desc); } } } return true; }
LLView* LLNameListCtrl::fromXML(LLXMLNodePtr node, LLView *parent, LLUICtrlFactory *factory) { std::string name("name_list"); node->getAttributeString("name", name); LLRect rect; createRect(node, rect, parent, LLRect()); BOOL multi_select = FALSE; node->getAttributeBOOL("multi_select", multi_select); BOOL draw_border = TRUE; node->getAttributeBOOL("draw_border", draw_border); BOOL draw_heading = FALSE; node->getAttributeBOOL("draw_heading", draw_heading); S32 name_column_index = 0; node->getAttributeS32("name_column_index", name_column_index); LLUICtrlCallback callback = NULL; LLNameListCtrl* name_list = new LLNameListCtrl(name, rect, callback, NULL, multi_select, draw_border, name_column_index); name_list->setDisplayHeading(draw_heading); if (node->hasAttribute("heading_height")) { S32 heading_height; node->getAttributeS32("heading_height", heading_height); name_list->setHeadingHeight(heading_height); } BOOL allow_calling_card_drop = FALSE; if (node->getAttributeBOOL("allow_calling_card_drop", allow_calling_card_drop)) { name_list->setAllowCallingCardDrop(allow_calling_card_drop); } name_list->setScrollListParameters(node); name_list->initFromXML(node, parent); LLSD columns; S32 index = 0; S32 total_static = 0; LLXMLNodePtr child; for (child = node->getFirstChild(); child.notNull(); child = child->getNextSibling()) { if (child->hasName("column")) { std::string labelname(""); child->getAttributeString("label", labelname); std::string columnname(labelname); child->getAttributeString("name", columnname); BOOL columndynamicwidth = FALSE; child->getAttributeBOOL("dynamicwidth", columndynamicwidth); std::string sortname(columnname); child->getAttributeString("sort", sortname); S32 columnwidth = -1; if (child->hasAttribute("relwidth")) { F32 columnrelwidth = 0.f; child->getAttributeF32("relwidth", columnrelwidth); columns[index]["relwidth"] = columnrelwidth; } else { child->getAttributeS32("width", columnwidth); columns[index]["width"] = columnwidth; } LLFontGL::HAlign h_align = LLFontGL::LEFT; h_align = LLView::selectFontHAlign(child); if(!columndynamicwidth) total_static += llmax(0, columnwidth); columns[index]["name"] = columnname; columns[index]["label"] = labelname; columns[index]["halign"] = (S32)h_align; columns[index]["dynamicwidth"] = columndynamicwidth; columns[index]["sort"] = sortname; index++; } } name_list->setTotalStaticColumnWidth(total_static); name_list->setColumnHeadings(columns); for (child = node->getFirstChild(); child.notNull(); child = child->getNextSibling()) { if (child->hasName("row")) { LLUUID id; child->getAttributeUUID("id", id); LLSD row; row["id"] = id; S32 column_idx = 0; LLXMLNodePtr row_child; for (row_child = node->getFirstChild(); row_child.notNull(); row_child = row_child->getNextSibling()) { if (row_child->hasName("column")) { std::string value = row_child->getTextContents(); std::string columnname(""); row_child->getAttributeString("name", columnname); std::string font(""); row_child->getAttributeString("font", font); std::string font_style(""); row_child->getAttributeString("font-style", font_style); row["columns"][column_idx]["column"] = columnname; row["columns"][column_idx]["value"] = value; row["columns"][column_idx]["font"] = font; row["columns"][column_idx]["font-style"] = font_style; column_idx++; } } name_list->addElement(row); } } std::string contents = node->getTextContents(); typedef boost::tokenizer<boost::char_separator<char> > tokenizer; boost::char_separator<char> sep("\t\n"); tokenizer tokens(contents, sep); tokenizer::iterator token_iter = tokens.begin(); while(token_iter != tokens.end()) { const std::string& line = *token_iter; name_list->addCommentText(line); ++token_iter; } return name_list; }
// static LLView* LLRadioGroup::fromXML(LLXMLNodePtr node, LLView *parent, LLUICtrlFactory *factory) { std::string name("radio_group"); node->getAttributeString("name", name); U32 initial_value = 0; node->getAttributeU32("initial_value", initial_value); BOOL draw_border = TRUE; node->getAttributeBOOL("draw_border", draw_border); LLRect rect; createRect(node, rect, parent, LLRect()); LLRadioGroup* radio_group = new LLRadioGroup(name, rect, initial_value, NULL, NULL, draw_border); const std::string& contents = node->getValue(); LLRect group_rect = radio_group->getRect(); LLFontGL *font = LLView::selectFont(node); if (contents.find_first_not_of(" \n\t") != contents.npos) { // ...old school default vertical layout typedef boost::tokenizer<boost::char_separator<char> > tokenizer; boost::char_separator<char> sep("\t\n"); tokenizer tokens(contents, sep); tokenizer::iterator token_iter = tokens.begin(); const S32 HPAD = 4, VPAD = 4; S32 cur_y = group_rect.getHeight() - VPAD; while(token_iter != tokens.end()) { const std::string& line = *token_iter; LLRect rect(HPAD, cur_y, group_rect.getWidth() - (2 * HPAD), cur_y - 15); cur_y -= VPAD + 15; radio_group->addRadioButton(std::string("radio"), line, rect, font); ++token_iter; } llwarns << "Legacy radio group format used! Please convert to use <radio_item> tags!" << llendl; } else { // ...per pixel layout LLXMLNodePtr child; for (child = node->getFirstChild(); child.notNull(); child = child->getNextSibling()) { if (child->hasName("radio_item")) { LLRect item_rect; createRect(child, item_rect, radio_group, rect); std::string radioname("radio"); child->getAttributeString("name", radioname); std::string item_label = child->getTextContents(); LLRadioCtrl* radio = radio_group->addRadioButton(radioname, item_label, item_rect, font); radio->initFromXML(child, radio_group); } } } radio_group->initFromXML(node, parent); return radio_group; }
// static LLView* LLTabContainer::fromXML(LLXMLNodePtr node, LLView *parent, LLUICtrlFactory *factory) { std::string name("tab_container"); node->getAttributeString("name", name); // Figure out if we are creating a vertical or horizontal tab container. bool is_vertical = false; LLTabContainer::TabPosition tab_position = LLTabContainer::TOP; if (node->hasAttribute("tab_position")) { std::string tab_position_string; node->getAttributeString("tab_position", tab_position_string); LLStringUtil::toLower(tab_position_string); if ("top" == tab_position_string) { tab_position = LLTabContainer::TOP; is_vertical = false; } else if ("bottom" == tab_position_string) { tab_position = LLTabContainer::BOTTOM; is_vertical = false; } else if ("left" == tab_position_string) { is_vertical = true; } } BOOL border = FALSE; node->getAttributeBOOL("border", border); LLTabContainer* tab_container = new LLTabContainer(name, LLRect::null, tab_position, border, is_vertical); S32 tab_min_width = tab_container->mMinTabWidth; if (node->hasAttribute("tab_width")) { node->getAttributeS32("tab_width", tab_min_width); } else if( node->hasAttribute("tab_min_width")) { node->getAttributeS32("tab_min_width", tab_min_width); } S32 tab_max_width = tab_container->mMaxTabWidth; if (node->hasAttribute("tab_max_width")) { node->getAttributeS32("tab_max_width", tab_max_width); } tab_container->setMinTabWidth(tab_min_width); tab_container->setMaxTabWidth(tab_max_width); BOOL hidden(tab_container->getTabsHidden()); node->getAttributeBOOL("hide_tabs", hidden); tab_container->setTabsHidden(hidden); tab_container->setPanelParameters(node, parent); if (LLFloater::getFloaterHost()) { LLFloater::getFloaterHost()->setTabContainer(tab_container); } //parent->addChild(tab_container); // Add all tab panels. LLXMLNodePtr child; for (child = node->getFirstChild(); child.notNull(); child = child->getNextSibling()) { LLView *control = factory->createCtrlWidget(tab_container, child); if (control && control->isPanel()) { LLPanel* panelp = (LLPanel*)control; std::string label; child->getAttributeString("label", label); if (label.empty()) { label = panelp->getLabel(); } BOOL placeholder = FALSE; child->getAttributeBOOL("placeholder", placeholder); tab_container->addTabPanel(panelp, label, false, NULL, NULL, 0, placeholder); } } tab_container->selectFirstTab(); tab_container->postBuild(); tab_container->initButtons(); // now that we have the correct rect return tab_container; }
bool LLNotifications::loadNotifications() { LL_INFOS() << "Reading notifications template" << LL_ENDL; // Passing findSkinnedFilenames(constraint=LLDir::ALL_SKINS) makes it // output all relevant pathnames instead of just the ones from the most // specific skin. std::vector<std::string> search_paths = gDirUtilp->findSkinnedFilenames(LLDir::XUI, "notifications.xml", LLDir::ALL_SKINS); std::string base_filename = search_paths.front(); LLXMLNodePtr root; BOOL success = LLXMLNode::getLayeredXMLNode(root, search_paths); if (!success || root.isNull() || !root->hasName( "notifications" )) { LL_ERRS() << "Problem reading XML from UI Notifications file: " << base_filename << LL_ENDL; return false; } 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 = LLNotificationTemplates::instance().checkForXMLTemplate(item); if (!item->hasName("notification")) continue; // now we know we have a notification entry, so let's build it LLNotificationTemplatePtr pTemplate(new LLNotificationTemplate()); if (!item->getAttributeString("name", pTemplate->mName)) { LL_WARNS() << "Unable to parse notification with no name" << LL_ENDL; continue; } //LL_INFOS() << "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->findString(sound.c_str())); } for (LLXMLNodePtr child = item->getFirstChild(); !child.isNull(); child = child->getNextSibling()) { child = LLNotificationTemplates::instance().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); //LL_WARNS() << "adding " << key << " to unique context" << LL_ENDL; } else { LL_WARNS() << "'unique' has unrecognized subelement " << formitem->getName()->mString << LL_ENDL; } } } // <form> if (child->hasName("form")) { pTemplate->mForm = LLNotificationFormPtr(new LLNotificationForm(pTemplate->mName, child)); } } LLNotificationTemplates::instance().addTemplate(pTemplate->mName, pTemplate); } //std::ostringstream ostream; //root->writeToOstream(ostream, "\n "); //LL_WARNS() << ostream.str() << LL_ENDL; return true; }
void LLXSDWriter::writeAttribute(const std::string& type, const Parser::name_stack_t& stack, S32 min_count, S32 max_count, const std::vector<std::string>* possible_values) { name_stack_t non_empty_names; std::string attribute_name; for (name_stack_t::const_iterator it = stack.begin(); it != stack.end(); ++it) { const std::string& name = it->first; if (!name.empty()) { non_empty_names.push_back(*it); } } for (name_stack_t::const_iterator it = non_empty_names.begin(); it != non_empty_names.end(); ++it) { if (!attribute_name.empty()) { attribute_name += "."; } attribute_name += it->first; } // only flag non-nested attributes as mandatory, nested attributes have variant syntax // that can't be properly constrained in XSD // e.g. <foo mandatory.value="bar"/> vs <foo><mandatory value="bar"/></foo> bool attribute_mandatory = min_count == 1 && max_count == 1 && non_empty_names.size() == 1; // don't bother supporting "Multiple" params as xml attributes if (max_count <= 1) { // add compound attribute to root node addAttributeToSchema(mAttributeNode, attribute_name, type, attribute_mandatory, possible_values); } // now generated nested elements for compound attributes if (non_empty_names.size() > 1 && !attribute_mandatory) { std::string element_name; // traverse all but last element, leaving that as an attribute name name_stack_t::const_iterator end_it = non_empty_names.end(); end_it--; for (name_stack_t::const_iterator it = non_empty_names.begin(); it != end_it; ++it) { if (it != non_empty_names.begin()) { element_name += "."; } element_name += it->first; } std::string short_attribute_name = non_empty_names.back().first; LLXMLNodePtr complex_type_node; // find existing element node here, starting at tail of child list if (mElementNode->mChildren.notNull()) { for(LLXMLNodePtr element = mElementNode->mChildren->tail; element.notNull(); element = element->mPrev) { std::string name; if(element->getAttributeString("name", name) && name == element_name) { complex_type_node = element->mChildren->head; break; } } } //create complex_type node // //<xs:element // maxOccurs="1" // minOccurs="0" // name="name"> // <xs:complexType> // </xs:complexType> //</xs:element> if(complex_type_node.isNull()) { complex_type_node = mElementNode->createChild("xs:element", false); complex_type_node->createChild("minOccurs", true)->setIntValue(min_count); complex_type_node->createChild("maxOccurs", true)->setIntValue(max_count); complex_type_node->createChild("name", true)->setStringValue(element_name); complex_type_node = complex_type_node->createChild("xs:complexType", false); } addAttributeToSchema(complex_type_node, short_attribute_name, type, false, possible_values); } }
void LLXSDWriter::addAttributeToSchema(LLXMLNodePtr type_declaration_node, const std::string& attribute_name, const std::string& type, bool mandatory, const std::vector<std::string>* possible_values) { if (!attribute_name.empty()) { LLXMLNodePtr new_enum_type_node; if (possible_values != NULL) { // custom attribute type, for example //<xs:simpleType> // <xs:restriction // base="xs:string"> // <xs:enumeration // value="a" /> // <xs:enumeration // value="b" /> // </xs:restriction> // </xs:simpleType> new_enum_type_node = new LLXMLNode("xs:simpleType", false); LLXMLNodePtr restriction_node = new_enum_type_node->createChild("xs:restriction", false); restriction_node->createChild("base", true)->setStringValue("xs:string"); for (std::vector<std::string>::const_iterator it = possible_values->begin(); it != possible_values->end(); ++it) { LLXMLNodePtr enum_node = restriction_node->createChild("xs:enumeration", false); enum_node->createChild("value", true)->setStringValue(*it); } } string_set_t& attributes_written = mAttributesWritten[type_declaration_node]; string_set_t::iterator found_it = attributes_written.lower_bound(attribute_name); // attribute not yet declared if (found_it == attributes_written.end() || attributes_written.key_comp()(attribute_name, *found_it)) { attributes_written.insert(found_it, attribute_name); LLXMLNodePtr attribute_node = type_declaration_node->createChild("xs:attribute", false); // attribute name attribute_node->createChild("name", true)->setStringValue(attribute_name); if (new_enum_type_node.notNull()) { attribute_node->addChild(new_enum_type_node); } else { // simple attribute type attribute_node->createChild("type", true)->setStringValue(type); } // required or optional attribute_node->createChild("use", true)->setStringValue(mandatory ? "required" : "optional"); } // attribute exists...handle collision of same name attributes with potentially different types else { LLXMLNodePtr attribute_declaration; if (type_declaration_node.notNull()) { for(LLXMLNodePtr node = type_declaration_node->mChildren->tail; node.notNull(); node = node->mPrev) { std::string name; if (node->getAttributeString("name", name) && name == attribute_name) { attribute_declaration = node; break; } } } bool new_type_is_enum = new_enum_type_node.notNull(); bool existing_type_is_enum = !attribute_declaration->hasAttribute("type"); // either type is enum, revert to string in collision // don't bother to check for enum equivalence if (new_type_is_enum || existing_type_is_enum) { if (attribute_declaration->hasAttribute("type")) { attribute_declaration->setAttributeString("type", "xs:string"); } else { attribute_declaration->createChild("type", true)->setStringValue("xs:string"); } attribute_declaration->deleteChildren("xs:simpleType"); } else { // check for collision of different standard types std::string existing_type; attribute_declaration->getAttributeString("type", existing_type); // if current type is not the same as the new type, revert to strnig if (existing_type != type) { // ...than use most general type, string attribute_declaration->setAttributeString("type", "string"); } } } } }
// static LLView* LLComboBox::fromXML(LLXMLNodePtr node, LLView *parent, LLUICtrlFactory *factory) { std::string name("combo_box"); node->getAttributeString("name", name); std::string label(""); node->getAttributeString("label", label); LLRect rect; createRect(node, rect, parent, LLRect()); BOOL allow_text_entry = FALSE; node->getAttributeBOOL("allow_text_entry", allow_text_entry); S32 max_chars = 20; node->getAttributeS32("max_chars", max_chars); LLUICtrlCallback callback = NULL; LLComboBox* combo_box = new LLComboBox(name, rect, label, callback, NULL); combo_box->setAllowTextEntry(allow_text_entry, max_chars); combo_box->initFromXML(node, parent); const std::string& contents = node->getValue(); if (contents.find_first_not_of(" \n\t") != contents.npos) { llerrs << "Legacy combo box item format used! Please convert to <combo_item> tags!" << llendl; } else { LLXMLNodePtr child; for (child = node->getFirstChild(); child.notNull(); child = child->getNextSibling()) { if (child->hasName("combo_item")) { std::string label = child->getTextContents(); std::string value = label; child->getAttributeString("value", value); LLScrollListItem * item=combo_box->add(label, LLSD(value) ); if(item && child->hasAttribute("tool_tip")) { std::string tool_tip = label; child->getAttributeString("tool_tip", tool_tip); item->setToolTip(tool_tip); } } } } // if providing user text entry or descriptive label // don't select an item under the hood if (!combo_box->acceptsTextInput() && combo_box->mLabel.empty()) { combo_box->selectFirstItem(); } return combo_box; }
//static LLView* LLLayoutStack::fromXML(LLXMLNodePtr node, LLView *parent, LLUICtrlFactory *factory) { std::string orientation_string("vertical"); node->getAttributeString("orientation", orientation_string); eLayoutOrientation orientation = VERTICAL; if (orientation_string == "horizontal") { orientation = HORIZONTAL; } else if (orientation_string == "vertical") { orientation = VERTICAL; } else { llwarns << "Unknown orientation " << orientation_string << ", using vertical" << llendl; } LLLayoutStack* layout_stackp = new LLLayoutStack(orientation); node->getAttributeS32("border_size", layout_stackp->mPanelSpacing); // don't allow negative spacing values layout_stackp->mPanelSpacing = llmax(layout_stackp->mPanelSpacing, 0); std::string name("stack"); node->getAttributeString("name", name); layout_stackp->setName(name); layout_stackp->initFromXML(node, parent); LLXMLNodePtr child; for (child = node->getFirstChild(); child.notNull(); child = child->getNextSibling()) { S32 min_width = 0; S32 min_height = 0; BOOL auto_resize = TRUE; child->getAttributeS32("min_width", min_width); child->getAttributeS32("min_height", min_height); child->getAttributeBOOL("auto_resize", auto_resize); if (child->hasName("layout_panel")) { BOOL user_resize = TRUE; child->getAttributeBOOL("user_resize", user_resize); LLPanel* panelp = (LLPanel*)LLPanel::fromXML(child, layout_stackp, factory); if (panelp) { panelp->setFollowsNone(); layout_stackp->addPanel(panelp, min_width, min_height, auto_resize, user_resize); } } else { BOOL user_resize = FALSE; child->getAttributeBOOL("user_resize", user_resize); LLPanel* panelp = new LLPanel(std::string("auto_panel")); LLView* new_child = factory->createWidget(panelp, child); if (new_child) { // put child in new embedded panel layout_stackp->addPanel(panelp, min_width, min_height, auto_resize, user_resize); // resize panel to contain widget and move widget to be contained in panel panelp->setRect(new_child->getRect()); new_child->setOrigin(0, 0); } else { panelp->die(); } } } layout_stackp->updateLayout(); return layout_stackp; }
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; } //llinfos << "Parsing " << pTemplate->mName << llendl; 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; }
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; }