/indra/newview/llfloaterabout.cpp

https://bitbucket.org/lindenlab/viewer-beta/ · C++ · 502 lines · 363 code · 62 blank · 77 comment · 24 complexity · 9b4cacada8d2ab20ebf62c63fdc371be MD5 · raw file

  1. /**
  2. * @file llfloaterabout.cpp
  3. * @author James Cook
  4. * @brief The about box from Help->About
  5. *
  6. * $LicenseInfo:firstyear=2001&license=viewerlgpl$
  7. * Second Life Viewer Source Code
  8. * Copyright (C) 2010, Linden Research, Inc.
  9. *
  10. * This library is free software; you can redistribute it and/or
  11. * modify it under the terms of the GNU Lesser General Public
  12. * License as published by the Free Software Foundation;
  13. * version 2.1 of the License only.
  14. *
  15. * This library is distributed in the hope that it will be useful,
  16. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  17. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  18. * Lesser General Public License for more details.
  19. *
  20. * You should have received a copy of the GNU Lesser General Public
  21. * License along with this library; if not, write to the Free Software
  22. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  23. *
  24. * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
  25. * $/LicenseInfo$
  26. */
  27. #include "llviewerprecompiledheaders.h"
  28. #include <iostream>
  29. #include <fstream>
  30. #include "llfloaterabout.h"
  31. // Viewer includes
  32. #include "llagent.h"
  33. #include "llappviewer.h"
  34. #include "llsecondlifeurls.h"
  35. #include "llvoiceclient.h"
  36. #include "lluictrlfactory.h"
  37. #include "llviewertexteditor.h"
  38. #include "llviewercontrol.h"
  39. #include "llviewerstats.h"
  40. #include "llviewerregion.h"
  41. #include "llversioninfo.h"
  42. #include "llweb.h"
  43. // Linden library includes
  44. #include "llaudioengine.h"
  45. #include "llbutton.h"
  46. #include "llcurl.h"
  47. #include "llglheaders.h"
  48. #include "llfloater.h"
  49. #include "llfloaterreg.h"
  50. #include "llimagej2c.h"
  51. #include "llsys.h"
  52. #include "lltrans.h"
  53. #include "lluri.h"
  54. #include "v3dmath.h"
  55. #include "llwindow.h"
  56. #include "stringize.h"
  57. #include "llsdutil_math.h"
  58. #include "lleventapi.h"
  59. #if LL_WINDOWS
  60. #include "lldxhardware.h"
  61. #endif
  62. extern LLMemoryInfo gSysMemory;
  63. extern U32 gPacketsIn;
  64. static std::string get_viewer_release_notes_url();
  65. ///----------------------------------------------------------------------------
  66. /// Class LLServerReleaseNotesURLFetcher
  67. ///----------------------------------------------------------------------------
  68. class LLServerReleaseNotesURLFetcher : public LLHTTPClient::Responder
  69. {
  70. LOG_CLASS(LLServerReleaseNotesURLFetcher);
  71. public:
  72. static void startFetch();
  73. /*virtual*/ void completedHeader(U32 status, const std::string& reason, const LLSD& content);
  74. /*virtual*/ void completedRaw(
  75. U32 status,
  76. const std::string& reason,
  77. const LLChannelDescriptors& channels,
  78. const LLIOPipe::buffer_ptr_t& buffer);
  79. };
  80. ///----------------------------------------------------------------------------
  81. /// Class LLFloaterAbout
  82. ///----------------------------------------------------------------------------
  83. class LLFloaterAbout
  84. : public LLFloater
  85. {
  86. friend class LLFloaterReg;
  87. private:
  88. LLFloaterAbout(const LLSD& key);
  89. virtual ~LLFloaterAbout();
  90. public:
  91. /*virtual*/ BOOL postBuild();
  92. /// Obtain the data used to fill out the contents string. This is
  93. /// separated so that we can programmatically access the same info.
  94. static LLSD getInfo();
  95. void onClickCopyToClipboard();
  96. void updateServerReleaseNotesURL(const std::string& url);
  97. private:
  98. void setSupportText(const std::string& server_release_notes_url);
  99. };
  100. // Default constructor
  101. LLFloaterAbout::LLFloaterAbout(const LLSD& key)
  102. : LLFloater(key)
  103. {
  104. }
  105. // Destroys the object
  106. LLFloaterAbout::~LLFloaterAbout()
  107. {
  108. }
  109. BOOL LLFloaterAbout::postBuild()
  110. {
  111. center();
  112. LLViewerTextEditor *support_widget =
  113. getChild<LLViewerTextEditor>("support_editor", true);
  114. LLViewerTextEditor *linden_names_widget =
  115. getChild<LLViewerTextEditor>("linden_names", true);
  116. LLViewerTextEditor *contrib_names_widget =
  117. getChild<LLViewerTextEditor>("contrib_names", true);
  118. LLViewerTextEditor *trans_names_widget =
  119. getChild<LLViewerTextEditor>("trans_names", true);
  120. getChild<LLUICtrl>("copy_btn")->setCommitCallback(
  121. boost::bind(&LLFloaterAbout::onClickCopyToClipboard, this));
  122. if (gAgent.getRegion())
  123. {
  124. // start fetching server release notes URL
  125. setSupportText(LLTrans::getString("RetrievingData"));
  126. LLServerReleaseNotesURLFetcher::startFetch();
  127. }
  128. else // not logged in
  129. {
  130. setSupportText(LLStringUtil::null);
  131. }
  132. support_widget->blockUndo();
  133. // Fix views
  134. support_widget->setEnabled(FALSE);
  135. support_widget->startOfDoc();
  136. // Get the names of Lindens, added by viewer_manifest.py at build time
  137. std::string lindens_path = gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS,"lindens.txt");
  138. llifstream linden_file;
  139. std::string lindens;
  140. linden_file.open(lindens_path); /* Flawfinder: ignore */
  141. if (linden_file.is_open())
  142. {
  143. std::getline(linden_file, lindens); // all names are on a single line
  144. linden_file.close();
  145. linden_names_widget->setText(lindens);
  146. }
  147. else
  148. {
  149. LL_INFOS("AboutInit") << "Could not read lindens file at " << lindens_path << LL_ENDL;
  150. }
  151. linden_names_widget->setEnabled(FALSE);
  152. linden_names_widget->startOfDoc();
  153. // Get the names of contributors, extracted from .../doc/contributions.txt by viewer_manifest.py at build time
  154. std::string contributors_path = gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS,"contributors.txt");
  155. llifstream contrib_file;
  156. std::string contributors;
  157. contrib_file.open(contributors_path); /* Flawfinder: ignore */
  158. if (contrib_file.is_open())
  159. {
  160. std::getline(contrib_file, contributors); // all names are on a single line
  161. contrib_file.close();
  162. }
  163. else
  164. {
  165. LL_WARNS("AboutInit") << "Could not read contributors file at " << contributors_path << LL_ENDL;
  166. }
  167. contrib_names_widget->setText(contributors);
  168. contrib_names_widget->setEnabled(FALSE);
  169. contrib_names_widget->startOfDoc();
  170. // Get the names of translators, extracted from .../doc/tranlations.txt by viewer_manifest.py at build time
  171. std::string translators_path = gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS,"translators.txt");
  172. llifstream trans_file;
  173. std::string translators;
  174. trans_file.open(translators_path); /* Flawfinder: ignore */
  175. if (trans_file.is_open())
  176. {
  177. std::getline(trans_file, translators); // all names are on a single line
  178. trans_file.close();
  179. }
  180. else
  181. {
  182. LL_WARNS("AboutInit") << "Could not read translators file at " << translators_path << LL_ENDL;
  183. }
  184. trans_names_widget->setText(translators);
  185. trans_names_widget->setEnabled(FALSE);
  186. trans_names_widget->startOfDoc();
  187. return TRUE;
  188. }
  189. // static
  190. LLSD LLFloaterAbout::getInfo()
  191. {
  192. // The point of having one method build an LLSD info block and the other
  193. // construct the user-visible About string is to ensure that the same info
  194. // is available to a getInfo() caller as to the user opening
  195. // LLFloaterAbout.
  196. LLSD info;
  197. LLSD version;
  198. version.append(LLVersionInfo::getMajor());
  199. version.append(LLVersionInfo::getMinor());
  200. version.append(LLVersionInfo::getPatch());
  201. version.append(LLVersionInfo::getBuild());
  202. info["VIEWER_VERSION"] = version;
  203. info["VIEWER_VERSION_STR"] = LLVersionInfo::getVersion();
  204. info["BUILD_DATE"] = __DATE__;
  205. info["BUILD_TIME"] = __TIME__;
  206. info["CHANNEL"] = LLVersionInfo::getChannel();
  207. info["VIEWER_RELEASE_NOTES_URL"] = get_viewer_release_notes_url();
  208. #if LL_MSVC
  209. info["COMPILER"] = "MSVC";
  210. info["COMPILER_VERSION"] = _MSC_VER;
  211. #elif LL_GNUC
  212. info["COMPILER"] = "GCC";
  213. info["COMPILER_VERSION"] = GCC_VERSION;
  214. #endif
  215. // Position
  216. LLViewerRegion* region = gAgent.getRegion();
  217. if (region)
  218. {
  219. const LLVector3d &pos = gAgent.getPositionGlobal();
  220. info["POSITION"] = ll_sd_from_vector3d(pos);
  221. info["REGION"] = gAgent.getRegion()->getName();
  222. info["HOSTNAME"] = gAgent.getRegion()->getHost().getHostName();
  223. info["HOSTIP"] = gAgent.getRegion()->getHost().getString();
  224. info["SERVER_VERSION"] = gLastVersionChannel;
  225. }
  226. // CPU
  227. info["CPU"] = gSysCPU.getCPUString();
  228. info["MEMORY_MB"] = LLSD::Integer(gSysMemory.getPhysicalMemoryKB() / 1024);
  229. // Moved hack adjustment to Windows memory size into llsys.cpp
  230. info["OS_VERSION"] = LLAppViewer::instance()->getOSInfo().getOSString();
  231. info["GRAPHICS_CARD_VENDOR"] = (const char*)(glGetString(GL_VENDOR));
  232. info["GRAPHICS_CARD"] = (const char*)(glGetString(GL_RENDERER));
  233. #if LL_WINDOWS
  234. LLSD driver_info = gDXHardware.getDisplayInfo();
  235. if (driver_info.has("DriverVersion"))
  236. {
  237. info["GRAPHICS_DRIVER_VERSION"] = driver_info["DriverVersion"];
  238. }
  239. #endif
  240. info["OPENGL_VERSION"] = (const char*)(glGetString(GL_VERSION));
  241. info["LIBCURL_VERSION"] = LLCurl::getVersionString();
  242. info["J2C_VERSION"] = LLImageJ2C::getEngineInfo();
  243. bool want_fullname = true;
  244. info["AUDIO_DRIVER_VERSION"] = gAudiop ? LLSD(gAudiop->getDriverName(want_fullname)) : LLSD();
  245. if(LLVoiceClient::getInstance()->voiceEnabled())
  246. {
  247. LLVoiceVersionInfo version = LLVoiceClient::getInstance()->getVersion();
  248. std::ostringstream version_string;
  249. version_string << version.serverType << " " << version.serverVersion << std::endl;
  250. info["VOICE_VERSION"] = version_string.str();
  251. }
  252. else
  253. {
  254. info["VOICE_VERSION"] = LLTrans::getString("NotConnected");
  255. }
  256. // TODO: Implement media plugin version query
  257. info["QT_WEBKIT_VERSION"] = "4.7.1 (version number hard-coded)";
  258. if (gPacketsIn > 0)
  259. {
  260. info["PACKETS_LOST"] = LLViewerStats::getInstance()->mPacketsLostStat.getCurrent();
  261. info["PACKETS_IN"] = F32(gPacketsIn);
  262. info["PACKETS_PCT"] = 100.f*info["PACKETS_LOST"].asReal() / info["PACKETS_IN"].asReal();
  263. }
  264. return info;
  265. }
  266. static std::string get_viewer_release_notes_url()
  267. {
  268. // return a URL to the release notes for this viewer, such as:
  269. // http://wiki.secondlife.com/wiki/Release_Notes/Second Life Beta Viewer/2.1.0
  270. std::string url = LLTrans::getString("RELEASE_NOTES_BASE_URL");
  271. if (! LLStringUtil::endsWith(url, "/"))
  272. url += "/";
  273. url += LLVersionInfo::getChannel() + "/";
  274. url += LLVersionInfo::getShortVersion();
  275. return LLWeb::escapeURL(url);
  276. }
  277. class LLFloaterAboutListener: public LLEventAPI
  278. {
  279. public:
  280. LLFloaterAboutListener():
  281. LLEventAPI("LLFloaterAbout",
  282. "LLFloaterAbout listener to retrieve About box info")
  283. {
  284. add("getInfo",
  285. "Request an LLSD::Map containing information used to populate About box",
  286. &LLFloaterAboutListener::getInfo,
  287. LLSD().with("reply", LLSD()));
  288. }
  289. private:
  290. void getInfo(const LLSD& request) const
  291. {
  292. LLReqID reqid(request);
  293. LLSD reply(LLFloaterAbout::getInfo());
  294. reqid.stamp(reply);
  295. LLEventPumps::instance().obtain(request["reply"]).post(reply);
  296. }
  297. };
  298. static LLFloaterAboutListener floaterAboutListener;
  299. void LLFloaterAbout::onClickCopyToClipboard()
  300. {
  301. LLViewerTextEditor *support_widget =
  302. getChild<LLViewerTextEditor>("support_editor", true);
  303. support_widget->selectAll();
  304. support_widget->copy();
  305. support_widget->deselect();
  306. }
  307. void LLFloaterAbout::updateServerReleaseNotesURL(const std::string& url)
  308. {
  309. setSupportText(url);
  310. }
  311. void LLFloaterAbout::setSupportText(const std::string& server_release_notes_url)
  312. {
  313. #if LL_WINDOWS
  314. getWindow()->incBusyCount();
  315. getWindow()->setCursor(UI_CURSOR_ARROW);
  316. #endif
  317. LLSD info(getInfo());
  318. #if LL_WINDOWS
  319. getWindow()->decBusyCount();
  320. getWindow()->setCursor(UI_CURSOR_ARROW);
  321. #endif
  322. if (LLStringUtil::startsWith(server_release_notes_url, "http")) // it's an URL
  323. {
  324. info["SERVER_RELEASE_NOTES_URL"] = "[" + LLWeb::escapeURL(server_release_notes_url) + " " + LLTrans::getString("ReleaseNotes") + "]";
  325. }
  326. else
  327. {
  328. info["SERVER_RELEASE_NOTES_URL"] = server_release_notes_url;
  329. }
  330. LLViewerTextEditor *support_widget =
  331. getChild<LLViewerTextEditor>("support_editor", true);
  332. std::ostringstream support;
  333. // Render the LLSD from getInfo() as a format_map_t
  334. LLStringUtil::format_map_t args;
  335. // allow the "Release Notes" URL label to be localized
  336. args["ReleaseNotes"] = LLTrans::getString("ReleaseNotes");
  337. for (LLSD::map_const_iterator ii(info.beginMap()), iend(info.endMap());
  338. ii != iend; ++ii)
  339. {
  340. if (! ii->second.isArray())
  341. {
  342. // Scalar value
  343. if (ii->second.isUndefined())
  344. {
  345. args[ii->first] = getString("none");
  346. }
  347. else
  348. {
  349. // don't forget to render value asString()
  350. args[ii->first] = ii->second.asString();
  351. }
  352. }
  353. else
  354. {
  355. // array value: build KEY_0, KEY_1 etc. entries
  356. for (LLSD::Integer n(0), size(ii->second.size()); n < size; ++n)
  357. {
  358. args[STRINGIZE(ii->first << '_' << n)] = ii->second[n].asString();
  359. }
  360. }
  361. }
  362. // Now build the various pieces
  363. support << getString("AboutHeader", args);
  364. if (info.has("REGION"))
  365. {
  366. support << "\n\n" << getString("AboutPosition", args);
  367. }
  368. support << "\n\n" << getString("AboutSystem", args);
  369. support << "\n";
  370. if (info.has("GRAPHICS_DRIVER_VERSION"))
  371. {
  372. support << "\n" << getString("AboutDriver", args);
  373. }
  374. support << "\n" << getString("AboutLibs", args);
  375. if (info.has("COMPILER"))
  376. {
  377. support << "\n" << getString("AboutCompiler", args);
  378. }
  379. if (info.has("PACKETS_IN"))
  380. {
  381. support << '\n' << getString("AboutTraffic", args);
  382. }
  383. support_widget->clear();
  384. support_widget->appendText(support.str(),
  385. FALSE,
  386. LLStyle::Params()
  387. .color(LLUIColorTable::instance().getColor("TextFgReadOnlyColor")));
  388. }
  389. ///----------------------------------------------------------------------------
  390. /// LLFloaterAboutUtil
  391. ///----------------------------------------------------------------------------
  392. void LLFloaterAboutUtil::registerFloater()
  393. {
  394. LLFloaterReg::add("sl_about", "floater_about.xml",
  395. &LLFloaterReg::build<LLFloaterAbout>);
  396. }
  397. ///----------------------------------------------------------------------------
  398. /// Class LLServerReleaseNotesURLFetcher implementation
  399. ///----------------------------------------------------------------------------
  400. // static
  401. void LLServerReleaseNotesURLFetcher::startFetch()
  402. {
  403. LLViewerRegion* region = gAgent.getRegion();
  404. if (!region) return;
  405. // We cannot display the URL returned by the ServerReleaseNotes capability
  406. // because opening it in an external browser will trigger a warning about untrusted
  407. // SSL certificate.
  408. // So we query the URL ourselves, expecting to find
  409. // an URL suitable for external browsers in the "Location:" HTTP header.
  410. std::string cap_url = region->getCapability("ServerReleaseNotes");
  411. LLHTTPClient::get(cap_url, new LLServerReleaseNotesURLFetcher);
  412. }
  413. // virtual
  414. void LLServerReleaseNotesURLFetcher::completedHeader(U32 status, const std::string& reason, const LLSD& content)
  415. {
  416. lldebugs << "Status: " << status << llendl;
  417. lldebugs << "Reason: " << reason << llendl;
  418. lldebugs << "Headers: " << content << llendl;
  419. LLFloaterAbout* floater_about = LLFloaterReg::getTypedInstance<LLFloaterAbout>("sl_about");
  420. if (floater_about)
  421. {
  422. std::string location = content["location"].asString();
  423. if (location.empty())
  424. {
  425. location = floater_about->getString("ErrorFetchingServerReleaseNotesURL");
  426. }
  427. floater_about->updateServerReleaseNotesURL(location);
  428. }
  429. }
  430. // virtual
  431. void LLServerReleaseNotesURLFetcher::completedRaw(
  432. U32 status,
  433. const std::string& reason,
  434. const LLChannelDescriptors& channels,
  435. const LLIOPipe::buffer_ptr_t& buffer)
  436. {
  437. // Do nothing.
  438. // We're overriding just because the base implementation tries to
  439. // deserialize LLSD which triggers warnings.
  440. }