PageRenderTime 44ms CodeModel.GetById 17ms app.highlight 23ms RepoModel.GetById 1ms app.codeStats 0ms

/indra/newview/llnamelistctrl.cpp

https://bitbucket.org/lindenlab/viewer-beta/
C++ | 433 lines | 326 code | 54 blank | 53 comment | 52 complexity | 082c2fe8ca758229b64632fbacc3a93a MD5 | raw file
  1/** 
  2 * @file llnamelistctrl.cpp
  3 * @brief A list of names, automatically refreshed from name cache.
  4 *
  5 * $LicenseInfo:firstyear=2003&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 "llviewerprecompiledheaders.h"
 28
 29#include "llnamelistctrl.h"
 30
 31#include <boost/tokenizer.hpp>
 32
 33#include "llavatarnamecache.h"
 34#include "llcachename.h"
 35#include "llfloaterreg.h"
 36#include "llinventory.h"
 37#include "llscrolllistitem.h"
 38#include "llscrolllistcell.h"
 39#include "llscrolllistcolumn.h"
 40#include "llsdparam.h"
 41#include "lltooltip.h"
 42#include "lltrans.h"
 43
 44static LLDefaultChildRegistry::Register<LLNameListCtrl> r("name_list");
 45
 46static const S32 info_icon_size = 16;
 47
 48void LLNameListCtrl::NameTypeNames::declareValues()
 49{
 50	declare("INDIVIDUAL", LLNameListCtrl::INDIVIDUAL);
 51	declare("GROUP", LLNameListCtrl::GROUP);
 52	declare("SPECIAL", LLNameListCtrl::SPECIAL);
 53}
 54
 55LLNameListCtrl::Params::Params()
 56:	name_column(""),
 57	allow_calling_card_drop("allow_calling_card_drop", false),
 58	short_names("short_names", false)
 59{
 60}
 61
 62LLNameListCtrl::LLNameListCtrl(const LLNameListCtrl::Params& p)
 63:	LLScrollListCtrl(p),
 64	mNameColumnIndex(p.name_column.column_index),
 65	mNameColumn(p.name_column.column_name),
 66	mAllowCallingCardDrop(p.allow_calling_card_drop),
 67	mShortNames(p.short_names)
 68{}
 69
 70// public
 71void LLNameListCtrl::addNameItem(const LLUUID& agent_id, EAddPosition pos,
 72								 BOOL enabled, const std::string& suffix)
 73{
 74	//llinfos << "LLNameListCtrl::addNameItem " << agent_id << llendl;
 75
 76	NameItem item;
 77	item.value = agent_id;
 78	item.enabled = enabled;
 79	item.target = INDIVIDUAL;
 80
 81	addNameItemRow(item, pos, suffix);
 82}
 83
 84// virtual, public
 85BOOL LLNameListCtrl::handleDragAndDrop( 
 86		S32 x, S32 y, MASK mask,
 87		BOOL drop,
 88		EDragAndDropType cargo_type, void *cargo_data, 
 89		EAcceptance *accept,
 90		std::string& tooltip_msg)
 91{
 92	if (!mAllowCallingCardDrop)
 93	{
 94		return FALSE;
 95	}
 96
 97	BOOL handled = FALSE;
 98
 99	if (cargo_type == DAD_CALLINGCARD)
100	{
101		if (drop)
102		{
103			LLInventoryItem* item = (LLInventoryItem *)cargo_data;
104			addNameItem(item->getCreatorUUID());
105		}
106
107		*accept = ACCEPT_YES_MULTI;
108	}
109	else
110	{
111		*accept = ACCEPT_NO;
112		if (tooltip_msg.empty())
113		{
114			if (!getToolTip().empty())
115			{
116				tooltip_msg = getToolTip();
117			}
118			else
119			{
120				// backwards compatable English tooltip (should be overridden in xml)
121				tooltip_msg.assign("Drag a calling card here\nto add a resident.");
122			}
123		}
124	}
125
126	handled = TRUE;
127	lldebugst(LLERR_USER_INPUT) << "dragAndDrop handled by LLNameListCtrl " << getName() << llendl;
128
129	return handled;
130}
131
132void LLNameListCtrl::showInspector(const LLUUID& avatar_id, bool is_group)
133{
134	if (is_group)
135		LLFloaterReg::showInstance("inspect_group", LLSD().with("group_id", avatar_id));
136	else
137		LLFloaterReg::showInstance("inspect_avatar", LLSD().with("avatar_id", avatar_id));
138}
139
140void	LLNameListCtrl::mouseOverHighlightNthItem( S32 target_index )
141{
142	S32 cur_index = getHighlightedItemInx();
143	if (cur_index != target_index)
144	{
145		bool is_mouse_over_name_cell = false;
146
147		S32 mouse_x, mouse_y;
148		LLUI::getMousePositionLocal(this, &mouse_x, &mouse_y);
149
150		S32 column_index = getColumnIndexFromOffset(mouse_x);
151		LLScrollListItem* hit_item = hitItem(mouse_x, mouse_y);
152		if (hit_item && column_index == mNameColumnIndex)
153		{
154			// Get the name cell which is currently under the mouse pointer.
155			LLScrollListCell* hit_cell = hit_item->getColumn(column_index);
156			if (hit_cell)
157			{
158				is_mouse_over_name_cell = getCellRect(cur_index, column_index).pointInRect(mouse_x, mouse_y);
159			}
160		}
161
162		// If the tool tip is visible and the mouse is over the currently highlighted item's name cell,
163		// we should not reset the highlighted item index i.e. set mHighlightedItem = -1
164		// and should not increase the width of the text inside the cell because it may
165		// overlap the tool tip icon.
166		if (LLToolTipMgr::getInstance()->toolTipVisible() && is_mouse_over_name_cell)
167			return;
168
169		if(0 <= cur_index && cur_index < (S32)getItemList().size())
170		{
171			LLScrollListItem* item = getItemList()[cur_index];
172			if (item)
173			{
174				LLScrollListText* cell = dynamic_cast<LLScrollListText*>(item->getColumn(mNameColumnIndex));
175				if (cell)
176					cell->setTextWidth(cell->getTextWidth() + info_icon_size);
177			}
178			else
179			{
180				llwarns << "highlighted name list item is NULL" << llendl;
181			}
182		}
183		if(target_index != -1)
184		{
185			LLScrollListItem* item = getItemList()[target_index];
186			LLScrollListText* cell = dynamic_cast<LLScrollListText*>(item->getColumn(mNameColumnIndex));
187			if (item)
188			{
189				if (cell)
190					cell->setTextWidth(cell->getTextWidth() - info_icon_size);
191			}
192			else
193			{
194				llwarns << "target name item is NULL" << llendl;
195			}
196		}
197	}
198
199	LLScrollListCtrl::mouseOverHighlightNthItem(target_index);
200}
201
202//virtual
203BOOL LLNameListCtrl::handleToolTip(S32 x, S32 y, MASK mask)
204{
205	BOOL handled = FALSE;
206	S32 column_index = getColumnIndexFromOffset(x);
207	LLScrollListItem* hit_item = hitItem(x, y);
208	if (hit_item
209		&& column_index == mNameColumnIndex)
210	{
211		// ...this is the column with the avatar name
212		LLUUID avatar_id = hit_item->getUUID();
213		if (avatar_id.notNull())
214		{
215			// ...valid avatar id
216
217			LLScrollListCell* hit_cell = hit_item->getColumn(column_index);
218			if (hit_cell)
219			{
220				S32 row_index = getItemIndex(hit_item);
221				LLRect cell_rect = getCellRect(row_index, column_index);
222				// Convert rect local to screen coordinates
223				LLRect sticky_rect;
224				localRectToScreen(cell_rect, &sticky_rect);
225
226				// Spawn at right side of cell
227				LLPointer<LLUIImage> icon = LLUI::getUIImage("Info_Small");
228				LLCoordGL pos( sticky_rect.mRight - info_icon_size, sticky_rect.mTop - (sticky_rect.getHeight() - icon->getHeight())/2 );
229
230				// Should we show a group or an avatar inspector?
231				bool is_group = hit_item->getValue()["is_group"].asBoolean();
232
233				LLToolTip::Params params;
234				params.background_visible( false );
235				params.click_callback( boost::bind(&LLNameListCtrl::showInspector, this, avatar_id, is_group) );
236				params.delay_time(0.0f);		// spawn instantly on hover
237				params.image( icon );
238				params.message("");
239				params.padding(0);
240				params.pos(pos);
241				params.sticky_rect(sticky_rect);
242
243				LLToolTipMgr::getInstance()->show(params);
244				handled = TRUE;
245			}
246		}
247	}
248	if (!handled)
249	{
250		handled = LLScrollListCtrl::handleToolTip(x, y, mask);
251	}
252	return handled;
253}
254
255// public
256void LLNameListCtrl::addGroupNameItem(const LLUUID& group_id, EAddPosition pos,
257									  BOOL enabled)
258{
259	NameItem item;
260	item.value = group_id;
261	item.enabled = enabled;
262	item.target = GROUP;
263
264	addNameItemRow(item, pos);
265}
266
267// public
268void LLNameListCtrl::addGroupNameItem(LLNameListCtrl::NameItem& item, EAddPosition pos)
269{
270	item.target = GROUP;
271	addNameItemRow(item, pos);
272}
273
274void LLNameListCtrl::addNameItem(LLNameListCtrl::NameItem& item, EAddPosition pos)
275{
276	item.target = INDIVIDUAL;
277	addNameItemRow(item, pos);
278}
279
280LLScrollListItem* LLNameListCtrl::addElement(const LLSD& element, EAddPosition pos, void* userdata)
281{
282	LLNameListCtrl::NameItem item_params;
283	LLParamSDParser parser;
284	parser.readSD(element, item_params);
285	item_params.userdata = userdata;
286	return addNameItemRow(item_params, pos);
287}
288
289
290LLScrollListItem* LLNameListCtrl::addNameItemRow(
291	const LLNameListCtrl::NameItem& name_item,
292	EAddPosition pos,
293	const std::string& suffix)
294{
295	LLUUID id = name_item.value().asUUID();
296	LLNameListItem* item = NULL;
297
298	// Store item type so that we can invoke the proper inspector.
299	// *TODO Vadim: Is there a more proper way of storing additional item data?
300	{
301		LLNameListCtrl::NameItem item_p(name_item);
302		item_p.value = LLSD().with("uuid", id).with("is_group", name_item.target() == GROUP);
303		item = new LLNameListItem(item_p);
304		LLScrollListCtrl::addRow(item, item_p, pos);
305	}
306
307	if (!item) return NULL;
308
309	// use supplied name by default
310	std::string fullname = name_item.name;
311	switch(name_item.target)
312	{
313	case GROUP:
314		gCacheName->getGroupName(id, fullname);
315		// fullname will be "nobody" if group not found
316		break;
317	case SPECIAL:
318		// just use supplied name
319		break;
320	case INDIVIDUAL:
321		{
322			LLAvatarName av_name;
323			if (id.isNull())
324			{
325				fullname = LLTrans::getString("AvatarNameNobody");
326			}
327			else if (LLAvatarNameCache::get(id, &av_name))
328			{
329				if (mShortNames)
330					fullname = av_name.mDisplayName;
331				else
332					fullname = av_name.getCompleteName();
333			}
334			else
335			{
336				// ...schedule a callback
337				LLAvatarNameCache::get(id,
338					boost::bind(&LLNameListCtrl::onAvatarNameCache,
339						this, _1, _2));
340			}
341			break;
342		}
343	default:
344		break;
345	}
346	
347	// Append optional suffix.
348	if (!suffix.empty())
349	{
350		fullname.append(suffix);
351	}
352
353	LLScrollListCell* cell = item->getColumn(mNameColumnIndex);
354	if (cell)
355	{
356		cell->setValue(fullname);
357	}
358
359	dirtyColumns();
360
361	// this column is resizable
362	LLScrollListColumn* columnp = getColumn(mNameColumnIndex);
363	if (columnp && columnp->mHeader)
364	{
365		columnp->mHeader->setHasResizableElement(TRUE);
366	}
367
368	return item;
369}
370
371// public
372void LLNameListCtrl::removeNameItem(const LLUUID& agent_id)
373{
374	// Find the item specified with agent_id.
375	S32 idx = -1;
376	for (item_list::iterator it = getItemList().begin(); it != getItemList().end(); it++)
377	{
378		LLScrollListItem* item = *it;
379		if (item->getUUID() == agent_id)
380		{
381			idx = getItemIndex(item);
382			break;
383		}
384	}
385
386	// Remove it.
387	if (idx >= 0)
388	{
389		selectNthItem(idx); // not sure whether this is needed, taken from previous implementation
390		deleteSingleItem(idx);
391	}
392}
393
394void LLNameListCtrl::onAvatarNameCache(const LLUUID& agent_id,
395									   const LLAvatarName& av_name)
396{
397	std::string name;
398	if (mShortNames)
399		name = av_name.mDisplayName;
400	else
401		name = av_name.getCompleteName();
402
403	item_list::iterator iter;
404	for (iter = getItemList().begin(); iter != getItemList().end(); iter++)
405	{
406		LLScrollListItem* item = *iter;
407		if (item->getUUID() == agent_id)
408		{
409			LLScrollListCell* cell = item->getColumn(mNameColumnIndex);
410			if (cell)
411			{
412				cell->setValue(name);
413			}
414		}
415	}
416
417	dirtyColumns();
418}
419
420
421void LLNameListCtrl::updateColumns()
422{
423	LLScrollListCtrl::updateColumns();
424
425	if (!mNameColumn.empty())
426	{
427		LLScrollListColumn* name_column = getColumn(mNameColumn);
428		if (name_column)
429		{
430			mNameColumnIndex = name_column->mIndex;
431		}
432	}
433}