PageRenderTime 89ms CodeModel.GetById 18ms app.highlight 67ms RepoModel.GetById 1ms app.codeStats 0ms

/indra/llui/llfloaterreg.cpp

https://bitbucket.org/lindenlab/viewer-beta/
C++ | 507 lines | 375 code | 54 blank | 78 comment | 73 complexity | 255d9f5c14c2d0695c1d28b4b78f8830 MD5 | raw file
  1/** 
  2 * @file llfloaterreg.cpp
  3 * @brief LLFloaterReg Floater Registration Class
  4 *
  5 * $LicenseInfo:firstyear=2002&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#include "linden_common.h"
 28
 29#include "llfloaterreg.h"
 30
 31//#include "llagent.h" 
 32#include "llfloater.h"
 33#include "llmultifloater.h"
 34#include "llfloaterreglistener.h"
 35
 36//*******************************************************
 37
 38//static
 39LLFloaterReg::instance_list_t LLFloaterReg::sNullInstanceList;
 40LLFloaterReg::instance_map_t LLFloaterReg::sInstanceMap;
 41LLFloaterReg::build_map_t LLFloaterReg::sBuildMap;
 42std::map<std::string,std::string> LLFloaterReg::sGroupMap;
 43bool LLFloaterReg::sBlockShowFloaters = false;
 44std::set<std::string> LLFloaterReg::sAlwaysShowableList;
 45
 46static LLFloaterRegListener sFloaterRegListener;
 47
 48//*******************************************************
 49
 50//static
 51void LLFloaterReg::add(const std::string& name, const std::string& filename, const LLFloaterBuildFunc& func, const std::string& groupname)
 52{
 53	sBuildMap[name].mFunc = func;
 54	sBuildMap[name].mFile = filename;
 55	sGroupMap[name] = groupname.empty() ? name : groupname;
 56	sGroupMap[groupname] = groupname; // for referencing directly by group name
 57}
 58
 59//static
 60LLFloater* LLFloaterReg::getLastFloaterInGroup(const std::string& name)
 61{
 62	const std::string& groupname = sGroupMap[name];
 63	if (!groupname.empty())
 64	{
 65		instance_list_t& list = sInstanceMap[groupname];
 66		if (!list.empty())
 67		{
 68			for (instance_list_t::reverse_iterator iter = list.rbegin(); iter != list.rend(); ++iter)
 69			{
 70				LLFloater* inst = *iter;
 71
 72				if (inst->getVisible() && !inst->isMinimized())
 73				{
 74					return inst;
 75				}
 76			}
 77		}
 78	}
 79	return NULL;
 80}
 81
 82LLFloater* LLFloaterReg::getLastFloaterCascading()
 83{
 84	LLRect candidate_rect;
 85	candidate_rect.mTop = 100000;
 86	LLFloater* candidate_floater = NULL;
 87
 88	std::map<std::string,std::string>::const_iterator it = sGroupMap.begin(), it_end = sGroupMap.end();
 89	for( ; it != it_end; ++it)
 90	{
 91		const std::string& group_name = it->second;
 92
 93		instance_list_t& instances = sInstanceMap[group_name];
 94
 95		for (instance_list_t::const_iterator iter = instances.begin(); iter != instances.end(); ++iter)
 96		{
 97			LLFloater* inst = *iter;
 98
 99			if (inst->getVisible() && inst->isPositioning(LLFloaterEnums::OPEN_POSITIONING_CASCADING))
100			{
101				if (candidate_rect.mTop > inst->getRect().mTop)
102				{
103					candidate_floater = inst;
104					candidate_rect = inst->getRect();
105				}
106			}
107		}
108	}
109
110	return candidate_floater;
111}
112
113//static
114LLFloater* LLFloaterReg::findInstance(const std::string& name, const LLSD& key)
115{
116	LLFloater* res = NULL;
117	const std::string& groupname = sGroupMap[name];
118	if (!groupname.empty())
119	{
120		instance_list_t& list = sInstanceMap[groupname];
121		for (instance_list_t::iterator iter = list.begin(); iter != list.end(); ++iter)
122		{
123			LLFloater* inst = *iter;
124			if (inst->matchesKey(key))
125			{
126				res = inst;
127				break;
128			}
129		}
130	}
131	return res;
132}
133
134//static
135LLFloater* LLFloaterReg::getInstance(const std::string& name, const LLSD& key) 
136{
137	LLFloater* res = findInstance(name, key);
138	if (!res)
139	{
140		const LLFloaterBuildFunc& build_func = sBuildMap[name].mFunc;
141		const std::string& xui_file = sBuildMap[name].mFile;
142		if (build_func)
143		{
144			const std::string& groupname = sGroupMap[name];
145			if (!groupname.empty())
146			{
147				instance_list_t& list = sInstanceMap[groupname];
148
149				res = build_func(key);
150				if (!res)
151				{
152					llwarns << "Failed to build floater type: '" << name << "'." << llendl;
153					return NULL;
154				}
155				bool success = res->buildFromFile(xui_file, NULL);
156				if (!success)
157				{
158					llwarns << "Failed to build floater type: '" << name << "'." << llendl;
159					return NULL;
160				}
161
162				// Note: key should eventually be a non optional LLFloater arg; for now, set mKey to be safe
163				if (res->mKey.isUndefined()) 
164				{
165					res->mKey = key;
166				}
167				res->setInstanceName(name);
168
169				LLFloater *last_floater = (list.empty() ? NULL : list.back());
170
171				res->applyControlsAndPosition(last_floater);
172
173				gFloaterView->adjustToFitScreen(res, false);
174
175				list.push_back(res);
176			}
177		}
178		if (!res)
179		{
180			llwarns << "Floater type: '" << name << "' not registered." << llendl;
181		}
182	}
183	return res;
184}
185
186//static
187LLFloater* LLFloaterReg::removeInstance(const std::string& name, const LLSD& key)
188{
189	LLFloater* res = NULL;
190	const std::string& groupname = sGroupMap[name];
191	if (!groupname.empty())
192	{
193		instance_list_t& list = sInstanceMap[groupname];
194		for (instance_list_t::iterator iter = list.begin(); iter != list.end(); ++iter)
195		{
196			LLFloater* inst = *iter;
197			if (inst->matchesKey(key))
198			{
199				res = inst;
200				list.erase(iter);
201				break;
202			}
203		}
204	}
205	return res;
206}
207
208//static
209// returns true if the instance existed
210bool LLFloaterReg::destroyInstance(const std::string& name, const LLSD& key)
211{
212	LLFloater* inst = removeInstance(name, key);
213	if (inst)
214	{
215		delete inst;
216		return true;
217	}
218	else
219	{
220		return false;
221	}
222}
223
224// Iterators
225//static
226LLFloaterReg::const_instance_list_t& LLFloaterReg::getFloaterList(const std::string& name)
227{
228	instance_map_t::iterator iter = sInstanceMap.find(name);
229	if (iter != sInstanceMap.end())
230	{
231		return iter->second;
232	}
233	else
234	{
235		return sNullInstanceList;
236	}
237}
238
239// Visibility Management
240
241//static
242LLFloater* LLFloaterReg::showInstance(const std::string& name, const LLSD& key, BOOL focus) 
243{
244	if( sBlockShowFloaters
245			// see EXT-7090
246			&& sAlwaysShowableList.find(name) == sAlwaysShowableList.end())
247		return 0;//
248	LLFloater* instance = getInstance(name, key); 
249	if (instance) 
250	{
251		instance->openFloater(key);
252		if (focus)
253			instance->setFocus(TRUE);
254	}
255	return instance;
256}
257
258//static
259// returns true if the instance exists
260bool LLFloaterReg::hideInstance(const std::string& name, const LLSD& key) 
261{ 
262	LLFloater* instance = findInstance(name, key); 
263	if (instance)
264	{
265		// When toggling *visibility*, close the host instead of the floater when hosted
266		if (instance->getHost())
267			instance->getHost()->closeFloater();
268		else
269			instance->closeFloater();
270		return true;
271	}
272	else
273	{
274		return false;
275	}
276}
277
278//static
279// returns true if the instance is visible when completed
280bool LLFloaterReg::toggleInstance(const std::string& name, const LLSD& key)
281{
282	LLFloater* instance = findInstance(name, key); 
283	if (LLFloater::isShown(instance))
284	{
285		// When toggling *visibility*, close the host instead of the floater when hosted
286		if (instance->getHost())
287			instance->getHost()->closeFloater();
288		else
289			instance->closeFloater();
290		return false;
291	}
292	else
293	{
294		return showInstance(name, key, TRUE) ? true : false;
295	}
296}
297
298//static
299// returns true if the instance exists and is visible (doesnt matter minimized or not)
300bool LLFloaterReg::instanceVisible(const std::string& name, const LLSD& key)
301{
302	LLFloater* instance = findInstance(name, key); 
303	return LLFloater::isVisible(instance);
304}
305
306//static
307void LLFloaterReg::showInitialVisibleInstances() 
308{
309	// Iterate through alll registered instance names and show any with a save visible state
310	for (build_map_t::iterator iter = sBuildMap.begin(); iter != sBuildMap.end(); ++iter)
311	{
312		const std::string& name = iter->first;
313		std::string controlname = getVisibilityControlName(name);
314		if (LLFloater::getControlGroup()->controlExists(controlname))
315		{
316			BOOL isvis = LLFloater::getControlGroup()->getBOOL(controlname);
317			if (isvis)
318			{
319				showInstance(name, LLSD()); // keyed floaters shouldn't set save_vis to true
320			}
321		}
322	}
323}
324
325//static
326void LLFloaterReg::hideVisibleInstances(const std::set<std::string>& exceptions)
327{
328	// Iterate through alll active instances and hide them
329	for (instance_map_t::iterator iter = sInstanceMap.begin(); iter != sInstanceMap.end(); ++iter)
330	{
331		const std::string& name = iter->first;
332		if (exceptions.find(name) != exceptions.end())
333			continue;
334		instance_list_t& list = iter->second;
335		for (instance_list_t::iterator iter = list.begin(); iter != list.end(); ++iter)
336		{
337			LLFloater* floater = *iter;
338			floater->pushVisible(FALSE);
339		}
340	}
341}
342
343//static
344void LLFloaterReg::restoreVisibleInstances()
345{
346	// Iterate through all active instances and restore visibility
347	for (instance_map_t::iterator iter = sInstanceMap.begin(); iter != sInstanceMap.end(); ++iter)
348	{
349		instance_list_t& list = iter->second;
350		for (instance_list_t::iterator iter = list.begin(); iter != list.end(); ++iter)
351		{
352			LLFloater* floater = *iter;
353			floater->popVisible();
354		}
355	}
356}
357
358//static
359std::string LLFloaterReg::getRectControlName(const std::string& name)
360{
361	std::string res = std::string("floater_rect_") + name;
362	LLStringUtil::replaceChar( res, ' ', '_' );
363	return res;
364}
365
366//static
367std::string LLFloaterReg::declareRectControl(const std::string& name)
368{
369	std::string controlname = getRectControlName(name);
370	LLFloater::getControlGroup()->declareRect(controlname, LLRect(),
371												 llformat("Window Position and Size for %s", name.c_str()),
372												 TRUE);
373	return controlname;
374}
375
376//static
377std::string LLFloaterReg::getVisibilityControlName(const std::string& name)
378{
379	std::string res = std::string("floater_vis_") + name;
380	LLStringUtil::replaceChar( res, ' ', '_' );
381	return res;
382}
383
384//static
385std::string LLFloaterReg::declareVisibilityControl(const std::string& name)
386{
387	std::string controlname = getVisibilityControlName(name);
388	LLFloater::getControlGroup()->declareBOOL(controlname, FALSE,
389												 llformat("Window Visibility for %s", name.c_str()),
390												 TRUE);
391	return controlname;
392}
393
394//static
395std::string LLFloaterReg::declareDockStateControl(const std::string& name)
396{
397	std::string controlname = getDockStateControlName(name);
398	LLFloater::getControlGroup()->declareBOOL(controlname, TRUE,
399												 llformat("Window Docking state for %s", name.c_str()),
400												 TRUE);
401	return controlname;
402
403}
404
405//static
406std::string LLFloaterReg::getDockStateControlName(const std::string& name)
407{
408	std::string res = std::string("floater_dock_") + name;
409	LLStringUtil::replaceChar( res, ' ', '_' );
410	return res;
411}
412
413
414//static
415void LLFloaterReg::registerControlVariables()
416{
417	// Iterate through alll registered instance names and register rect and visibility control variables
418	for (build_map_t::iterator iter = sBuildMap.begin(); iter != sBuildMap.end(); ++iter)
419	{
420		const std::string& name = iter->first;
421		if (LLFloater::getControlGroup()->controlExists(getRectControlName(name)))
422		{
423			declareRectControl(name);
424		}
425		if (LLFloater::getControlGroup()->controlExists(getVisibilityControlName(name)))
426		{
427			declareVisibilityControl(name);
428		}
429	}
430
431	const LLSD& exclude_list = LLUI::sSettingGroups["config"]->getLLSD("always_showable_floaters");
432	for (LLSD::array_const_iterator iter = exclude_list.beginArray();
433		iter != exclude_list.endArray();
434		iter++)
435	{
436		sAlwaysShowableList.insert(iter->asString());
437	}
438}
439
440//static
441void LLFloaterReg::toggleInstanceOrBringToFront(const LLSD& sdname, const LLSD& key)
442{
443	//
444	// Floaters controlled by the toolbar behave a bit differently from others.
445	// Namely they have 3-4 states as defined in the design wiki page here:
446	//   https://wiki.lindenlab.com/wiki/FUI_Button_states
447	//
448	// The basic idea is this:
449	// * If the target floater is minimized, this button press will un-minimize it.
450	// * Else if the target floater is closed open it.
451	// * Else if the target floater does not have focus, give it focus.
452	//       * Also, if it is not on top, bring it forward when focus is given.
453	// * Else the target floater is open, close it.
454	// 
455
456	std::string name = sdname.asString();
457	LLFloater* instance = getInstance(name, key); 
458
459	if (!instance)
460	{
461		lldebugs << "Unable to get instance of floater '" << name << "'" << llendl;
462	}
463	else if (instance->isMinimized())
464	{
465		instance->setMinimized(FALSE);
466		instance->setVisibleAndFrontmost();
467	}
468	else if (!instance->isShown())
469	{
470		instance->openFloater(key);
471		instance->setVisibleAndFrontmost();
472	}
473	else if (!instance->isFrontmost())
474	{
475		instance->setVisibleAndFrontmost();
476	}
477	else
478	{
479		instance->closeFloater();
480	}
481}
482
483// static
484U32 LLFloaterReg::getVisibleFloaterInstanceCount()
485{
486	U32 count = 0;
487
488	std::map<std::string,std::string>::const_iterator it = sGroupMap.begin(), it_end = sGroupMap.end();
489	for( ; it != it_end; ++it)
490	{
491		const std::string& group_name = it->second;
492
493		instance_list_t& instances = sInstanceMap[group_name];
494
495		for (instance_list_t::const_iterator iter = instances.begin(); iter != instances.end(); ++iter)
496		{
497			LLFloater* inst = *iter;
498
499			if (inst->getVisible() && !inst->isMinimized())
500			{
501				count++;
502			}
503		}
504	}
505
506	return count;
507}