/** * @file llfloaterpreference.cpp * @brief Global preferences with and without persistence. * * $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$ */ /* * 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 "llbutton.h" #include "llcheckboxctrl.h" #include "lldir.h" #include "llfocusmgr.h" #include "llscrollbar.h" #include "llspinctrl.h" #include "message.h" #include "impprefsfonts.h" #include "llcommandhandler.h" #include "llfloaterpreference.h" #include "llpanelnetwork.h" #include "llpanelaudioprefs.h" #include "llpaneldisplay.h" #include "llpaneldebug.h" #include "llpanelgeneral.h" #include "llpanelinput.h" #include "llpanellogin.h" #include "llpanelLCD.h" #include "llpanelmsgs.h" #include "llpanelskins.h" #include "llprefsadvanced.h" #include "llprefschat.h" #include "llprefscolors.h" #include "llprefsvoice.h" #include "llprefsim.h" #include "llresizehandle.h" #include "llresmgr.h" #include "llassetstorage.h" #include "llagent.h" #include "llviewercontrol.h" #include "llviewernetwork.h" #include "lluictrlfactory.h" #include "llviewerwindow.h" #include "llkeyboard.h" #include "llscrollcontainer.h" #include "llfloaterhardwaresettings.h" const S32 PREF_BORDER = 4; const S32 PREF_PAD = 5; const S32 PREF_BUTTON_WIDTH = 70; const S32 PREF_CATEGORY_WIDTH = 150; const S32 PREF_FLOATER_MIN_HEIGHT = 2 * SCROLLBAR_SIZE + 2 * LLPANEL_BORDER_WIDTH + 96; LLFloaterPreference* LLFloaterPreference::sInstance = NULL; class LLPreferencesHandler : public LLCommandHandler { public: // requires trusted browser LLPreferencesHandler() : LLCommandHandler("preferences", true) { } bool handle(const LLSD& tokens, const LLSD& query_map, LLMediaCtrl* web) { LLFloaterPreference::show(NULL); return true; } }; LLPreferencesHandler gPreferencesHandler; // Must be done at run time, not compile time. JC S32 pref_min_width() { return 2 * PREF_BORDER + 2 * PREF_BUTTON_WIDTH + PREF_PAD + RESIZE_HANDLE_WIDTH + PREF_CATEGORY_WIDTH + PREF_PAD; } S32 pref_min_height() { return 2 * PREF_BORDER + 3*(BTN_HEIGHT + PREF_PAD) + PREF_FLOATER_MIN_HEIGHT; } LLPreferenceCore::LLPreferenceCore(LLTabContainer* tab_container, LLButton * default_btn) : mTabContainer(tab_container), mGeneralPanel(NULL), mInputPanel(NULL), mNetworkPanel(NULL), mDisplayPanel(NULL), mAudioPanel(NULL), mMsgPanel(NULL), mSkinsPanel(NULL), mPrefsColors(NULL), mLCDPanel(NULL), mPrefsFonts(NULL), mPrefsAdvanced(NULL) { mGeneralPanel = new LLPanelGeneral(); mTabContainer->addTabPanel(mGeneralPanel, mGeneralPanel->getLabel(), FALSE, onTabChanged, mTabContainer); mGeneralPanel->setDefaultBtn(default_btn); mInputPanel = new LLPanelInput(); mTabContainer->addTabPanel(mInputPanel, mInputPanel->getLabel(), FALSE, onTabChanged, mTabContainer); mInputPanel->setDefaultBtn(default_btn); mNetworkPanel = new LLPanelNetwork(); mTabContainer->addTabPanel(mNetworkPanel, mNetworkPanel->getLabel(), FALSE, onTabChanged, mTabContainer); mNetworkPanel->setDefaultBtn(default_btn); mDisplayPanel = new LLPanelDisplay(); mTabContainer->addTabPanel(mDisplayPanel, mDisplayPanel->getLabel(), FALSE, onTabChanged, mTabContainer); mDisplayPanel->setDefaultBtn(default_btn); mAudioPanel = new LLPanelAudioPrefs(); mTabContainer->addTabPanel(mAudioPanel, mAudioPanel->getLabel(), FALSE, onTabChanged, mTabContainer); mAudioPanel->setDefaultBtn(default_btn); mPrefsChat = new LLPrefsChat(); mTabContainer->addTabPanel(mPrefsChat->getPanel(), mPrefsChat->getPanel()->getLabel(), FALSE, onTabChanged, mTabContainer); mPrefsChat->getPanel()->setDefaultBtn(default_btn); mPrefsIM = new LLPrefsIM(); mTabContainer->addTabPanel(mPrefsIM->getPanel(), mPrefsIM->getPanel()->getLabel(), FALSE, onTabChanged, mTabContainer); mPrefsIM->getPanel()->setDefaultBtn(default_btn); mPrefsVoice = new LLPrefsVoice(); mTabContainer->addTabPanel(mPrefsVoice, mPrefsVoice->getLabel(), FALSE, onTabChanged, mTabContainer); mPrefsVoice->setDefaultBtn(default_btn); #if LL_LCD_COMPILE // only add this option if we actually have a logitech keyboard / speaker set if (gLcdScreen->Enabled()) { mLCDPanel = new LLPanelLCD(); mTabContainer->addTabPanel(mLCDPanel, mLCDPanel->getLabel(), FALSE, onTabChanged, mTabContainer); mLCDPanel->setDefaultBtn(default_btn); } #else mLCDPanel = NULL; #endif mMsgPanel = new LLPanelMsgs(); mTabContainer->addTabPanel(mMsgPanel, mMsgPanel->getLabel(), FALSE, onTabChanged, mTabContainer); mMsgPanel->setDefaultBtn(default_btn); mPrefsColors = new LLPrefsColors(); mTabContainer->addTabPanel(mPrefsColors, mPrefsColors->getLabel(), FALSE, onTabChanged, mTabContainer); mPrefsColors->setDefaultBtn(default_btn); mSkinsPanel = new LLPanelSkins(); mTabContainer->addTabPanel(mSkinsPanel, mSkinsPanel->getLabel(), FALSE, onTabChanged, mTabContainer); mSkinsPanel->setDefaultBtn(default_btn); mPrefsFonts = new ImpPrefsFonts(); mTabContainer->addTabPanel(mPrefsFonts, mPrefsFonts->getLabel(), FALSE, onTabChanged, mTabContainer); mPrefsFonts->setDefaultBtn(default_btn); mPrefsAdvanced = new LLPrefsAdvanced(); mTabContainer->addTabPanel(mPrefsAdvanced, mPrefsAdvanced->getLabel(), FALSE, onTabChanged, mTabContainer); mPrefsAdvanced->setDefaultBtn(default_btn); if (!mTabContainer->selectTab(gSavedSettings.getS32("LastPrefTab"))) { mTabContainer->selectFirstTab(); } } LLPreferenceCore::~LLPreferenceCore() { if (mGeneralPanel) { delete mGeneralPanel; mGeneralPanel = NULL; } if (mInputPanel) { delete mInputPanel; mInputPanel = NULL; } if (mNetworkPanel) { delete mNetworkPanel; mNetworkPanel = NULL; } if (mDisplayPanel) { delete mDisplayPanel; mDisplayPanel = NULL; } if (mAudioPanel) { delete mAudioPanel; mAudioPanel = NULL; } if (mPrefsChat) { delete mPrefsChat; mPrefsChat = NULL; } if (mPrefsIM) { delete mPrefsIM; mPrefsIM = NULL; } if (mMsgPanel) { delete mMsgPanel; mMsgPanel = NULL; } if (mSkinsPanel) { delete mSkinsPanel; mSkinsPanel = NULL; } if (mPrefsAdvanced) { delete mPrefsAdvanced; mPrefsAdvanced = NULL; } if (mPrefsFonts) { delete mPrefsFonts; mPrefsFonts = NULL; } if (mPrefsColors) { delete mPrefsColors; mPrefsColors = NULL; } } void LLPreferenceCore::apply() { mGeneralPanel->apply(); mInputPanel->apply(); mNetworkPanel->apply(); mDisplayPanel->apply(); mAudioPanel->apply(); mPrefsChat->apply(); mPrefsVoice->apply(); mPrefsIM->apply(); mMsgPanel->apply(); mSkinsPanel->apply(); mPrefsAdvanced->apply(); mPrefsFonts->apply(); mPrefsColors->apply(); // hardware menu apply LLFloaterHardwareSettings::instance()->apply(); #if LL_LCD_COMPILE // only add this option if we actually have a logitech keyboard / speaker set if (gLcdScreen->Enabled()) { mLCDPanel->apply(); } #endif // Sims always wants us to send IMViaEMail and DirectoryVisible in the same msg or we crash, they're evil like that // We only know both these values after mPrefsChat and mPrefsIM have been applied -- MC if (mPrefsChat->getUpdateUserInfo() || mPrefsIM->getUpdateUserInfo()) { bool new_im_via_email = mPrefsChat->getIMViaEmail(); std::string directory_visibility = mPrefsIM->getDirectoryVis(); LLMessageSystem* msg = gMessageSystem; msg->newMessageFast(_PREHASH_UpdateUserInfo); msg->nextBlockFast(_PREHASH_AgentData); msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); msg->nextBlockFast(_PREHASH_UserData); msg->addBOOLFast(_PREHASH_IMViaEMail, new_im_via_email); msg->addString("DirectoryVisibility", directory_visibility); gAgent.sendReliableMessage(); } } void LLPreferenceCore::cancel() { mGeneralPanel->cancel(); mInputPanel->cancel(); mNetworkPanel->cancel(); mDisplayPanel->cancel(); mAudioPanel->cancel(); mPrefsChat->cancel(); mPrefsVoice->cancel(); mPrefsIM->cancel(); mMsgPanel->cancel(); mSkinsPanel->cancel(); mPrefsAdvanced->cancel(); mPrefsFonts->cancel(); mPrefsColors->cancel(); // cancel hardware menu LLFloaterHardwareSettings::instance()->cancel(); #if LL_LCD_COMPILE // only add this option if we actually have a logitech keyboard / speaker set if (gLcdScreen->Enabled()) { mLCDPanel->cancel(); } #endif } // static void LLPreferenceCore::onTabChanged(void* user_data, bool from_click) { LLTabContainer* self = (LLTabContainer*)user_data; gSavedSettings.setS32("LastPrefTab", self->getCurrentPanelIndex()); } void LLPreferenceCore::setPersonalInfo(const std::string& visibility, bool im_via_email, const std::string& email) { mPrefsIM->setPersonalInfo(visibility); mPrefsChat->setPersonalInfo(im_via_email, email); } void LLPreferenceCore::updateIsLoggedIn(bool enable) { mPrefsIM->preparePerAccountPrefs(enable); mAudioPanel->updateIsLoggedIn(enable); } void LLPreferenceCore::refreshEnabledGraphics() { LLFloaterHardwareSettings::instance()->refreshEnabledState(); mDisplayPanel->refreshEnabledState(); } ////////////////////////////////////////////// // LLFloaterPreference LLFloaterPreference::LLFloaterPreference() { LLUICtrlFactory::getInstance()->buildFloater(this, "floater_preferences.xml"); } BOOL LLFloaterPreference::postBuild() { requires("OK"); requires("Cancel"); requires("Apply"); requires("pref core"); if (!checkRequirements()) { return FALSE; } mApplyBtn = getChild("Apply"); mApplyBtn->setClickedCallback(onBtnApply, this); mCancelBtn = getChild("Cancel"); mCancelBtn->setClickedCallback(onBtnCancel, this); mOKBtn = getChild("OK"); mOKBtn->setClickedCallback(onBtnOK, this); childSetAction("reset_btn", onClickResetPrefs, this); mPreferenceCore = new LLPreferenceCore( getChild("pref core"), getChild("OK") ); sInstance = this; return TRUE; } LLFloaterPreference::~LLFloaterPreference() { sInstance = NULL; delete mPreferenceCore; } void LLFloaterPreference::apply() { this->mPreferenceCore->apply(); } void LLFloaterPreference::cancel() { this->mPreferenceCore->cancel(); } // static void LLFloaterPreference::show(void*) { if (!sInstance) { new LLFloaterPreference(); sInstance->center(); } sInstance->open(); /* Flawfinder: ignore */ if(!gAgent.getID().isNull()) { // we're logged in, so we can get this info. gMessageSystem->newMessageFast(_PREHASH_UserInfoRequest); gMessageSystem->nextBlockFast(_PREHASH_AgentData); gMessageSystem->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); gMessageSystem->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); gAgent.sendReliableMessage(); } LLPanelLogin::setAlwaysRefresh(true); } // static void LLFloaterPreference::onClickResetPrefs(void* user_data) { LLFloaterPreference* self = (LLFloaterPreference*)user_data; LLNotifications::instance().add("ConfirmResetAllPreferences", LLSD(), LLSD(), boost::bind(callbackReset, _1, _2, self)); } // static bool LLFloaterPreference::callbackReset(const LLSD& notification, const LLSD& response, LLFloaterPreference *self) { S32 option = LLNotification::getSelectedOption(notification, response); if ( option == 0 ) { gSavedSettings.setBOOL("ResetAllPreferences", TRUE); } return false; } // static void LLFloaterPreference::onBtnOK( void* userdata ) { LLFloaterPreference *fp =(LLFloaterPreference *)userdata; if (fp) { // commit any outstanding text entry if (fp->hasFocus()) { LLUICtrl* cur_focus = dynamic_cast(gFocusMgr.getKeyboardFocus()); if (cur_focus->acceptsTextInput()) { cur_focus->onCommit(); } } if (fp->canClose()) { fp->apply(); fp->close(false); gSavedSettings.saveToFile( gSavedSettings.getString("ClientSettingsFile"), TRUE ); 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); } else { // Show beep, pop up dialog, etc. llinfos << "Can't close preferences!" << llendl; } LLPanelLogin::refreshLocation( false ); } } // static void LLFloaterPreference::onBtnApply( void* userdata ) { LLFloaterPreference *fp =(LLFloaterPreference *)userdata; if (fp) { if (fp->hasFocus()) { LLUICtrl* cur_focus = dynamic_cast(gFocusMgr.getKeyboardFocus()); if (cur_focus->acceptsTextInput()) { cur_focus->onCommit(); } } fp->apply(); LLPanelLogin::refreshLocation( false ); } } void LLFloaterPreference::onClose(bool app_quitting) { LLPanelLogin::setAlwaysRefresh(false); cancel(); // will be a no-op if OK or apply was performed just prior. LLFloater::onClose(app_quitting); } // static void LLFloaterPreference::onBtnCancel( void* userdata ) { LLFloaterPreference *fp =(LLFloaterPreference *)userdata; if (fp) { if (fp->hasFocus()) { LLUICtrl* cur_focus = dynamic_cast(gFocusMgr.getKeyboardFocus()); if (cur_focus->acceptsTextInput()) { cur_focus->onCommit(); } } fp->close(); // side effect will also cancel any unsaved changes. } } // static void LLFloaterPreference::updateUserInfo(const std::string& visibility, bool im_via_email, const std::string& email) { if(sInstance && sInstance->mPreferenceCore) { sInstance->mPreferenceCore->setPersonalInfo(visibility, im_via_email, email); } } // static void LLFloaterPreference::updateIsLoggedIn(bool enable) { if(sInstance && sInstance->mPreferenceCore) { sInstance->mPreferenceCore->updateIsLoggedIn(enable); } } void LLFloaterPreference::refreshEnabledGraphics() { sInstance->mPreferenceCore->refreshEnabledGraphics(); }