llprefsim.cpp 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538
  1. /**
  2. * @file llprefsim.cpp
  3. * @author James Cook, Richard Nelson
  4. * @brief Instant messsage preferences panel
  5. *
  6. * $LicenseInfo:firstyear=2003&license=viewergpl$
  7. *
  8. * Copyright (c) 2003-2009, Linden Research, Inc.
  9. *
  10. * Second Life Viewer Source Code
  11. * The source code in this file ("Source Code") is provided by Linden Lab
  12. * to you under the terms of the GNU General Public License, version 2.0
  13. * ("GPL"), unless you have obtained a separate licensing agreement
  14. * ("Other License"), formally executed by you and Linden Lab. Terms of
  15. * the GPL can be found in doc/GPL-license.txt in this distribution, or
  16. * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
  17. *
  18. * There are special exceptions to the terms and conditions of the GPL as
  19. * it is applied to this Source Code. View the full text of the exception
  20. * in the file doc/FLOSS-exception.txt in this software distribution, or
  21. * online at
  22. * http://secondlifegrid.net/programs/open_source/licensing/flossexception
  23. *
  24. * By copying, modifying or distributing this software, you acknowledge
  25. * that you have read and understood your obligations described above,
  26. * and agree to abide by those obligations.
  27. *
  28. * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
  29. * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
  30. * COMPLETENESS OR PERFORMANCE.
  31. * $/LicenseInfo$
  32. */
  33. #include "llviewerprecompiledheaders.h"
  34. #include "llprefsim.h"
  35. #include "lldir.h"
  36. #include "llcheckboxctrl.h"
  37. #include "hbfileselector.h"
  38. #include "llnotifications.h"
  39. #include "llpanel.h"
  40. #include "lltextbox.h"
  41. #include "lltexteditor.h"
  42. #include "lluictrlfactory.h"
  43. #include "llagent.h"
  44. #include "llgridmanager.h"
  45. #include "llstartup.h"
  46. #include "llviewercontrol.h"
  47. #include "llweb.h"
  48. // Some constants
  49. static const char* const VISIBILITY_DEFAULT = "default";
  50. static const char* const VISIBILITY_HIDDEN = "hidden";
  51. class LLPrefsIMImpl final : public LLPanel
  52. {
  53. public:
  54. LLPrefsIMImpl();
  55. ~LLPrefsIMImpl() override;
  56. bool postBuild() override;
  57. void draw() override;
  58. void apply();
  59. void cancel();
  60. void setPersonalInfo(const std::string& visibility, bool im_via_email,
  61. const std::string& email, S32 verified);
  62. private:
  63. void enableHistory();
  64. void enableBacklog();
  65. static void setLogPathCallback(std::string& dir_name, void* user_data);
  66. static void onClickLogPath(void* user_data);
  67. static void onCommitLogging(LLUICtrl* ctrl, void* user_data);
  68. static void onCommitBacklog(LLUICtrl* ctrl, void* user_data);
  69. static void onClickEmailSettings(void* user_data);
  70. static void onOpenHelp(void* user_data);
  71. private:
  72. LLCheckBoxCtrl* mOnlineVisibilityCheck;
  73. LLCheckBoxCtrl* mSendIMToEmailCheck;
  74. LLTextBox* mEmailSettingsTextBox;
  75. std::string mDirectoryVisibility;
  76. U32 mGroupIMSnoozeDuration;
  77. bool mGotPersonalInfo;
  78. bool mIMViaEmail;
  79. bool mHideOnlineStatus;
  80. static LLPrefsIMImpl* sInstance;
  81. };
  82. LLPrefsIMImpl* LLPrefsIMImpl::sInstance = NULL;
  83. LLPrefsIMImpl::LLPrefsIMImpl()
  84. : LLPanel(std::string("IM Prefs Panel")),
  85. mGotPersonalInfo(false),
  86. mIMViaEmail(false)
  87. {
  88. sInstance = this;
  89. LLUICtrlFactory::getInstance()->buildPanel(this,
  90. "panel_preferences_im.xml");
  91. }
  92. //virtual
  93. LLPrefsIMImpl::~LLPrefsIMImpl()
  94. {
  95. sInstance = NULL;
  96. }
  97. //virtual
  98. bool LLPrefsIMImpl::postBuild()
  99. {
  100. // Help button
  101. childSetAction("busy_response_help", onOpenHelp, this);
  102. // Do not enable the following controls until we get personal data
  103. mOnlineVisibilityCheck = getChild<LLCheckBoxCtrl>("online_visibility");
  104. mOnlineVisibilityCheck->setEnabled(false);
  105. mSendIMToEmailCheck = getChild<LLCheckBoxCtrl>("send_im_to_email");
  106. mSendIMToEmailCheck->setLabelArg("[EMAIL]", getString("log_in_to_change"));
  107. mSendIMToEmailCheck->setEnabled(false);
  108. // Note: support for setting the IM to email redirection with the viewer
  109. // has been removed from SL in November 2021... In SL we replace the check
  110. // box with a text box that, when clicked, opens the corresponding account
  111. // settings web page on SL's site... HB
  112. mEmailSettingsTextBox = getChild<LLTextBox>("email_settings_text");
  113. if (gIsInSecondLife && LLStartUp::isLoggedIn())
  114. {
  115. mEmailSettingsTextBox->setColor(LLTextEditor::getLinksColor());
  116. mEmailSettingsTextBox->setClickedCallback(onClickEmailSettings, this);
  117. mEmailSettingsTextBox->setVisible(true);
  118. mSendIMToEmailCheck->setVisible(false);
  119. }
  120. else
  121. {
  122. mEmailSettingsTextBox->setVisible(false);
  123. mSendIMToEmailCheck->setVisible(true);
  124. }
  125. childDisable("log_instant_messages");
  126. childDisable("log_chat");
  127. childDisable("log_show_history");
  128. childDisable("backlog_size");
  129. childDisable("log_open_in_built_in_browser");
  130. childDisable("log_path_button");
  131. childDisable("busy_response");
  132. childDisable("busy_response_when_away");
  133. childDisable("log_instant_messages_timestamp");
  134. childDisable("log_server_fetch");
  135. childDisable("log_chat_timestamp");
  136. childDisable("log_chat_IM");
  137. childDisable("logfile_name_datestamp");
  138. childDisable("logfile_name_resident");
  139. childSetVisible("logfile_name_resident", gIsInSecondLife);
  140. // Set the other controls flolowing the corresponding settings
  141. childSetText("busy_response", getString("log_in_to_change"));
  142. childSetValue("busy_response_when_away",
  143. gSavedPerAccountSettings.getBool("BusyResponseWhenAway"));
  144. childSetValue("include_im_in_chat_console",
  145. gSavedSettings.getBool("IMInChatConsole"));
  146. childSetValue("show_timestamps_check",
  147. gSavedSettings.getBool("IMShowTimestamps"));
  148. childSetValue("open_on_incoming_check",
  149. gSavedSettings.getBool("IMOpenSessionOnIncoming"));
  150. childSetText("log_path_string",
  151. gSavedPerAccountSettings.getString("InstantMessageLogPath"));
  152. childSetValue("log_instant_messages",
  153. gSavedPerAccountSettings.getBool("LogInstantMessages"));
  154. childSetValue("log_chat",
  155. gSavedPerAccountSettings.getBool("LogChat"));
  156. childSetValue("log_show_history",
  157. gSavedPerAccountSettings.getBool("LogShowHistory"));
  158. childSetValue("backlog_size",
  159. (S32)gSavedPerAccountSettings.getU32("LogShowHistoryMaxSize"));
  160. childSetValue("log_open_in_built_in_browser",
  161. gSavedPerAccountSettings.getBool("OpenIMLogsInBuiltInBrowser"));
  162. childSetValue("log_instant_messages_timestamp",
  163. gSavedPerAccountSettings.getBool("IMLogTimestamp"));
  164. childSetValue("log_server_fetch",
  165. gSavedPerAccountSettings.getBool("FetchGroupChatHistory"));
  166. childSetValue("log_chat_timestamp",
  167. gSavedPerAccountSettings.getBool("LogChatTimestamp"));
  168. childSetValue("log_chat_IM",
  169. gSavedPerAccountSettings.getBool("LogChatIM"));
  170. childSetValue("log_date_timestamp",
  171. gSavedSettings.getBool("LogTimestampDate"));
  172. childSetValue("log_seconds_timestamp",
  173. gSavedSettings.getBool("LogTimestampSeconds"));
  174. childSetValue("logfile_name_datestamp",
  175. gSavedPerAccountSettings.getBool("LogFileNamewithDate"));
  176. childSetValue("logfile_name_resident",
  177. gSavedPerAccountSettings.getBool("LogFileNameWithoutResident"));
  178. childSetAction("log_path_button", onClickLogPath, this);
  179. childSetCommitCallback("log_chat", onCommitLogging, this);
  180. childSetCommitCallback("log_instant_messages", onCommitLogging, this);
  181. childSetCommitCallback("log_show_history", onCommitBacklog, this);
  182. mGroupIMSnoozeDuration = gSavedSettings.getU32("GroupIMSnoozeDuration");
  183. return true;
  184. }
  185. //virtual
  186. void LLPrefsIMImpl::draw()
  187. {
  188. static bool was_selector_in_use = false;
  189. bool is_selector_in_use = HBFileSelector::isInUse();
  190. if (is_selector_in_use != was_selector_in_use)
  191. {
  192. was_selector_in_use = is_selector_in_use;
  193. childSetEnabled("log_path_button", !is_selector_in_use);
  194. }
  195. LLPanel::draw();
  196. }
  197. void LLPrefsIMImpl::enableHistory()
  198. {
  199. bool log_ims = childGetValue("log_instant_messages").asBoolean();
  200. bool log_chat = childGetValue("log_chat").asBoolean();
  201. childSetEnabled("log_path_button", log_ims || log_chat);
  202. childSetEnabled("log_show_history", log_ims);
  203. enableBacklog();
  204. }
  205. void LLPrefsIMImpl::enableBacklog()
  206. {
  207. bool enable = childGetValue("log_instant_messages").asBoolean() &&
  208. childGetValue("log_show_history").asBoolean();
  209. childSetEnabled("backlog_size", enable);
  210. childSetEnabled("log_open_in_built_in_browser", enable);
  211. enable = childGetValue("log_show_history").asBoolean() &&
  212. gAgent.hasRegionCapability("ChatSessionRequest");
  213. childSetEnabled("log_server_fetch", enable);
  214. }
  215. void LLPrefsIMImpl::cancel()
  216. {
  217. gSavedSettings.setU32("GroupIMSnoozeDuration", mGroupIMSnoozeDuration);
  218. }
  219. void LLPrefsIMImpl::apply()
  220. {
  221. LLTextEditor* busy = getChild<LLTextEditor>("busy_response");
  222. LLWString busy_response;
  223. if (busy)
  224. {
  225. busy_response = busy->getWText();
  226. }
  227. LLWStringUtil::replaceTabsWithSpaces(busy_response, 4);
  228. LLWStringUtil::replaceChar(busy_response, '\n', '^');
  229. LLWStringUtil::replaceChar(busy_response, ' ', '%');
  230. // Needed since cancel() is called on panel closing !
  231. mGroupIMSnoozeDuration = gSavedSettings.getU32("GroupIMSnoozeDuration");
  232. if (mGotPersonalInfo)
  233. {
  234. gSavedPerAccountSettings.setString("BusyModeResponse",
  235. wstring_to_utf8str(busy_response));
  236. gSavedPerAccountSettings.setBool("BusyResponseWhenAway",
  237. childGetValue("busy_response_when_away").asBoolean());
  238. gSavedSettings.setBool("IMInChatConsole",
  239. childGetValue("include_im_in_chat_console").asBoolean());
  240. gSavedSettings.setBool("IMShowTimestamps",
  241. childGetValue("show_timestamps_check").asBoolean());
  242. gSavedSettings.setBool("IMOpenSessionOnIncoming",
  243. childGetValue("open_on_incoming_check").asBoolean());
  244. gSavedPerAccountSettings.setString("InstantMessageLogPath",
  245. childGetText("log_path_string"));
  246. gSavedPerAccountSettings.setBool("LogInstantMessages",
  247. childGetValue("log_instant_messages").asBoolean());
  248. gSavedPerAccountSettings.setBool("LogChat",
  249. childGetValue("log_chat").asBoolean());
  250. gSavedPerAccountSettings.setBool("LogShowHistory",
  251. childGetValue("log_show_history").asBoolean());
  252. gSavedPerAccountSettings.setU32("LogShowHistoryMaxSize",
  253. childGetValue("backlog_size").asInteger());
  254. gSavedPerAccountSettings.setBool("OpenIMLogsInBuiltInBrowser",
  255. childGetValue("log_open_in_built_in_browser").asInteger());
  256. gSavedPerAccountSettings.setBool("IMLogTimestamp",
  257. childGetValue("log_instant_messages_timestamp").asBoolean());
  258. gSavedPerAccountSettings.setBool("FetchGroupChatHistory",
  259. childGetValue("log_server_fetch").asBoolean());
  260. gSavedPerAccountSettings.setBool("LogChatTimestamp",
  261. childGetValue("log_chat_timestamp").asBoolean());
  262. gSavedPerAccountSettings.setBool("LogChatIM",
  263. childGetValue("log_chat_IM").asBoolean());
  264. gSavedSettings.setBool("LogTimestampDate",
  265. childGetValue("log_date_timestamp").asBoolean());
  266. gSavedSettings.setBool("LogTimestampSeconds",
  267. childGetValue("log_seconds_timestamp").asBoolean());
  268. gSavedPerAccountSettings.setBool("LogFileNamewithDate",
  269. childGetValue("logfile_name_datestamp").asBoolean());
  270. gSavedPerAccountSettings.setBool("LogFileNameWithoutResident", childGetValue("logfile_name_resident").asBoolean());
  271. gDirUtil.setChatLogsDir(gSavedPerAccountSettings.getString("InstantMessageLogPath"));
  272. gDirUtil.setPerAccountChatLogsDir(LLGridManager::getInstance()->getGridLabel(),
  273. gLoginFirstName, gLoginLastName);
  274. LLFile::mkdir(gDirUtil.getPerAccountChatLogsDir());
  275. bool new_im_via_email = mSendIMToEmailCheck->get();
  276. bool new_hide_online = mOnlineVisibilityCheck->get();
  277. if (new_im_via_email != mIMViaEmail ||
  278. new_hide_online != mHideOnlineStatus)
  279. {
  280. // This hack is because we are representing several different
  281. // possible strings with a single checkbox. Since most users
  282. // can only select between 2 values, we represent it as a
  283. // checkbox. This breaks down a little bit for liaisons, but
  284. // works out in the end.
  285. if (new_hide_online != mHideOnlineStatus)
  286. {
  287. if (new_hide_online)
  288. {
  289. mDirectoryVisibility = VISIBILITY_HIDDEN;
  290. }
  291. else
  292. {
  293. mDirectoryVisibility = VISIBILITY_DEFAULT;
  294. }
  295. // Update showonline value, otherwise multiple applies won't
  296. // work
  297. mHideOnlineStatus = new_hide_online;
  298. }
  299. gAgent.sendAgentUpdateUserInfo(new_im_via_email,
  300. mDirectoryVisibility);
  301. }
  302. }
  303. }
  304. void LLPrefsIMImpl::setPersonalInfo(const std::string& visibility,
  305. bool im_via_email,
  306. const std::string& email, S32 verified)
  307. {
  308. mGotPersonalInfo = true;
  309. mIMViaEmail = im_via_email;
  310. mDirectoryVisibility = visibility;
  311. if (visibility == VISIBILITY_DEFAULT)
  312. {
  313. mHideOnlineStatus = false;
  314. mOnlineVisibilityCheck->setEnabled(true);
  315. }
  316. else if (visibility == VISIBILITY_HIDDEN)
  317. {
  318. mHideOnlineStatus = true;
  319. mOnlineVisibilityCheck->setEnabled(true);
  320. }
  321. else
  322. {
  323. mHideOnlineStatus = true;
  324. }
  325. std::string email_status;
  326. switch (verified)
  327. {
  328. case 0:
  329. email_status = getString("unverified");
  330. break;
  331. case 1:
  332. email_status = getString("verified");
  333. break;
  334. default:
  335. email_status = getString("unknown");
  336. }
  337. mSendIMToEmailCheck->setEnabled(verified);
  338. mSendIMToEmailCheck->set(im_via_email);
  339. mSendIMToEmailCheck->setToolTip(email_status);
  340. mEmailSettingsTextBox->setToolTip(email_status);
  341. mOnlineVisibilityCheck->set(mHideOnlineStatus);
  342. mOnlineVisibilityCheck->setLabelArg("[DIR_VIS]", mDirectoryVisibility);
  343. childEnable("log_instant_messages");
  344. childEnable("log_chat");
  345. childEnable("busy_response");
  346. childEnable("busy_response_when_away");
  347. childEnable("log_instant_messages_timestamp");
  348. if (gAgent.hasRegionCapability("ChatSessionRequest"))
  349. {
  350. childEnable("log_server_fetch");
  351. }
  352. childEnable("log_chat_timestamp");
  353. childEnable("log_chat_IM");
  354. childEnable("logfile_name_datestamp");
  355. childEnable("logfile_name_resident");
  356. // RN: get wide string so replace char can work (requires fixed-width
  357. // encoding).
  358. LLWString busy_response =
  359. utf8str_to_wstring(gSavedPerAccountSettings.getString("BusyModeResponse"));
  360. LLWStringUtil::replaceChar(busy_response, '^', '\n');
  361. LLWStringUtil::replaceChar(busy_response, '%', ' ');
  362. childSetText("busy_response", wstring_to_utf8str(busy_response));
  363. enableHistory();
  364. enableBacklog();
  365. std::string display_email(email);
  366. if (display_email.empty())
  367. {
  368. display_email = getString("unset");
  369. }
  370. // Truncate the e-mail address if it is too long (to prevent going off
  371. // the edge of the dialog).
  372. else if (display_email.size() > 30)
  373. {
  374. display_email.resize(30);
  375. display_email += "...";
  376. }
  377. mSendIMToEmailCheck->setLabelArg("[EMAIL]", display_email);
  378. mSendIMToEmailCheck->setToolTipArg("[EMAIL]", display_email);
  379. mEmailSettingsTextBox->setToolTipArg("[EMAIL]", display_email);
  380. }
  381. // static
  382. void LLPrefsIMImpl::setLogPathCallback(std::string& dir_name, void* user_data)
  383. {
  384. LLPrefsIMImpl* self = (LLPrefsIMImpl*)user_data;
  385. if (!self || self != sInstance)
  386. {
  387. gNotifications.add("PreferencesClosed");
  388. return;
  389. }
  390. if (!dir_name.empty())
  391. {
  392. self->childSetText("log_path_string", dir_name);
  393. }
  394. }
  395. // static
  396. void LLPrefsIMImpl::onClickLogPath(void* user_data)
  397. {
  398. LLPrefsIMImpl* self = (LLPrefsIMImpl*)user_data;
  399. if (self)
  400. {
  401. std::string suggestion = self->childGetText("log_path_string");
  402. HBFileSelector::pickDirectory(suggestion, setLogPathCallback, self);
  403. }
  404. }
  405. // static
  406. void LLPrefsIMImpl::onCommitLogging(LLUICtrl* ctrl, void* user_data)
  407. {
  408. LLPrefsIMImpl* self=(LLPrefsIMImpl*)user_data;
  409. if (self)
  410. {
  411. self->enableHistory();
  412. }
  413. }
  414. // static
  415. void LLPrefsIMImpl::onCommitBacklog(LLUICtrl* ctrl, void* user_data)
  416. {
  417. LLPrefsIMImpl* self= (LLPrefsIMImpl*)user_data;
  418. if (self)
  419. {
  420. self->enableBacklog();
  421. }
  422. }
  423. void LLPrefsIMImpl::onClickEmailSettings(void* user_data)
  424. {
  425. LLPrefsIMImpl* self = (LLPrefsIMImpl*)user_data;
  426. if (self)
  427. {
  428. LLWeb::loadURL(self->getString("sl_email_url"));
  429. }
  430. }
  431. void LLPrefsIMImpl::onOpenHelp(void* user_data)
  432. {
  433. LLPrefsIMImpl* self = (LLPrefsIMImpl*)user_data;
  434. if (self)
  435. {
  436. LLSD args;
  437. args["MESSAGE"] = self->getString("help_text");
  438. gNotifications.add("GenericAlert", args);
  439. }
  440. }
  441. //---------------------------------------------------------------------------
  442. LLPrefsIM::LLPrefsIM()
  443. : impl(* new LLPrefsIMImpl())
  444. {
  445. }
  446. LLPrefsIM::~LLPrefsIM()
  447. {
  448. delete &impl;
  449. }
  450. void LLPrefsIM::apply()
  451. {
  452. impl.apply();
  453. }
  454. void LLPrefsIM::cancel()
  455. {
  456. impl.cancel();
  457. }
  458. void LLPrefsIM::setPersonalInfo(const std::string& visibility,
  459. bool im_via_email, const std::string& email,
  460. S32 verified)
  461. {
  462. impl.setPersonalInfo(visibility, im_via_email, email, verified);
  463. }
  464. LLPanel* LLPrefsIM::getPanel()
  465. {
  466. return &impl;
  467. }