PageRenderTime 80ms CodeModel.GetById 12ms app.highlight 61ms RepoModel.GetById 1ms app.codeStats 0ms

/indra/llui/llpanel.cpp

https://bitbucket.org/lindenlab/viewer-beta/
C++ | 1050 lines | 821 code | 138 blank | 91 comment | 128 complexity | 6c14c17f8ae69d0fc369d72dfb0de0f0 MD5 | raw file
   1/** 
   2 * @file llpanel.cpp
   3 * @brief LLPanel base class
   4 *
   5 * $LicenseInfo:firstyear=2001&license=viewerlgpl$
   6 * Second Life Viewer Source Code
   7 * Copyright (C) 2010, Linden Research, Inc.
   8 * 
   9 * This library is free software; you can redistribute it and/or
  10 * modify it under the terms of the GNU Lesser General Public
  11 * License as published by the Free Software Foundation;
  12 * version 2.1 of the License only.
  13 * 
  14 * This library is distributed in the hope that it will be useful,
  15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  17 * Lesser General Public License for more details.
  18 * 
  19 * You should have received a copy of the GNU Lesser General Public
  20 * License along with this library; if not, write to the Free Software
  21 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
  22 * 
  23 * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
  24 * $/LicenseInfo$
  25 */
  26
  27// Opaque view with a background and a border.  Can contain LLUICtrls.
  28
  29#include "linden_common.h"
  30
  31#define LLPANEL_CPP
  32#include "llpanel.h"
  33
  34#include "llfocusmgr.h"
  35#include "llfontgl.h"
  36#include "llrect.h"
  37#include "llerror.h"
  38#include "lldir.h"
  39#include "lltimer.h"
  40
  41#include "llaccordionctrltab.h"
  42#include "llbutton.h"
  43#include "llmenugl.h"
  44//#include "llstatusbar.h"
  45#include "llui.h"
  46#include "llkeyboard.h"
  47#include "lllineeditor.h"
  48#include "llcontrol.h"
  49#include "lltextbox.h"
  50#include "lluictrl.h"
  51#include "lluictrlfactory.h"
  52#include "llviewborder.h"
  53#include "lltabcontainer.h"
  54
  55static LLDefaultChildRegistry::Register<LLPanel> r1("panel", &LLPanel::fromXML);
  56LLPanel::factory_stack_t	LLPanel::sFactoryStack;
  57
  58
  59// Compiler optimization, generate extern template
  60template class LLPanel* LLView::getChild<class LLPanel>(
  61	const std::string& name, BOOL recurse) const;
  62
  63LLPanel::LocalizedString::LocalizedString()
  64:	name("name"),
  65	value("value")
  66{}
  67
  68const LLPanel::Params& LLPanel::getDefaultParams() 
  69{ 
  70	return LLUICtrlFactory::getDefaultParams<LLPanel>(); 
  71}
  72
  73LLPanel::Params::Params()
  74:	has_border("border", false),
  75	border(""),
  76	background_visible("background_visible", false),
  77	background_opaque("background_opaque", false),
  78	bg_opaque_color("bg_opaque_color"),
  79	bg_alpha_color("bg_alpha_color"),
  80	bg_opaque_image_overlay("bg_opaque_image_overlay"),
  81	bg_alpha_image_overlay("bg_alpha_image_overlay"),
  82	bg_opaque_image("bg_opaque_image"),
  83	bg_alpha_image("bg_alpha_image"),
  84	min_width("min_width", 100),
  85	min_height("min_height", 100),
  86	strings("string"),
  87	filename("filename"),
  88	class_name("class"),
  89	help_topic("help_topic"),
  90	visible_callback("visible_callback"),
  91	accepts_badge("accepts_badge")
  92{
  93	addSynonym(background_visible, "bg_visible");
  94	addSynonym(has_border, "border_visible");
  95	addSynonym(label, "title");
  96}
  97
  98
  99LLPanel::LLPanel(const LLPanel::Params& p)
 100:	LLUICtrl(p),
 101	LLBadgeHolder(p.accepts_badge),
 102	mBgVisible(p.background_visible),
 103	mBgOpaque(p.background_opaque),
 104	mBgOpaqueColor(p.bg_opaque_color()),
 105	mBgAlphaColor(p.bg_alpha_color()),
 106	mBgOpaqueImageOverlay(p.bg_opaque_image_overlay),
 107	mBgAlphaImageOverlay(p.bg_alpha_image_overlay),
 108	mBgOpaqueImage(p.bg_opaque_image()),
 109	mBgAlphaImage(p.bg_alpha_image()),
 110	mDefaultBtn(NULL),
 111	mBorder(NULL),
 112	mLabel(p.label),
 113	mHelpTopic(p.help_topic),
 114	mCommitCallbackRegistrar(false),
 115	mEnableCallbackRegistrar(false),
 116	mXMLFilename(p.filename),
 117	mVisibleSignal(NULL)
 118	// *NOTE: Be sure to also change LLPanel::initFromParams().  We have too
 119	// many classes derived from LLPanel to retrofit them all to pass in params.
 120{
 121	if (p.has_border)
 122	{
 123		addBorder(p.border);
 124	}
 125}
 126
 127LLPanel::~LLPanel()
 128{
 129	delete mVisibleSignal;
 130}
 131
 132// virtual
 133BOOL LLPanel::isPanel() const
 134{
 135	return TRUE;
 136}
 137
 138void LLPanel::addBorder(LLViewBorder::Params p)
 139{
 140	removeBorder();
 141	p.rect = getLocalRect();
 142
 143	mBorder = LLUICtrlFactory::create<LLViewBorder>(p);
 144	addChild( mBorder );
 145}
 146
 147void LLPanel::addBorder() 
 148{  
 149	LLViewBorder::Params p; 
 150	p.border_thickness(LLPANEL_BORDER_WIDTH); 
 151	addBorder(p); 
 152}
 153
 154
 155void LLPanel::removeBorder()
 156{
 157	if (mBorder)
 158	{
 159		removeChild(mBorder);
 160		delete mBorder;
 161		mBorder = NULL;
 162	}
 163}
 164
 165
 166// virtual
 167void LLPanel::clearCtrls()
 168{
 169	LLView::ctrl_list_t ctrls = getCtrlList();
 170	for (LLView::ctrl_list_t::iterator ctrl_it = ctrls.begin(); ctrl_it != ctrls.end(); ++ctrl_it)
 171	{
 172		LLUICtrl* ctrl = *ctrl_it;
 173		ctrl->setFocus( FALSE );
 174		ctrl->setEnabled( FALSE );
 175		ctrl->clear();
 176	}
 177}
 178
 179void LLPanel::setCtrlsEnabled( BOOL b )
 180{
 181	LLView::ctrl_list_t ctrls = getCtrlList();
 182	for (LLView::ctrl_list_t::iterator ctrl_it = ctrls.begin(); ctrl_it != ctrls.end(); ++ctrl_it)
 183	{
 184		LLUICtrl* ctrl = *ctrl_it;
 185		ctrl->setEnabled( b );
 186	}
 187}
 188
 189void LLPanel::draw()
 190{
 191	F32 alpha = getDrawContext().mAlpha;
 192
 193	// draw background
 194	if( mBgVisible )
 195	{
 196		alpha = getCurrentTransparency();
 197
 198		LLRect local_rect = getLocalRect();
 199		if (mBgOpaque )
 200		{
 201			// opaque, in-front look
 202			if (mBgOpaqueImage.notNull())
 203			{
 204				mBgOpaqueImage->draw( local_rect, mBgOpaqueImageOverlay % alpha );
 205			}
 206			else
 207			{
 208				// fallback to flat colors when there are no images
 209				gl_rect_2d( local_rect, mBgOpaqueColor.get() % alpha);
 210			}
 211		}
 212		else
 213		{
 214			// transparent, in-back look
 215			if (mBgAlphaImage.notNull())
 216			{
 217				mBgAlphaImage->draw( local_rect, mBgAlphaImageOverlay % alpha );
 218			}
 219			else
 220			{
 221				gl_rect_2d( local_rect, mBgAlphaColor.get() % alpha );
 222			}
 223		}
 224	}
 225
 226	updateDefaultBtn();
 227
 228	LLView::draw();
 229}
 230
 231void LLPanel::updateDefaultBtn()
 232{
 233	if( mDefaultBtn)
 234	{
 235		if (gFocusMgr.childHasKeyboardFocus( this ) && mDefaultBtn->getEnabled())
 236		{
 237			LLButton* buttonp = dynamic_cast<LLButton*>(gFocusMgr.getKeyboardFocus());
 238			BOOL focus_is_child_button = buttonp && buttonp->getCommitOnReturn();
 239			// only enable default button when current focus is not a return-capturing button
 240			mDefaultBtn->setBorderEnabled(!focus_is_child_button);
 241		}
 242		else
 243		{
 244			mDefaultBtn->setBorderEnabled(FALSE);
 245		}
 246	}
 247}
 248
 249void LLPanel::refresh()
 250{
 251	// do nothing by default
 252	// but is automatically called in setFocus(TRUE)
 253}
 254
 255void LLPanel::setDefaultBtn(LLButton* btn)
 256{
 257	if (mDefaultBtn && mDefaultBtn->getEnabled())
 258	{
 259		mDefaultBtn->setBorderEnabled(FALSE);
 260	}
 261	mDefaultBtn = btn; 
 262	if (mDefaultBtn)
 263	{
 264		mDefaultBtn->setBorderEnabled(TRUE);
 265	}
 266}
 267
 268void LLPanel::setDefaultBtn(const std::string& id)
 269{
 270	LLButton *button = getChild<LLButton>(id);
 271	if (button)
 272	{
 273		setDefaultBtn(button);
 274	}
 275	else
 276	{
 277		setDefaultBtn(NULL);
 278	}
 279}
 280
 281BOOL LLPanel::handleKeyHere( KEY key, MASK mask )
 282{
 283	BOOL handled = FALSE;
 284
 285	LLUICtrl* cur_focus = dynamic_cast<LLUICtrl*>(gFocusMgr.getKeyboardFocus());
 286
 287	// handle user hitting ESC to defocus
 288	if (key == KEY_ESCAPE)
 289	{
 290		setFocus(FALSE);
 291		return TRUE;
 292	}
 293	else if( (mask == MASK_SHIFT) && (KEY_TAB == key))
 294	{
 295		//SHIFT-TAB
 296		if (cur_focus)
 297		{
 298			LLUICtrl* focus_root = cur_focus->findRootMostFocusRoot();
 299			if (focus_root)
 300			{
 301				handled = focus_root->focusPrevItem(FALSE);
 302			}
 303		}
 304	}
 305	else if( (mask == MASK_NONE ) && (KEY_TAB == key))	
 306	{
 307		//TAB
 308		if (cur_focus)
 309		{
 310			LLUICtrl* focus_root = cur_focus->findRootMostFocusRoot();
 311			if (focus_root)
 312			{
 313				handled = focus_root->focusNextItem(FALSE);
 314			}
 315		}
 316	}
 317	
 318	// If RETURN was pressed and something has focus, call onCommit()
 319	if (!handled && cur_focus && key == KEY_RETURN && mask == MASK_NONE)
 320	{
 321		LLButton* focused_button = dynamic_cast<LLButton*>(cur_focus);
 322		if (focused_button && focused_button->getCommitOnReturn())
 323		{
 324			// current focus is a return-capturing button,
 325			// let *that* button handle the return key
 326			handled = FALSE; 
 327		}
 328		else if (mDefaultBtn && mDefaultBtn->getVisible() && mDefaultBtn->getEnabled())
 329		{
 330			// If we have a default button, click it when return is pressed
 331			mDefaultBtn->onCommit();
 332			handled = TRUE;
 333		}
 334		else if (cur_focus->acceptsTextInput())
 335		{
 336			// call onCommit for text input handling control
 337			cur_focus->onCommit();
 338			handled = TRUE;
 339		}
 340	}
 341
 342	return handled;
 343}
 344
 345void LLPanel::handleVisibilityChange ( BOOL new_visibility )
 346{
 347	LLUICtrl::handleVisibilityChange ( new_visibility );
 348	if (mVisibleSignal)
 349		(*mVisibleSignal)(this, LLSD(new_visibility) ); // Pass BOOL as LLSD
 350}
 351
 352void LLPanel::setFocus(BOOL b)
 353{
 354	if( b && !hasFocus())
 355	{
 356		// give ourselves focus preemptively, to avoid infinite loop
 357		LLUICtrl::setFocus(TRUE);
 358		// then try to pass to first valid child
 359		focusFirstItem();
 360	}
 361	else
 362	{
 363		LLUICtrl::setFocus(b);
 364	}
 365}
 366
 367void LLPanel::setBorderVisible(BOOL b)
 368{
 369	if (mBorder)
 370	{
 371		mBorder->setVisible( b );
 372	}
 373}
 374
 375LLFastTimer::DeclareTimer FTM_PANEL_CONSTRUCTION("Panel Construction");
 376
 377LLView* LLPanel::fromXML(LLXMLNodePtr node, LLView* parent, LLXMLNodePtr output_node)
 378{
 379	std::string name("panel");
 380	node->getAttributeString("name", name);
 381
 382	std::string class_attr;
 383	node->getAttributeString("class", class_attr);
 384
 385	LLPanel* panelp = NULL;
 386	
 387	{	LLFastTimer _(FTM_PANEL_CONSTRUCTION);
 388		
 389		if(!class_attr.empty())
 390		{
 391			panelp = LLRegisterPanelClass::instance().createPanelClass(class_attr);
 392			if (!panelp)
 393			{
 394				llwarns << "Panel class \"" << class_attr << "\" not registered." << llendl;
 395			}
 396		}
 397
 398		if (!panelp)
 399		{
 400			panelp = createFactoryPanel(name);
 401			llassert(panelp);
 402			
 403			if (!panelp)
 404			{
 405				return NULL; // :(
 406			}
 407		}
 408
 409	}
 410	// factory panels may have registered their own factory maps
 411	if (!panelp->getFactoryMap().empty())
 412	{
 413		sFactoryStack.push_back(&panelp->getFactoryMap());
 414	}
 415	// for local registry callbacks; define in constructor, referenced in XUI or postBuild
 416	panelp->mCommitCallbackRegistrar.pushScope(); 
 417	panelp->mEnableCallbackRegistrar.pushScope();
 418
 419	panelp->initPanelXML(node, parent, output_node, LLUICtrlFactory::getDefaultParams<LLPanel>());
 420	
 421	panelp->mCommitCallbackRegistrar.popScope();
 422	panelp->mEnableCallbackRegistrar.popScope();
 423
 424	if (!panelp->getFactoryMap().empty())
 425	{
 426		sFactoryStack.pop_back();
 427	}
 428
 429	return panelp;
 430}
 431
 432void LLPanel::initFromParams(const LLPanel::Params& p)
 433{
 434    //setting these here since panel constructor not called with params
 435    //and LLView::initFromParams will use them to set visible and enabled  
 436	setVisible(p.visible);
 437	setEnabled(p.enabled);
 438	setFocusRoot(p.focus_root);
 439	setSoundFlags(p.sound_flags);
 440
 441	 // control_name, tab_stop, focus_lost_callback, initial_value, rect, enabled, visible
 442	LLUICtrl::initFromParams(p);
 443	
 444	// visible callback 
 445	if (p.visible_callback.isProvided())
 446	{
 447		setVisibleCallback(initCommitCallback(p.visible_callback));
 448	}
 449	
 450	for (LLInitParam::ParamIterator<LocalizedString>::const_iterator it = p.strings.begin();
 451		it != p.strings.end();
 452		++it)
 453	{
 454		mUIStrings[it->name] = it->value;
 455	}
 456
 457	setLabel(p.label());
 458	setHelpTopic(p.help_topic);
 459	setShape(p.rect);
 460	parseFollowsFlags(p);
 461
 462	setToolTip(p.tool_tip());
 463	setFromXUI(p.from_xui);
 464	
 465	mHoverCursor = getCursorFromString(p.hover_cursor);
 466	
 467	if (p.has_border)
 468	{
 469		addBorder(p.border);
 470	}
 471	// let constructors set this value if not provided
 472	if (p.use_bounding_rect.isProvided())
 473	{
 474		setUseBoundingRect(p.use_bounding_rect);
 475	}
 476	setDefaultTabGroup(p.default_tab_group);
 477	setMouseOpaque(p.mouse_opaque);
 478	
 479	setBackgroundVisible(p.background_visible);
 480	setBackgroundOpaque(p.background_opaque);
 481	setBackgroundColor(p.bg_opaque_color().get());
 482	setTransparentColor(p.bg_alpha_color().get());
 483	mBgOpaqueImage = p.bg_opaque_image();
 484	mBgAlphaImage = p.bg_alpha_image();
 485	mBgOpaqueImageOverlay = p.bg_opaque_image_overlay;
 486	mBgAlphaImageOverlay = p.bg_alpha_image_overlay;
 487
 488	setAcceptsBadge(p.accepts_badge);
 489}
 490
 491static LLFastTimer::DeclareTimer FTM_PANEL_SETUP("Panel Setup");
 492static LLFastTimer::DeclareTimer FTM_EXTERNAL_PANEL_LOAD("Load Extern Panel Reference");
 493static LLFastTimer::DeclareTimer FTM_PANEL_POSTBUILD("Panel PostBuild");
 494
 495BOOL LLPanel::initPanelXML(LLXMLNodePtr node, LLView *parent, LLXMLNodePtr output_node, const LLPanel::Params& default_params)
 496{
 497	Params params(default_params);
 498	{
 499		LLFastTimer timer(FTM_PANEL_SETUP);
 500
 501		LLXMLNodePtr referenced_xml;
 502		std::string xml_filename = mXMLFilename;
 503		
 504		// if the panel didn't provide a filename, check the node
 505		if (xml_filename.empty())
 506		{
 507			node->getAttributeString("filename", xml_filename);
 508			setXMLFilename(xml_filename);
 509		}
 510
 511		LLXUIParser parser;
 512
 513		if (!xml_filename.empty())
 514		{
 515			if (output_node)
 516			{
 517				//if we are exporting, we want to export the current xml
 518				//not the referenced xml
 519				parser.readXUI(node, params, LLUICtrlFactory::getInstance()->getCurFileName());
 520				Params output_params(params);
 521				setupParamsForExport(output_params, parent);
 522				output_node->setName(node->getName()->mString);
 523				parser.writeXUI(output_node, output_params, &default_params);
 524				return TRUE;
 525			}
 526		
 527			LLUICtrlFactory::instance().pushFileName(xml_filename);
 528
 529			LLFastTimer timer(FTM_EXTERNAL_PANEL_LOAD);
 530			if (!LLUICtrlFactory::getLayeredXMLNode(xml_filename, referenced_xml))
 531			{
 532				llwarns << "Couldn't parse panel from: " << xml_filename << llendl;
 533
 534				return FALSE;
 535			}
 536
 537			parser.readXUI(referenced_xml, params, LLUICtrlFactory::getInstance()->getCurFileName());
 538
 539			// add children using dimensions from referenced xml for consistent layout
 540			setShape(params.rect);
 541			LLUICtrlFactory::createChildren(this, referenced_xml, child_registry_t::instance());
 542
 543			LLUICtrlFactory::instance().popFileName();
 544		}
 545
 546		// ask LLUICtrlFactory for filename, since xml_filename might be empty
 547		parser.readXUI(node, params, LLUICtrlFactory::getInstance()->getCurFileName());
 548
 549		if (output_node)
 550		{
 551			Params output_params(params);
 552			setupParamsForExport(output_params, parent);
 553			output_node->setName(node->getName()->mString);
 554			parser.writeXUI(output_node, output_params, &default_params);
 555		}
 556		
 557		params.from_xui = true;
 558		applyXUILayout(params, parent);
 559		{
 560			LLFastTimer timer(FTM_PANEL_CONSTRUCTION);
 561			initFromParams(params);
 562		}
 563
 564		// add children
 565		LLUICtrlFactory::createChildren(this, node, child_registry_t::instance(), output_node);
 566
 567		// Connect to parent after children are built, because tab containers
 568		// do a reshape() on their child panels, which requires that the children
 569		// be built/added. JC
 570		if (parent)
 571		{
 572			S32 tab_group = params.tab_group.isProvided() ? params.tab_group() : parent->getLastTabGroup();
 573			parent->addChild(this, tab_group);
 574		}
 575
 576		{
 577			LLFastTimer timer(FTM_PANEL_POSTBUILD);
 578			postBuild();
 579		}
 580	}
 581	return TRUE;
 582}
 583
 584bool LLPanel::hasString(const std::string& name)
 585{
 586	return mUIStrings.find(name) != mUIStrings.end();
 587}
 588
 589std::string LLPanel::getString(const std::string& name, const LLStringUtil::format_map_t& args) const
 590{
 591	ui_string_map_t::const_iterator found_it = mUIStrings.find(name);
 592	if (found_it != mUIStrings.end())
 593	{
 594		// make a copy as format works in place
 595		LLUIString formatted_string = LLUIString(found_it->second);
 596		formatted_string.setArgList(args);
 597		return formatted_string.getString();
 598	}
 599	std::string err_str("Failed to find string " + name + " in panel " + getName()); //*TODO: Translate
 600	if(LLUI::sSettingGroups["config"]->getBOOL("QAMode"))
 601	{
 602		llerrs << err_str << llendl;
 603	}
 604	else
 605	{
 606		llwarns << err_str << llendl;
 607	}
 608	return LLStringUtil::null;
 609}
 610
 611std::string LLPanel::getString(const std::string& name) const
 612{
 613	ui_string_map_t::const_iterator found_it = mUIStrings.find(name);
 614	if (found_it != mUIStrings.end())
 615	{
 616		return found_it->second;
 617	}
 618	std::string err_str("Failed to find string " + name + " in panel " + getName()); //*TODO: Translate
 619	if(LLUI::sSettingGroups["config"]->getBOOL("QAMode"))
 620	{
 621		llerrs << err_str << llendl;
 622	}
 623	else
 624	{
 625		llwarns << err_str << llendl;
 626	}
 627	return LLStringUtil::null;
 628}
 629
 630
 631void LLPanel::childSetVisible(const std::string& id, bool visible)
 632{
 633	LLView* child = findChild<LLView>(id);
 634	if (child)
 635	{
 636		child->setVisible(visible);
 637	}
 638}
 639
 640bool LLPanel::childIsVisible(const std::string& id) const
 641{
 642	LLView* child = findChild<LLView>(id);
 643	if (child)
 644	{
 645		return (bool)child->getVisible();
 646	}
 647	return false;
 648}
 649
 650void LLPanel::childSetEnabled(const std::string& id, bool enabled)
 651{
 652	LLView* child = findChild<LLView>(id);
 653	if (child)
 654	{
 655		child->setEnabled(enabled);
 656	}
 657}
 658
 659void LLPanel::childSetTentative(const std::string& id, bool tentative)
 660{
 661	LLUICtrl* child = findChild<LLUICtrl>(id);
 662	if (child)
 663	{
 664		child->setTentative(tentative);
 665	}
 666}
 667
 668bool LLPanel::childIsEnabled(const std::string& id) const
 669{
 670	LLView* child = findChild<LLView>(id);
 671	if (child)
 672	{
 673		return (bool)child->getEnabled();
 674	}
 675	return false;
 676}
 677
 678
 679void LLPanel::childSetToolTip(const std::string& id, const std::string& msg)
 680{
 681	LLView* child = findChild<LLView>(id);
 682	if (child)
 683	{
 684		child->setToolTip(msg);
 685	}
 686}
 687
 688void LLPanel::childSetRect(const std::string& id, const LLRect& rect)
 689{
 690	LLView* child = findChild<LLView>(id);
 691	if (child)
 692	{
 693		child->setRect(rect);
 694	}
 695}
 696
 697bool LLPanel::childGetRect(const std::string& id, LLRect& rect) const
 698{
 699	LLView* child = findChild<LLView>(id);
 700	if (child)
 701	{
 702		rect = child->getRect();
 703		return true;
 704	}
 705	return false;
 706}
 707
 708void LLPanel::childSetFocus(const std::string& id, BOOL focus)
 709{
 710	LLUICtrl* child = findChild<LLUICtrl>(id);
 711	if (child)
 712	{
 713		child->setFocus(focus);
 714	}
 715}
 716
 717BOOL LLPanel::childHasFocus(const std::string& id)
 718{
 719	LLUICtrl* child = findChild<LLUICtrl>(id);
 720	if (child)
 721	{
 722		return child->hasFocus();
 723	}
 724	else
 725	{
 726		return FALSE;
 727	}
 728}
 729
 730// *TODO: Deprecate; for backwards compatability only:
 731// Prefer getChild<LLUICtrl>("foo")->setCommitCallback(boost:bind(...)),
 732// which takes a generic slot.  Or use mCommitCallbackRegistrar.add() with
 733// a named callback and reference it in XML.
 734void LLPanel::childSetCommitCallback(const std::string& id, boost::function<void (LLUICtrl*,void*)> cb, void* data)
 735{
 736	LLUICtrl* child = findChild<LLUICtrl>(id);
 737	if (child)
 738	{
 739		child->setCommitCallback(boost::bind(cb, child, data));
 740	}
 741}
 742
 743void LLPanel::childSetValidate(const std::string& id, boost::function<bool (const LLSD& data)> cb)
 744{
 745	LLUICtrl* child = findChild<LLUICtrl>(id);
 746	if (child)
 747	{
 748		child->setValidateBeforeCommit(cb);
 749	}
 750}
 751
 752void LLPanel::childSetColor(const std::string& id, const LLColor4& color)
 753{
 754	LLUICtrl* child = findChild<LLUICtrl>(id);
 755	if (child)
 756	{
 757		child->setColor(color);
 758	}
 759}
 760
 761LLCtrlSelectionInterface* LLPanel::childGetSelectionInterface(const std::string& id) const
 762{
 763	LLUICtrl* child = findChild<LLUICtrl>(id);
 764	if (child)
 765	{
 766		return child->getSelectionInterface();
 767	}
 768	return NULL;
 769}
 770
 771LLCtrlListInterface* LLPanel::childGetListInterface(const std::string& id) const
 772{
 773	LLUICtrl* child = findChild<LLUICtrl>(id);
 774	if (child)
 775	{
 776		return child->getListInterface();
 777	}
 778	return NULL;
 779}
 780
 781LLCtrlScrollInterface* LLPanel::childGetScrollInterface(const std::string& id) const
 782{
 783	LLUICtrl* child = findChild<LLUICtrl>(id);
 784	if (child)
 785	{
 786		return child->getScrollInterface();
 787	}
 788	return NULL;
 789}
 790
 791void LLPanel::childSetValue(const std::string& id, LLSD value)
 792{
 793	LLUICtrl* child = findChild<LLUICtrl>(id);
 794	if (child)
 795	{
 796		child->setValue(value);
 797	}
 798}
 799
 800LLSD LLPanel::childGetValue(const std::string& id) const
 801{
 802	LLUICtrl* child = findChild<LLUICtrl>(id);
 803	if (child)
 804	{
 805		return child->getValue();
 806	}
 807	// Not found => return undefined
 808	return LLSD();
 809}
 810
 811BOOL LLPanel::childSetTextArg(const std::string& id, const std::string& key, const LLStringExplicit& text)
 812{
 813	LLUICtrl* child = findChild<LLUICtrl>(id);
 814	if (child)
 815	{
 816		return child->setTextArg(key, text);
 817	}
 818	return FALSE;
 819}
 820
 821BOOL LLPanel::childSetLabelArg(const std::string& id, const std::string& key, const LLStringExplicit& text)
 822{
 823	LLView* child = findChild<LLView>(id);
 824	if (child)
 825	{
 826		return child->setLabelArg(key, text);
 827	}
 828	return FALSE;
 829}
 830
 831BOOL LLPanel::childSetToolTipArg(const std::string& id, const std::string& key, const LLStringExplicit& text)
 832{
 833	LLView* child = findChild<LLView>(id);
 834	if (child)
 835	{
 836		return child->setToolTipArg(key, text);
 837	}
 838	return FALSE;
 839}
 840
 841void LLPanel::childShowTab(const std::string& id, const std::string& tabname, bool visible)
 842{
 843	LLTabContainer* child = findChild<LLTabContainer>(id);
 844	if (child)
 845	{
 846		child->selectTabByName(tabname);
 847	}
 848}
 849
 850LLPanel *LLPanel::childGetVisibleTab(const std::string& id) const
 851{
 852	LLTabContainer* child = findChild<LLTabContainer>(id);
 853	if (child)
 854	{
 855		return child->getCurrentPanel();
 856	}
 857	return NULL;
 858}
 859
 860LLPanel* LLPanel::childGetVisibleTabWithHelp()
 861{
 862	LLView *child;
 863
 864	bfs_tree_iterator_t it = beginTreeBFS();
 865	// skip ourselves
 866	++it;
 867	for (; it != endTreeBFS(); ++it)
 868	{
 869		child = *it;
 870		LLPanel *curTabPanel = NULL;
 871
 872		// do we have a tab container?
 873		LLTabContainer *tab = dynamic_cast<LLTabContainer *>(child);
 874		if (tab && tab->getVisible())
 875		{
 876			curTabPanel = tab->getCurrentPanel();
 877		}
 878
 879		// do we have an accordion tab?
 880		LLAccordionCtrlTab* accordion = dynamic_cast<LLAccordionCtrlTab *>(child);
 881		if (accordion && accordion->getDisplayChildren())
 882		{
 883			curTabPanel = dynamic_cast<LLPanel *>(accordion->getAccordionView());
 884		}
 885
 886		// if we found a valid tab, does it have a help topic?
 887		if (curTabPanel && !curTabPanel->getHelpTopic().empty())
 888		{
 889			return curTabPanel;
 890		}
 891	}
 892
 893	// couldn't find any active tabs with a help topic string
 894	return NULL;
 895}
 896
 897
 898LLPanel *LLPanel::childGetVisiblePanelWithHelp()
 899{
 900	LLView *child;
 901
 902	bfs_tree_iterator_t it = beginTreeBFS();
 903	// skip ourselves
 904	++it;
 905	for (; it != endTreeBFS(); ++it)
 906	{
 907		child = *it;
 908		// do we have a panel with a help topic?
 909		LLPanel *panel = dynamic_cast<LLPanel *>(child);
 910		if (panel && panel->isInVisibleChain() && !panel->getHelpTopic().empty())
 911		{
 912			return panel;
 913		}
 914	}
 915
 916	// couldn't find any active panels with a help topic string
 917	return NULL;
 918}
 919
 920void LLPanel::childSetAction(const std::string& id, const commit_signal_t::slot_type& function)
 921{
 922	LLButton* button = findChild<LLButton>(id);
 923	if (button)
 924	{
 925		button->setClickedCallback(function);
 926	}
 927}
 928
 929void LLPanel::childSetAction(const std::string& id, boost::function<void(void*)> function, void* value)
 930{
 931	LLButton* button = findChild<LLButton>(id);
 932	if (button)
 933	{
 934		button->setClickedCallback(boost::bind(function, value));
 935	}
 936}
 937
 938void LLPanel::childSetActionTextbox(const std::string& id, boost::function<void(void*)> function, void* value)
 939{
 940	LLTextBox* textbox = findChild<LLTextBox>(id);
 941	if (textbox)
 942	{
 943		textbox->setClickedCallback(boost::bind(function, value));
 944	}
 945}
 946
 947void LLPanel::childSetControlName(const std::string& id, const std::string& control_name)
 948{
 949	LLUICtrl* view = findChild<LLUICtrl>(id);
 950	if (view)
 951	{
 952		view->setControlName(control_name, NULL);
 953	}
 954}
 955
 956boost::signals2::connection LLPanel::setVisibleCallback( const commit_signal_t::slot_type& cb )
 957{
 958	if (!mVisibleSignal)
 959	{
 960		mVisibleSignal = new commit_signal_t();
 961	}
 962
 963	return mVisibleSignal->connect(cb);
 964}
 965
 966static LLFastTimer::DeclareTimer FTM_BUILD_PANELS("Build Panels");
 967
 968//-----------------------------------------------------------------------------
 969// buildPanel()
 970//-----------------------------------------------------------------------------
 971BOOL LLPanel::buildFromFile(const std::string& filename, LLXMLNodePtr output_node, const LLPanel::Params& default_params)
 972{
 973	LLFastTimer timer(FTM_BUILD_PANELS);
 974	BOOL didPost = FALSE;
 975	LLXMLNodePtr root;
 976
 977	//if exporting, only load the language being exported, 
 978	//instead of layering localized version on top of english
 979	if (output_node)
 980	{	
 981		if (!LLUICtrlFactory::getLocalizedXMLNode(filename, root))
 982		{
 983			llwarns << "Couldn't parse panel from: " << LLUI::getLocalizedSkinPath() + gDirUtilp->getDirDelimiter() + filename  << llendl;
 984			return didPost;
 985		}
 986	}
 987	else if (!LLUICtrlFactory::getLayeredXMLNode(filename, root))
 988	{
 989		llwarns << "Couldn't parse panel from: " << LLUI::getSkinPath() + gDirUtilp->getDirDelimiter() + filename << llendl;
 990		return didPost;
 991	}
 992
 993	// root must be called panel
 994	if( !root->hasName("panel" ) )
 995	{
 996		llwarns << "Root node should be named panel in : " << filename << llendl;
 997		return didPost;
 998	}
 999
1000	lldebugs << "Building panel " << filename << llendl;
1001
1002	LLUICtrlFactory::instance().pushFileName(filename);
1003	{
1004		if (!getFactoryMap().empty())
1005		{
1006			sFactoryStack.push_back(&getFactoryMap());
1007		}
1008		
1009		 // for local registry callbacks; define in constructor, referenced in XUI or postBuild
1010		getCommitCallbackRegistrar().pushScope();
1011		getEnableCallbackRegistrar().pushScope();
1012		
1013		didPost = initPanelXML(root, NULL, output_node, default_params);
1014
1015		getCommitCallbackRegistrar().popScope();
1016		getEnableCallbackRegistrar().popScope();
1017		
1018		setXMLFilename(filename);
1019
1020		if (!getFactoryMap().empty())
1021		{
1022			sFactoryStack.pop_back();
1023		}
1024	}
1025	LLUICtrlFactory::instance().popFileName();
1026	return didPost;
1027}
1028
1029//-----------------------------------------------------------------------------
1030// createFactoryPanel()
1031//-----------------------------------------------------------------------------
1032LLPanel* LLPanel::createFactoryPanel(const std::string& name)
1033{
1034	std::deque<const LLCallbackMap::map_t*>::iterator itor;
1035	for (itor = sFactoryStack.begin(); itor != sFactoryStack.end(); ++itor)
1036	{
1037		const LLCallbackMap::map_t* factory_map = *itor;
1038
1039		// Look up this panel's name in the map.
1040		LLCallbackMap::map_const_iter_t iter = factory_map->find( name );
1041		if (iter != factory_map->end())
1042		{
1043			// Use the factory to create the panel, instead of using a default LLPanel.
1044			LLPanel *ret = (LLPanel*) iter->second.mCallback( iter->second.mData );
1045			return ret;
1046		}
1047	}
1048	LLPanel::Params panel_p;
1049	return LLUICtrlFactory::create<LLPanel>(panel_p);
1050}