Skip to content
Snippets Groups Projects
llfloaterpreference.cpp 48.1 KiB
Newer Older
James Cook's avatar
James Cook committed
/** 
 * @file llfloaterpreference.cpp
 * @brief Global preferences with and without persistence.
James Cook's avatar
James Cook committed
 *
 * $LicenseInfo:firstyear=2002&license=viewergpl$
 * 
 * Copyright (c) 2002-2009, Linden Research, Inc.
 * 
 * Second Life Viewer Source Code
 * The source code in this file ("Source Code") is provided by Linden Lab
 * to you under the terms of the GNU General Public License, version 2.0
 * ("GPL"), unless you have obtained a separate licensing agreement
 * ("Other License"), formally executed by you and Linden Lab.  Terms of
 * the GPL can be found in doc/GPL-license.txt in this distribution, or
 * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
 * 
 * There are special exceptions to the terms and conditions of the GPL as
 * it is applied to this Source Code. View the full text of the exception
 * in the file doc/FLOSS-exception.txt in this software distribution, or
 * online at
 * http://secondlifegrid.net/programs/open_source/licensing/flossexception
 * 
 * By copying, modifying or distributing this software, you acknowledge
 * that you have read and understood your obligations described above,
 * and agree to abide by those obligations.
 * 
 * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
 * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
 * COMPLETENESS OR PERFORMANCE.
 * $/LicenseInfo$
James Cook's avatar
James Cook committed
 */

/*
 * App-wide preferences.  Note that these are not per-user,
 * because we need to load many preferences before we have
 * a login name.
 */

#include "llviewerprecompiledheaders.h"

#include "llfloaterpreference.h"

#include "message.h"

#include "llagent.h"
#include "llavatarconstants.h"
#include "llcheckboxctrl.h"
#include "lldirpicker.h"
#include "llfeaturemanager.h"
#include "llfocusmgr.h"
#include "llfirstuse.h"
#include "llfloaterreg.h"
James Cook's avatar
James Cook committed
#include "llfloaterabout.h"
#include "llfloaterhardwaresettings.h"
#include "llfloatervoicedevicesettings.h"
#include "llkeyboard.h"
#include "llmodaldialog.h"
#include "llradiogroup.h"
#include "llstylemap.h"
#include "llscrolllistctrl.h"
#include "llscrolllistitem.h"
#include "llsliderctrl.h"
#include "lltabcontainer.h"
#include "lltexteditor.h"
James Cook's avatar
James Cook committed
#include "llviewercontrol.h"
#include "llviewercamera.h"
James Cook's avatar
James Cook committed
#include "llviewerwindow.h"
#include "llviewermessage.h"
#include "llviewershadermgr.h"
#include "llvotree.h"
#include "llvosky.h"

// linden library includes
#include "llerror.h"
#include "llfontgl.h"
#include "llrect.h"
#include "llstring.h"

// project includes

#include "llbutton.h"
#include "llflexibleobject.h"
#include "lllineeditor.h"
#include "llresmgr.h"
#include "llspinctrl.h"
#include "llstartup.h"
#include "lltextbox.h"
#include "llui.h"
#include "llviewerobjectlist.h"
#include "llvoavatar.h"
#include "llvovolume.h"
#include "llwindow.h"
#include "llworld.h"
#include "pipeline.h"
#include "lluictrlfactory.h"
#include "llboost.h"


//RN temporary includes for resolution switching
#include "llglheaders.h"
const F32 MAX_USER_FAR_CLIP = 512.f;
const F32 MIN_USER_FAR_CLIP = 64.f;

const S32 ASPECT_RATIO_STR_LEN = 100;
James Cook's avatar
James Cook committed

class LLVoiceSetKeyDialog : public LLModalDialog
	public:
		LLVoiceSetKeyDialog(LLFloaterPreference* parent);
		~LLVoiceSetKeyDialog();
		
		BOOL handleKeyHere(KEY key, MASK mask);
		static void onCancel(void* user_data);
		
	private:
		LLFloaterPreference* mParent;
	};
