// static
LLPreviewGesture* LLPreviewGesture::show(const std::string& title, const LLUUID& item_id, const LLUUID& object_id, BOOL take_focus)
{
	LLPreviewGesture* previewp = (LLPreviewGesture*)LLPreview::find(item_id);
	if (previewp)
	{
		previewp->open();   /*Flawfinder: ignore*/
		if (take_focus)
		{
			previewp->setFocus(TRUE);
		}
		return previewp;
	}

	LLPreviewGesture* self = new LLPreviewGesture();

	// Finish internal construction
	self->init(item_id, object_id);

	// Builds and adds to gFloaterView
	gUICtrlFactory->buildFloater(self, "floater_preview_gesture.xml");
	self->setTitle(title);

	// Move window to top-left of screen
	LLMultiFloater* hostp = self->getHost();
	if (hostp == NULL)
	{
		LLRect r = self->getRect();
		LLRect screen = gFloaterView->getRect();
		r.setLeftTopAndSize(0, screen.getHeight(), r.getWidth(), r.getHeight());
		self->setRect(r);
	}
	else
	{
		// re-add to host to update title
		hostp->addFloater(self, TRUE);
	}

	// this will call refresh when we have everything.
	LLViewerInventoryItem* item = (LLViewerInventoryItem*)self->getItem();
	if(item && !item->isComplete())
	{
		LLInventoryGestureAvailable* observer;
		observer = new LLInventoryGestureAvailable();
		observer->watchItem(item_id);
		gInventory.addObserver(observer);
		item->fetchFromServer();
	}
	else
	{
		// not sure this is necessary.
		self->refresh();
	}

	if (take_focus)
	{
		self->setFocus(TRUE);
	}

	return self;
}
// static
LLPreviewGesture* LLPreviewGesture::show(const std::string& title, const LLUUID& item_id, const LLUUID& object_id, BOOL take_focus)
{
	LLPreviewGesture* previewp = (LLPreviewGesture*)LLPreview::find(item_id);
	if (previewp)
	{
		previewp->open();   /*Flawfinder: ignore*/
		if (take_focus)
		{
			previewp->setFocus(TRUE);
		}
		return previewp;
	}

	LLPreviewGesture* self = new LLPreviewGesture();

	// Finish internal construction
	self->init(item_id, object_id);

	// Builds and adds to gFloaterView
	LLUICtrlFactory::getInstance()->buildFloater(self, "floater_preview_gesture.xml");
	self->setTitle(title);

	// Move window to top-left of screen
	LLMultiFloater* hostp = self->getHost();
	if (hostp == NULL)
	{
		LLRect r = self->getRect();
		LLRect screen = gFloaterView->getRect();
		r.setLeftTopAndSize(0, screen.getHeight(), r.getWidth(), r.getHeight());
		self->setRect(r);
	}
	else
	{
		// re-add to host to update title
		hostp->addFloater(self, TRUE);
	}

	// Start speculative download of sounds and animations
	const LLUUID animation_folder_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_ANIMATION);
	LLInventoryModelBackgroundFetch::instance().start(animation_folder_id);

	const LLUUID sound_folder_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_SOUND);
	LLInventoryModelBackgroundFetch::instance().start(sound_folder_id);

	// this will call refresh when we have everything.
	LLViewerInventoryItem* item = (LLViewerInventoryItem*)self->getItem();
	if(item && !item->isFinished())
	{
		LLInventoryGestureAvailable* observer;
		observer = new LLInventoryGestureAvailable();
		observer->watchItem(item_id);
		gInventory.addObserver(observer);
		item->fetchFromServer();
	}
	else
	{
		// not sure this is necessary.
		self->refresh();
	}

	if (take_focus)
	{
		self->setFocus(TRUE);
	}

	return self;
}
// static
void LLPreviewGesture::onLoadComplete(LLVFS *vfs,
									   const LLUUID& asset_uuid,
									   LLAssetType::EType type,
									   void* user_data, S32 status, LLExtStat ext_status)
{
	LLUUID* item_idp = (LLUUID*)user_data;
	LLPreview* preview = LLPreview::find(*item_idp);
	if (preview)
	{
		LLPreviewGesture* self = (LLPreviewGesture*)preview;

		if (0 == status)
		{
			LLVFile file(vfs, asset_uuid, type, LLVFile::READ);
			S32 size = file.getSize();

			std::vector<char> buffer(size+1);
			file.read((U8*)&buffer[0], size);
			buffer[size] = '\0';

			LLMultiGesture* gesture = new LLMultiGesture();

			LLDataPackerAsciiBuffer dp(&buffer[0], size+1);
			BOOL ok = gesture->deserialize(dp);

			if (ok)
			{
				// Everything has been successful.  Load up the UI.
				self->loadUIFromGesture(gesture);

				self->mStepList->selectFirstItem();

				self->mDirty = FALSE;
				self->refresh();
				self->refreshFromItem(self->getItem()); // to update description and title
			}
			else
			{
				llwarns << "Unable to load gesture" << llendl;
			}

			delete gesture;
			gesture = NULL;

			self->mAssetStatus = PREVIEW_ASSET_LOADED;
		}
		else
		{
			LLViewerStats::getInstance()->incStat( LLViewerStats::ST_DOWNLOAD_FAILED );

			if( LL_ERR_ASSET_REQUEST_NOT_IN_DATABASE == status ||
				LL_ERR_FILE_EMPTY == status)
			{
				LLDelayedGestureError::gestureMissing( *item_idp );
			}
			else
			{
				LLDelayedGestureError::gestureFailedToLoad( *item_idp );
			}

			llwarns << "Problem loading gesture: " << status << llendl;
			self->mAssetStatus = PREVIEW_ASSET_ERROR;
		}
	}
	delete item_idp;
	item_idp = NULL;
}