LLVoiceSetKeyDialog::LLVoiceSetKeyDialog(LLFloaterPreference* parent)
: LLModalDialog(LLStringUtil::null, 240, 100), mParent(parent)
James Cook's avatar
James Cook committed
{
	LLUICtrlFactory::getInstance()->buildFloater(this, "floater_select_key.xml");
	childSetAction("Cancel", onCancel, this);
	childSetFocus("Cancel");
	
	gFocusMgr.setKeystrokesOnly(TRUE);
LLVoiceSetKeyDialog::~LLVoiceSetKeyDialog()
BOOL LLVoiceSetKeyDialog::handleKeyHere(KEY key, MASK mask)
James Cook's avatar
James Cook committed
{
	BOOL result = TRUE;
	
	if(key == 'Q' && mask == MASK_CONTROL)
	{
		result = FALSE;
	}
	else
	{
		mParent->setKey(key);
	}
	
	closeFloater();
	return result;
}
James Cook's avatar
James Cook committed

//static
void LLVoiceSetKeyDialog::onCancel(void* user_data)
{
	LLVoiceSetKeyDialog* self = (LLVoiceSetKeyDialog*)user_data;
	self->closeFloater();
}
// helper functions for getting/freeing the web browser media
// if creating/destroying these is too slow, we'll need to create
// a static member and update all our static callbacks
James Cook's avatar
James Cook committed

void free_web_media(LLMediaBase *media_source);
void handleHTMLLinkColorChanged(const LLSD& newvalue);	
LLMediaBase *get_web_media();
bool callback_clear_browser_cache(const LLSD& notification, const LLSD& response);
James Cook's avatar
James Cook committed

bool callback_skip_dialogs(const LLSD& notification, const LLSD& response, LLFloaterPreference* floater);
bool callback_reset_dialogs(const LLSD& notification, const LLSD& response, LLFloaterPreference* floater);
James Cook's avatar
James Cook committed

bool extractWindowSizeFromString(const std::string& instr, U32 &width, U32 &height);
void fractionFromDecimal(F32 decimal_val, S32& numerator, S32& denominator);

LLMediaBase *get_web_media()
{
	LLMediaBase *media_source;
	LLMediaManager *mgr = LLMediaManager::getInstance();
	
	if (!mgr)
	{
		llwarns << "cannot get media manager" << llendl;
		return NULL;
	}
	
	media_source = mgr->createSourceFromMimeType("http", "text/html" );
	if ( !media_source )
	{
		llwarns << "media source create failed " << llendl;
		return NULL;
	}
	
	return media_source;
}
void free_web_media(LLMediaBase *media_source)
{
	if (!media_source)
		return;
	
	LLMediaManager *mgr = LLMediaManager::getInstance();
	if (!mgr)
	{
		llwarns << "cannot get media manager" << llendl;
		return;
	}
	
	mgr->destroySource(media_source);
}
James Cook's avatar
James Cook committed

bool callback_clear_browser_cache(const LLSD& notification, const LLSD& response)
{
	S32 option = LLNotification::getSelectedOption(notification, response);
	if ( option == 0 ) // YES
		LLMediaBase *media_source = get_web_media();
		if (media_source)
			media_source->clearCache();
		free_web_media(media_source);
void handleHTMLLinkColorChanged(const LLSD& newvalue)
{
	LLTextEditor::setLinkColor(LLColor4(newvalue));
	LLStyleMap::instance().update();
James Cook's avatar
James Cook committed

bool callback_skip_dialogs(const LLSD& notification, const LLSD& response, LLFloaterPreference* floater)
{
	S32 option = LLNotification::getSelectedOption(notification, response);
	if (0 == option && floater )
		if ( floater )
		{
			floater->setAllIgnored();
			LLFirstUse::disableFirstUse();
			LLFloaterPreference::buildLists(floater);
		}
bool callback_reset_dialogs(const LLSD& notification, const LLSD& response, LLFloaterPreference* floater)
	S32 option = LLNotification::getSelectedOption(notification, response);
	if ( 0 == option && floater )
		if ( floater )
		{
			floater->resetAllIgnored();
			LLFirstUse::resetFirstUse();
			LLFloaterPreference::buildLists(floater);
		}

// Extract from strings of the form "<width> x <height>", e.g. "640 x 480".
bool extractWindowSizeFromString(const std::string& instr, U32 &width, U32 &height)
{
	using namespace boost;
	cmatch what;
	const regex expression("([0-9]+) x ([0-9]+)");
	if (regex_match(instr.c_str(), what, expression))
	{
		width = atoi(what[1].first);
		height = atoi(what[2].first);
		return true;
	}
	
	width = height = 0;
	return false;
}

void fractionFromDecimal(F32 decimal_val, S32& numerator, S32& denominator)
{
	numerator = 0;
	denominator = 0;
	for (F32 test_denominator = 1.f; test_denominator < 30.f; test_denominator += 1.f)
	{
		if (fmodf((decimal_val * test_denominator) + 0.01f, 1.f) < 0.02f)
		{
			numerator = llround(decimal_val * test_denominator);
			denominator = llround(test_denominator);
			break;
		}
	}
}
// static
std::string LLFloaterPreference::sSkin = "";
F32 LLFloaterPreference::sAspectRatio = 0.0;
//////////////////////////////////////////////
// LLFloaterPreference

LLFloaterPreference::LLFloaterPreference(const LLSD& key)
	: LLFloater(key),
	mGotPersonalInfo(false),
	mOriginalIMViaEmail(false)
{
	//Build Floater is now Called from 	LLFloaterReg::add("preferences", "floater_preferences.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterPreference>);
          
	mCommitCallbackRegistrar.add("Pref.Apply",				boost::bind(&LLFloaterPreference::onBtnApply, this));
	mCommitCallbackRegistrar.add("Pref.Cancel",				boost::bind(&LLFloaterPreference::onBtnCancel, this));
	mCommitCallbackRegistrar.add("Pref.OK",					boost::bind(&LLFloaterPreference::onBtnOK, this));
	
	mCommitCallbackRegistrar.add("Pref.ClearCache",				boost::bind(&LLFloaterPreference::onClickClearCache, (void*)NULL));
	mCommitCallbackRegistrar.add("Pref.WebClearCache",			boost::bind(&LLFloaterPreference::onClickBrowserClearCache, (void*)NULL));
	mCommitCallbackRegistrar.add("Pref.SetCache",				boost::bind(&LLFloaterPreference::onClickSetCache, this));
	mCommitCallbackRegistrar.add("Pref.ResetCache",				boost::bind(&LLFloaterPreference::onClickResetCache, this));
	mCommitCallbackRegistrar.add("Pref.ClickSkin",				boost::bind(&LLFloaterPreference::onClickSkin, this,_1, _2));
	mCommitCallbackRegistrar.add("Pref.SelectSkin",				boost::bind(&LLFloaterPreference::onSelectSkin, this));
	mCommitCallbackRegistrar.add("Pref.VoiceSetKey",			boost::bind(&LLFloaterPreference::onClickSetKey, this));
	mCommitCallbackRegistrar.add("Pref.VoiceSetMiddleMouse",	boost::bind(&LLFloaterPreference::onClickSetMiddleMouse, this));
	mCommitCallbackRegistrar.add("Pref.ClickSkipDialogs",		boost::bind(&LLFloaterPreference::onClickSkipDialogs, this));
	mCommitCallbackRegistrar.add("Pref.ClickResetDialogs",		boost::bind(&LLFloaterPreference::onClickResetDialogs, this));
	mCommitCallbackRegistrar.add("Pref.ClickEnablePopup",		boost::bind(&LLFloaterPreference::onClickEnablePopup, this));
	mCommitCallbackRegistrar.add("Pref.LogPath",				boost::bind(&LLFloaterPreference::onClickLogPath, this));
	mCommitCallbackRegistrar.add("Pref.Logging",				boost::bind(&LLFloaterPreference::onCommitLogging, this));
	mCommitCallbackRegistrar.add("Pref.OpenHelp",				boost::bind(&LLFloaterPreference::onOpenHelp, this));	
	mCommitCallbackRegistrar.add("Pref.UpdateMeterText",		boost::bind(&LLFloaterPreference::updateMeterText, this, _1));	
	mCommitCallbackRegistrar.add("Pref.HardwareSettings",       boost::bind(&LLFloaterPreference::onOpenHardwareSettings, this));	
	mCommitCallbackRegistrar.add("Pref.HardwareDefaults",       boost::bind(&LLFloaterPreference::setHardwareDefaults, this));	
	mCommitCallbackRegistrar.add("Pref.VertexShaderEnable",     boost::bind(&LLFloaterPreference::onVertexShaderEnable, this));	
	mCommitCallbackRegistrar.add("Pref.WindowedMod",            boost::bind(&LLFloaterPreference::onCommitWindowedMode, this));	
	mCommitCallbackRegistrar.add("Pref.UpdateSliderText",       boost::bind(&LLFloaterPreference::onUpdateSliderText,this, _1,_2));	
	mCommitCallbackRegistrar.add("Pref.AutoDetectAspect",       boost::bind(&LLFloaterPreference::onCommitAutoDetectAspect, this));	
	mCommitCallbackRegistrar.add("Pref.onSelectAspectRatio",    boost::bind(&LLFloaterPreference::onKeystrokeAspectRatio, this));	
	mCommitCallbackRegistrar.add("Pref.QualityPerformance",     boost::bind(&LLFloaterPreference::onChangeQuality, this, _2));	

}

BOOL LLFloaterPreference::postBuild()
{
	LLTabContainer* tabcontainer = getChild<LLTabContainer>("pref core");
	if (!tabcontainer->selectTab(gSavedSettings.getS32("LastPrefTab")))
		tabcontainer->selectFirstTab();
	return TRUE;
}

LLFloaterPreference::~LLFloaterPreference()
{
	// clean up user data
	LLComboBox* ctrl_aspect_ratio = getChild<LLComboBox>( "aspect_ratio");
	LLComboBox* ctrl_window_size = getChild<LLComboBox>("windowsize combo");
	for (S32 i = 0; i < ctrl_aspect_ratio->getItemCount(); i++)
	{
		ctrl_aspect_ratio->setCurrentByIndex(i);
	}
	for (S32 i = 0; i < ctrl_window_size->getItemCount(); i++)
	{
		ctrl_window_size->setCurrentByIndex(i);
	}
}
void LLFloaterPreference::draw()
{
	BOOL has_first_selected = (getChildRef<LLScrollListCtrl>("disabled_popups").getFirstSelected()!=NULL);
	gSavedSettings.setBOOL("FirstSelectedDisabledPopups", has_first_selected);
	LLFloater::draw();
}

void LLFloaterPreference::apply()
{
	LLTabContainer* tabcontainer = getChild<LLTabContainer>("pref core");
	if (sSkin != gSavedSettings.getString("SkinCurrent"))
		LLNotifications::instance().add("ChangeSkin");
		refreshSkin(this);
	// Call apply() on all panels that derive from LLPanelPreference
	for (child_list_t::const_iterator iter = tabcontainer->getChildList()->begin();
		 iter != tabcontainer->getChildList()->end(); ++iter)
		LLView* view = *iter;
		LLPanelPreference* panel = dynamic_cast<LLPanelPreference*>(view);
		if (panel)
			panel->apply();
	// hardware menu apply
	LLFloaterHardwareSettings::instance()->apply();
	
	LLFloaterVoiceDeviceSettings* voice_device_settings = LLFloaterReg::findTypedInstance<LLFloaterVoiceDeviceSettings>("pref_voicedevicesettings");
	if(voice_device_settings)
		voice_device_settings->apply();
	
	gViewerWindow->requestResolutionUpdate(); // for UIScaleFactor
	LLSliderCtrl* fov_slider = getChild<LLSliderCtrl>("camera_fov");
	fov_slider->setMinValue(LLViewerCamera::getInstance()->getMinView());
	fov_slider->setMaxValue(LLViewerCamera::getInstance()->getMaxView());
	
	std::string cache_location = gDirUtilp->getExpandedFilename(LL_PATH_CACHE, "");
	childSetText("cache_location", cache_location);		
	
	LLMediaBase *media_source = get_web_media();
	if (media_source)
		media_source->enableCookies(childGetValue("cookies_enabled"));
		if(hasChild("web_proxy_enabled") &&hasChild("web_proxy_editor") && hasChild("web_proxy_port"))
		{
			bool proxy_enable = childGetValue("web_proxy_enabled");
			std::string proxy_address = childGetValue("web_proxy_editor");
			
			int proxy_port = childGetValue("web_proxy_port");
			media_source->enableProxy(proxy_enable, proxy_address, proxy_port);
		}
	free_web_media(media_source);
	
	LLTextEditor* busy = getChild<LLTextEditor>("busy_response");
	LLWString busy_response;
	if (busy) busy_response = busy->getWText(); 
	LLWStringUtil::replaceTabsWithSpaces(busy_response, 4);
	
	if(mGotPersonalInfo)
	{ 
		gSavedPerAccountSettings.setString("BusyModeResponse2", std::string(wstring_to_utf8str(busy_response)));
		bool new_im_via_email = childGetValue("send_im_to_email").asBoolean();
		bool new_hide_online = childGetValue("online_visibility").asBoolean();		
	
		if((new_im_via_email != mOriginalIMViaEmail)
			||(new_hide_online != mOriginalHideOnlineStatus))
		{
			// This hack is because we are representing several different 	 
			// possible strings with a single checkbox. Since most users 	 
			// can only select between 2 values, we represent it as a 	 
			// checkbox. This breaks down a little bit for liaisons, but 	 
			// works out in the end. 	 
			if(new_hide_online != mOriginalHideOnlineStatus) 	 
			{ 	 
				if(new_hide_online) mDirectoryVisibility = VISIBILITY_HIDDEN;
				else mDirectoryVisibility = VISIBILITY_DEFAULT;
			 //Update showonline value, otherwise multiple applys won't work
				mOriginalHideOnlineStatus = new_hide_online;
			} 	 
			gAgent.sendAgentUpdateUserInfo(new_im_via_email,mDirectoryVisibility);
		}
	}

	applyResolution();
	
	// Only set window size if we're not in fullscreen mode
	if(!gSavedSettings.getBOOL("WindowFullScreen"))
}

void LLFloaterPreference::cancel()
{
	LLTabContainer* tabcontainer = getChild<LLTabContainer>("pref core");
	// Call cancel() on all panels that derive from LLPanelPreference
	for (child_list_t::const_iterator iter = tabcontainer->getChildList()->begin();
		iter != tabcontainer->getChildList()->end(); ++iter)
		LLView* view = *iter;
		LLPanelPreference* panel = dynamic_cast<LLPanelPreference*>(view);
		if (panel)
			panel->cancel();
	// hide joystick pref floater
	LLFloaterReg::hideInstance("pref_joystick");
	
	// cancel hardware menu
	LLFloaterHardwareSettings::instance()->cancel();   // TODO: angela  change the build of the floater to floater reg
	
	// reverts any changes to current skin
	gSavedSettings.setString("SkinCurrent", sSkin);
	
	LLFloaterVoiceDeviceSettings* voice_device_settings = LLFloaterReg::findTypedInstance<LLFloaterVoiceDeviceSettings>("pref_voicedevicesettings");
	if (voice_device_settings)
		voice_device_settings ->cancel();
	LLFloaterReg::hideInstance("pref_voicedevicesettings");
	
	gSavedSettings.setF32("FullScreenAspectRatio", sAspectRatio);

}

void LLFloaterPreference::onOpen(const LLSD& key)
{
	gAgent.sendAgentUserInfoRequest();
	LLPanelLogin::setAlwaysRefresh(true);
}

void LLFloaterPreference::onVertexShaderEnable()
{
	refreshEnabledGraphics();
}

void LLFloaterPreference::setHardwareDefaults()
{
	LLFeatureManager::getInstance()->applyRecommendedSettings();
	refreshEnabledGraphics();
}
void LLFloaterPreference::onClose(bool app_quitting)
{
	gSavedSettings.setS32("LastPrefTab", getChild<LLTabContainer>("pref core")->getCurrentPanelIndex());
	LLPanelLogin::setAlwaysRefresh(false);
	cancel(); // will be a no-op if OK or apply was performed just prior.
	destroy();
}
void LLFloaterPreference::onOpenHardwareSettings()
{
	LLFloaterHardwareSettings::show();
}
// static 
void LLFloaterPreference::onBtnOK()
{
	// commit any outstanding text entry
	if (hasFocus())
		LLUICtrl* cur_focus = gFocusMgr.getKeyboardFocus();
		if (cur_focus->acceptsTextInput())
		{
			cur_focus->onCommit();
		}
		apply();
		closeFloater(false);
		gSavedSettings.saveToFile( gSavedSettings.getString("ClientSettingsFile"), TRUE );
		LLUIColorTable::instance().saveUserSettings();
		std::string crash_settings_filename = gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, CRASH_SETTINGS_FILE);
		// save all settings, even if equals defaults
		gCrashSettings.saveToFile(crash_settings_filename, FALSE);
		// Show beep, pop up dialog, etc.
		llinfos << "Can't close preferences!" << llendl;
	LLPanelLogin::refreshLocation( false );
void LLFloaterPreference::onOpenHelp()
{
	const char* xml_alert = "GraphicsPreferencesHelp";
	LLNotifications::instance().add(this->contextualNotification(xml_alert));
}
// static 
void LLFloaterPreference::onBtnApply( )
James Cook's avatar
James Cook committed
{
	if (hasFocus())
	{
		LLUICtrl* cur_focus = gFocusMgr.getKeyboardFocus();
		if (cur_focus->acceptsTextInput())
		{
			cur_focus->onCommit();
		}
	}
	apply();
	LLPanelLogin::refreshLocation( false );
}
// static 
void LLFloaterPreference::onBtnCancel()
{
	if (hasFocus())
		LLUICtrl* cur_focus = gFocusMgr.getKeyboardFocus();
		if (cur_focus->acceptsTextInput())
		{
			cur_focus->onCommit();
		}
	closeFloater(); // side effect will also cancel any unsaved changes.
// static 
void LLFloaterPreference::updateUserInfo(const std::string& visibility, bool im_via_email, const std::string& email)
James Cook's avatar
James Cook committed
{
	LLFloaterPreference* instance = LLFloaterReg::findTypedInstance<LLFloaterPreference>("preferences");
	if(instance)
		instance->setPersonalInfo(visibility, im_via_email, email);	

void LLFloaterPreference::refreshEnabledGraphics()
{
	LLFloaterPreference* instance = LLFloaterReg::findTypedInstance<LLFloaterPreference>("preferences");
	if(instance)
	{
		LLFloaterHardwareSettings::instance()->refreshEnabledState();
		instance->refreshEnabledState();
James Cook's avatar
James Cook committed
}
void LLFloaterPreference::updateMeterText(LLUICtrl* ctrl)
{
	// get our UI widgets
	LLSliderCtrl* slider = (LLSliderCtrl*) ctrl;
James Cook's avatar
James Cook committed

	LLTextBox* m1 = getChild<LLTextBox>("DrawDistanceMeterText1");
	LLTextBox* m2 = getChild<LLTextBox>("DrawDistanceMeterText2");
James Cook's avatar
James Cook committed

	// toggle the two text boxes based on whether we have 1 or two digits
	F32 val = slider->getValueF32();
	bool two_digits = val < 100;
	m1->setVisible(two_digits);
	m2->setVisible(!two_digits);
// static
void LLFloaterPreference::onClickClearCache(void*)
	// flag client cache for clearing next time the client runs
	gSavedSettings.setBOOL("PurgeCacheOnNextStartup", TRUE);
	LLNotifications::instance().add("CacheWillClear");
// static
void LLFloaterPreference::onClickBrowserClearCache(void*)
James Cook's avatar
James Cook committed
{
	LLNotifications::instance().add("ConfirmClearBrowserCache", LLSD(), LLSD(), callback_clear_browser_cache);
void LLFloaterPreference::onClickSetCache()
James Cook's avatar
James Cook committed
{
	std::string cur_name(gSavedSettings.getString("CacheLocation"));
	std::string proposed_name(cur_name);
James Cook's avatar
James Cook committed

	LLDirPicker& picker = LLDirPicker::instance();
	if (! picker.getDir(&proposed_name ) )
James Cook's avatar
James Cook committed
	{
	std::string dir_name = picker.getDirName();
	if (!dir_name.empty() && dir_name != cur_name)
	{
		childSetText("cache_location", dir_name);
		LLNotifications::instance().add("CacheWillBeMoved");
		gSavedSettings.setString("NewCacheLocation", dir_name);
	}
	else
	{
		std::string cache_location = gDirUtilp->getCacheDir();
		childSetText("cache_location", cache_location);
	}
void LLFloaterPreference::onClickResetCache()
James Cook's avatar
James Cook committed
{
	if (!gSavedSettings.getString("CacheLocation").empty())
	{
		gSavedSettings.setString("NewCacheLocation", "");
		LLNotifications::instance().add("CacheWillBeMoved");
	}
	std::string cache_location = gDirUtilp->getCacheDir(true);
	childSetText("cache_location", cache_location);
void LLFloaterPreference::onClickSkin(LLUICtrl* ctrl, const LLSD& userdata)
James Cook's avatar
James Cook committed
{
	gSavedSettings.setString("SkinCurrent", userdata.asString());
	ctrl->setValue(userdata.asString());
void LLFloaterPreference::onSelectSkin()
James Cook's avatar
James Cook committed
{
	std::string skin_selection = getChild<LLRadioGroup>("skin_selection")->getValue().asString();
	gSavedSettings.setString("SkinCurrent", skin_selection);
void LLFloaterPreference::refreshSkin(void* data)
{
	LLPanel*self = (LLPanel*)data;
	sSkin = gSavedSettings.getString("SkinCurrent");
	self->getChild<LLRadioGroup>("skin_selection", true)->setValue(sSkin);
}
James Cook's avatar
James Cook committed

// static
void LLFloaterPreference::buildLists(void* data)
James Cook's avatar
James Cook committed
{
	LLPanel*self = (LLPanel*)data;
	LLScrollListCtrl& disabled_popups = self->getChildRef<LLScrollListCtrl>("disabled_popups");
	LLScrollListCtrl& enabled_popups = self->getChildRef<LLScrollListCtrl>("enabled_popups");
	
	disabled_popups.deleteAllItems();
	enabled_popups.deleteAllItems();
	
	for (LLNotifications::TemplateMap::const_iterator iter = LLNotifications::instance().templatesBegin();
		 iter != LLNotifications::instance().templatesEnd();
		 ++iter)
James Cook's avatar
James Cook committed
	{
		LLNotificationTemplatePtr templatep = iter->second;
		LLNotificationFormPtr formp = templatep->mForm;
		
		LLNotificationForm::EIgnoreType ignore = formp->getIgnoreType();
		if (ignore == LLNotificationForm::IGNORE_NO)
			continue;
		
		LLSD row;
		row["columns"][0]["value"] = formp->getIgnoreMessage();
		row["columns"][0]["font"] = "SANSSERIF_SMALL";
		row["columns"][0]["width"] = 400;
		
		LLScrollListItem* item = NULL;
		
		bool show_popup = LLUI::sSettingGroups["ignores"]->getBOOL(templatep->mName);
		if (!show_popup)
		{
			if (ignore == LLNotificationForm::IGNORE_WITH_LAST_RESPONSE)
			{
				LLSD last_response = LLUI::sSettingGroups["config"]->getLLSD("Default" + templatep->mName);
				if (!last_response.isUndefined())
				{
					for (LLSD::map_const_iterator it = last_response.beginMap();
						 it != last_response.endMap();
						 ++it)
					{
						if (it->second.asBoolean())
						{
							row["columns"][1]["value"] = formp->getElement(it->first)["ignore"].asString();
							break;
						}
					}
				}
				row["columns"][1]["font"] = "SANSSERIF_SMALL";
				row["columns"][1]["width"] = 360;
			}
			item = disabled_popups.addElement(row,
											  ADD_SORTED);
		}
		else
		{
			item = enabled_popups.addElement(row,
											 ADD_SORTED);
		}
		
		if (item)
		{
			item->setUserdata((void*)&iter->first);
		}
James Cook's avatar
James Cook committed
	}
James Cook's avatar
James Cook committed

void LLFloaterPreference::refreshEnabledState()
{
	
	LLCheckBoxCtrl* ctrl_reflections = getChild<LLCheckBoxCtrl>("Reflections");
	LLRadioGroup* radio_reflection_detail = getChild<LLRadioGroup>("ReflectionDetailRadio");
	
	// Reflections
	BOOL reflections = gSavedSettings.getBOOL("VertexShaderEnable") 
		&& gGLManager.mHasCubeMap
		&& LLCubeMap::sUseCubeMaps;
	ctrl_reflections->setEnabled(reflections);
	
	// Bump & Shiny	
	bool bumpshiny = gGLManager.mHasCubeMap && LLCubeMap::sUseCubeMaps && LLFeatureManager::getInstance()->isFeatureAvailable("RenderObjectBump");
	getChild<LLCheckBoxCtrl>("BumpShiny")->setEnabled(bumpshiny ? TRUE : FALSE);
	
	for (S32 i = 0; i < radio_reflection_detail->getItemCount(); ++i)
	{
		radio_reflection_detail->setIndexEnabled(i, ctrl_reflections->get() && reflections);
	}
	
	// Avatar Mode
	// Enable Avatar Shaders
	LLCheckBoxCtrl* ctrl_avatar_vp = getChild<LLCheckBoxCtrl>("AvatarVertexProgram");
	// Avatar Render Mode
	LLCheckBoxCtrl* ctrl_avatar_cloth = getChild<LLCheckBoxCtrl>("AvatarCloth");

	S32 max_avatar_shader = LLViewerShaderMgr::instance()->mMaxAvatarShaderLevel;
	ctrl_avatar_vp->setEnabled((max_avatar_shader > 0) ? TRUE : FALSE);
	
	if (gSavedSettings.getBOOL("VertexShaderEnable") == FALSE || 
		gSavedSettings.getBOOL("RenderAvatarVP") == FALSE)
	{
		ctrl_avatar_cloth->setEnabled(false);
	} 
	else
	{
		ctrl_avatar_cloth->setEnabled(true);
	}
	
	// Vertex Shaders
	// Global Shader Enable
	LLCheckBoxCtrl* ctrl_shader_enable   = getChild<LLCheckBoxCtrl>("BasicShaders");
	// radio set for terrain detail mode
	LLRadioGroup*   mRadioTerrainDetail = getChild<LLRadioGroup>("TerrainDetailRadio");   // can be linked with control var

	ctrl_shader_enable->setEnabled(LLFeatureManager::getInstance()->isFeatureAvailable("VertexShaderEnable"));
	
	BOOL shaders = ctrl_shader_enable->get();
	if (shaders)
	{
		mRadioTerrainDetail->setValue(1);
		mRadioTerrainDetail->setEnabled(FALSE);
	}
	else
	{
		mRadioTerrainDetail->setEnabled(TRUE);
	}
	
	// WindLight
	LLCheckBoxCtrl* ctrl_wind_light = getChild<LLCheckBoxCtrl>("WindLightUseAtmosShaders");
	
	// *HACK just checks to see if we can use shaders... 
	// maybe some cards that use shaders, but don't support windlight
	ctrl_wind_light->setEnabled(ctrl_shader_enable->getEnabled() && shaders);
	// now turn off any features that are unavailable
	disableUnavailableSettings();
}

void LLFloaterPreference::disableUnavailableSettings()
{	
	LLCheckBoxCtrl* ctrl_reflections   = getChild<LLCheckBoxCtrl>("Reflections");
	LLCheckBoxCtrl* ctrl_avatar_vp     = getChild<LLCheckBoxCtrl>("AvatarVertexProgram");
	LLCheckBoxCtrl* ctrl_avatar_cloth  = getChild<LLCheckBoxCtrl>("AvatarCloth");
	LLCheckBoxCtrl* ctrl_shader_enable = getChild<LLCheckBoxCtrl>("BasicShaders");
	LLCheckBoxCtrl* ctrl_wind_light    = getChild<LLCheckBoxCtrl>("WindLightUseAtmosShaders");
	LLCheckBoxCtrl* ctrl_avatar_impostors = getChild<LLCheckBoxCtrl>("AvatarImpostors");

	// if vertex shaders off, disable all shader related products
	if(!LLFeatureManager::getInstance()->isFeatureAvailable("VertexShaderEnable"))
	{
		ctrl_shader_enable->setEnabled(FALSE);
		ctrl_shader_enable->setValue(FALSE);
		
		ctrl_wind_light->setEnabled(FALSE);
		ctrl_wind_light->setValue(FALSE);
		
		ctrl_reflections->setEnabled(FALSE);
		ctrl_reflections->setValue(FALSE);
		
		ctrl_avatar_vp->setEnabled(FALSE);
		ctrl_avatar_vp->setValue(FALSE);
		
		ctrl_avatar_cloth->setEnabled(FALSE);
		ctrl_avatar_cloth->setValue(FALSE);
	}
	
	// disabled windlight
	if(!LLFeatureManager::getInstance()->isFeatureAvailable("WindLightUseAtmosShaders"))
	{
		ctrl_wind_light->setEnabled(FALSE);
		ctrl_wind_light->setValue(FALSE);
	}
	
	// disabled reflections
	if(!LLFeatureManager::getInstance()->isFeatureAvailable("RenderWaterReflections"))
	{
		ctrl_reflections->setEnabled(FALSE);
		ctrl_reflections->setValue(FALSE);
	}
	
	// disabled av
	if(!LLFeatureManager::getInstance()->isFeatureAvailable("RenderAvatarVP"))
	{
		ctrl_avatar_vp->setEnabled(FALSE);
		ctrl_avatar_vp->setValue(FALSE);
		
		ctrl_avatar_cloth->setEnabled(FALSE);
		ctrl_avatar_cloth->setValue(FALSE);
	}
	// disabled cloth
	if(!LLFeatureManager::getInstance()->isFeatureAvailable("RenderAvatarCloth"))
	{
		ctrl_avatar_cloth->setEnabled(FALSE);
		ctrl_avatar_cloth->setValue(FALSE);
	}
	// disabled impostors
	if(!LLFeatureManager::getInstance()->isFeatureAvailable("RenderUseImpostors"))
	{
		ctrl_avatar_impostors->setEnabled(FALSE);
		ctrl_avatar_impostors->setValue(FALSE);
	}
}

void LLFloaterPreference::onCommitAutoDetectAspect()
{
	BOOL auto_detect = getChild<LLCheckBoxCtrl>("aspect_auto_detect")->get();
	F32 ratio;
	
	if (auto_detect)
	{
		S32 numerator = 0;
		S32 denominator = 0;
		
		// clear any aspect ratio override
		gViewerWindow->mWindow->setNativeAspectRatio(0.f);
		fractionFromDecimal(gViewerWindow->mWindow->getNativeAspectRatio(), numerator, denominator);
		
		std::string aspect;
		if (numerator != 0)
		{
			aspect = llformat("%d:%d", numerator, denominator);
		}
		else
		{
			aspect = llformat("%.3f", gViewerWindow->mWindow->getNativeAspectRatio());
		}
		
		getChild<LLComboBox>( "aspect_ratio")->setLabel(aspect);
		
		ratio = gViewerWindow->mWindow->getNativeAspectRatio();
		gSavedSettings.setF32("FullScreenAspectRatio", ratio);
	}
}

void LLFloaterPreference::refresh()
{
	LLPanel::refresh();

	// sliders and their text boxes
	//	mPostProcess = gSavedSettings.getS32("RenderGlowResolutionPow");
	// slider text boxes
	updateSliderText(getChild<LLSliderCtrl>("ObjectMeshDetail"), getChild<LLTextBox>("ObjectMeshDetailText"));
	updateSliderText(getChild<LLSliderCtrl>("FlexibleMeshDetail"), getChild<LLTextBox>("FlexibleMeshDetailText"));
	updateSliderText(getChild<LLSliderCtrl>("TreeMeshDetail"), getChild<LLTextBox>("TreeMeshDetailText"));
	updateSliderText(getChild<LLSliderCtrl>("AvatarMeshDetail"), getChild<LLTextBox>("AvatarMeshDetailText"));
	updateSliderText(getChild<LLSliderCtrl>("TerrainMeshDetail"), getChild<LLTextBox>("TerrainMeshDetailText"));
	updateSliderText(getChild<LLSliderCtrl>("RenderPostProcess"), getChild<LLTextBox>("PostProcessText"));
	updateSliderText(getChild<LLSliderCtrl>("SkyMeshDetail"), getChild<LLTextBox>("SkyMeshDetailText"));
	
	refreshEnabledState();
}

void LLFloaterPreference::onCommitWindowedMode()
{
	refresh();
}

void LLFloaterPreference::onChangeQuality(const LLSD& data)
{
	U32 level = (U32)(data.asReal());
	LLFeatureManager::getInstance()->setGraphicsLevel(level, true);
	refreshEnabledGraphics();
	refresh();
}

// static
// DEV-24146 -  needs to be removed at a later date. jan-2009
void LLFloaterPreference::cleanupBadSetting()
{
	if (gSavedPerAccountSettings.getString("BusyModeResponse2") == "|TOKEN COPY BusyModeResponse|")
James Cook's avatar
James Cook committed
	{
		llwarns << "cleaning old BusyModeResponse" << llendl;
		gSavedPerAccountSettings.setString("BusyModeResponse2", gSavedPerAccountSettings.getText("BusyModeResponse"));
James Cook's avatar
James Cook committed
	}
void LLFloaterPreference::onClickSetKey()
{
	LLVoiceSetKeyDialog* dialog = new LLVoiceSetKeyDialog(this);
	dialog->startModal();
void LLFloaterPreference::setKey(KEY key)
{
	childSetValue("modifier_combo", LLKeyboard::stringFromKey(key));
}
James Cook's avatar
James Cook committed

void LLFloaterPreference::onClickSetMiddleMouse()
James Cook's avatar
James Cook committed
{
	childSetValue("modifier_combo", "MiddleMouse");
void LLFloaterPreference::onClickSkipDialogs()
{
	LLNotifications::instance().add("SkipShowNextTimeDialogs", LLSD(), LLSD(), boost::bind(&callback_skip_dialogs, _1, _2, this));
}
James Cook's avatar
James Cook committed

void LLFloaterPreference::onClickResetDialogs()
James Cook's avatar
James Cook committed
{
	LLNotifications::instance().add("ResetShowNextTimeDialogs", LLSD(), LLSD(), boost::bind(&callback_reset_dialogs, _1, _2, this));
}

void LLFloaterPreference::onClickEnablePopup()
{	
	LLScrollListCtrl& disabled_popups = getChildRef<LLScrollListCtrl>("disabled_popups");
	
	std::vector<LLScrollListItem*> items = disabled_popups.getAllSelected();
	std::vector<LLScrollListItem*>::iterator itor;
	for (itor = items.begin(); itor != items.end(); ++itor)