PageRenderTime 47ms CodeModel.GetById 21ms RepoModel.GetById 0ms app.codeStats 0ms

/indra/newview/llfloaterwebcontent.cpp

https://bitbucket.org/lindenlab/viewer-beta/
C++ | 467 lines | 335 code | 66 blank | 66 comment | 61 complexity | 9858c8e846365f1e75fe44f9dd61be05 MD5 | raw file
Possible License(s): LGPL-2.1
  1. /**
  2. * @file llfloaterwebcontent.cpp
  3. * @brief floater for displaying web content - e.g. profiles and search (eventually)
  4. *
  5. * $LicenseInfo:firstyear=2006&license=viewerlgpl$
  6. * Second Life Viewer Source Code
  7. * Copyright (C) 2010, Linden Research, Inc.
  8. *
  9. * This library is free software; you can redistribute it and/or
  10. * modify it under the terms of the GNU Lesser General Public
  11. * License as published by the Free Software Foundation;
  12. * version 2.1 of the License only.
  13. *
  14. * This library is distributed in the hope that it will be useful,
  15. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  16. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  17. * Lesser General Public License for more details.
  18. *
  19. * You should have received a copy of the GNU Lesser General Public
  20. * License along with this library; if not, write to the Free Software
  21. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  22. *
  23. * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
  24. * $/LicenseInfo$
  25. */
  26. #include "llviewerprecompiledheaders.h"
  27. #include "llcombobox.h"
  28. #include "lliconctrl.h"
  29. #include "llfloaterreg.h"
  30. #include "lllayoutstack.h"
  31. #include "llpluginclassmedia.h"
  32. #include "llprogressbar.h"
  33. #include "lltextbox.h"
  34. #include "llurlhistory.h"
  35. #include "llviewercontrol.h"
  36. #include "llweb.h"
  37. #include "llwindow.h"
  38. #include "llfloaterwebcontent.h"
  39. LLFloaterWebContent::_Params::_Params()
  40. : url("url"),
  41. target("target"),
  42. id("id"),
  43. window_class("window_class", "web_content"),
  44. show_chrome("show_chrome", true),
  45. allow_address_entry("allow_address_entry", true),
  46. preferred_media_size("preferred_media_size"),
  47. trusted_content("trusted_content", false),
  48. show_page_title("show_page_title", true)
  49. {}
  50. LLFloaterWebContent::LLFloaterWebContent( const Params& params )
  51. : LLFloater( params ),
  52. LLInstanceTracker<LLFloaterWebContent, std::string>(params.id()),
  53. mWebBrowser(NULL),
  54. mAddressCombo(NULL),
  55. mSecureLockIcon(NULL),
  56. mStatusBarText(NULL),
  57. mStatusBarProgress(NULL),
  58. mBtnBack(NULL),
  59. mBtnForward(NULL),
  60. mBtnReload(NULL),
  61. mBtnStop(NULL),
  62. mUUID(params.id()),
  63. mShowPageTitle(params.show_page_title)
  64. {
  65. mCommitCallbackRegistrar.add( "WebContent.Back", boost::bind( &LLFloaterWebContent::onClickBack, this ));
  66. mCommitCallbackRegistrar.add( "WebContent.Forward", boost::bind( &LLFloaterWebContent::onClickForward, this ));
  67. mCommitCallbackRegistrar.add( "WebContent.Reload", boost::bind( &LLFloaterWebContent::onClickReload, this ));
  68. mCommitCallbackRegistrar.add( "WebContent.Stop", boost::bind( &LLFloaterWebContent::onClickStop, this ));
  69. mCommitCallbackRegistrar.add( "WebContent.EnterAddress", boost::bind( &LLFloaterWebContent::onEnterAddress, this ));
  70. mCommitCallbackRegistrar.add( "WebContent.PopExternal", boost::bind( &LLFloaterWebContent::onPopExternal, this ));
  71. }
  72. BOOL LLFloaterWebContent::postBuild()
  73. {
  74. // these are used in a bunch of places so cache them
  75. mWebBrowser = getChild< LLMediaCtrl >( "webbrowser" );
  76. mAddressCombo = getChild< LLComboBox >( "address" );
  77. mStatusBarText = getChild< LLTextBox >( "statusbartext" );
  78. mStatusBarProgress = getChild<LLProgressBar>("statusbarprogress" );
  79. mBtnBack = getChildView( "back" );
  80. mBtnForward = getChildView( "forward" );
  81. mBtnReload = getChildView( "reload" );
  82. mBtnStop = getChildView( "stop" );
  83. // observe browser events
  84. mWebBrowser->addObserver( this );
  85. // these buttons are always enabled
  86. mBtnReload->setEnabled( true );
  87. getChildView("popexternal")->setEnabled( true );
  88. // cache image for secure browsing
  89. mSecureLockIcon = getChild< LLIconCtrl >("media_secure_lock_flag");
  90. // initialize the URL history using the system URL History manager
  91. initializeURLHistory();
  92. return TRUE;
  93. }
  94. void LLFloaterWebContent::initializeURLHistory()
  95. {
  96. // start with an empty list
  97. LLCtrlListInterface* url_list = childGetListInterface("address");
  98. if (url_list)
  99. {
  100. url_list->operateOnAll(LLCtrlListInterface::OP_DELETE);
  101. }
  102. // Get all of the entries in the "browser" collection
  103. LLSD browser_history = LLURLHistory::getURLHistory("browser");
  104. LLSD::array_iterator iter_history = browser_history.beginArray();
  105. LLSD::array_iterator end_history = browser_history.endArray();
  106. for(; iter_history != end_history; ++iter_history)
  107. {
  108. std::string url = (*iter_history).asString();
  109. if(! url.empty())
  110. url_list->addSimpleElement(url);
  111. }
  112. }
  113. bool LLFloaterWebContent::matchesKey(const LLSD& key)
  114. {
  115. Params p(mKey);
  116. Params other_p(key);
  117. if (!other_p.target().empty() && other_p.target() != "_blank")
  118. {
  119. return other_p.target() == p.target();
  120. }
  121. else
  122. {
  123. return other_p.id() == p.id();
  124. }
  125. }
  126. //static
  127. LLFloater* LLFloaterWebContent::create( Params p)
  128. {
  129. preCreate(p);
  130. return new LLFloaterWebContent(p);
  131. }
  132. //static
  133. void LLFloaterWebContent::closeRequest(const std::string &uuid)
  134. {
  135. LLFloaterWebContent* floaterp = instance_tracker_t::getInstance(uuid);
  136. if (floaterp)
  137. {
  138. floaterp->closeFloater(false);
  139. }
  140. }
  141. //static
  142. void LLFloaterWebContent::geometryChanged(const std::string &uuid, S32 x, S32 y, S32 width, S32 height)
  143. {
  144. LLFloaterWebContent* floaterp = instance_tracker_t::getInstance(uuid);
  145. if (floaterp)
  146. {
  147. floaterp->geometryChanged(x, y, width, height);
  148. }
  149. }
  150. void LLFloaterWebContent::geometryChanged(S32 x, S32 y, S32 width, S32 height)
  151. {
  152. // Make sure the layout of the browser control is updated, so this calculation is correct.
  153. LLLayoutStack::updateClass();
  154. // TODO: need to adjust size and constrain position to make sure floaters aren't moved outside the window view, etc.
  155. LLCoordWindow window_size;
  156. getWindow()->getSize(&window_size);
  157. // Adjust width and height for the size of the chrome on the web Browser window.
  158. LLRect browser_rect;
  159. mWebBrowser->localRectToOtherView(mWebBrowser->getLocalRect(), &browser_rect, this);
  160. S32 requested_browser_bottom = window_size.mY - (y + height);
  161. LLRect geom;
  162. geom.setOriginAndSize(x - browser_rect.mLeft,
  163. requested_browser_bottom - browser_rect.mBottom,
  164. width + getRect().getWidth() - browser_rect.getWidth(),
  165. height + getRect().getHeight() - browser_rect.getHeight());
  166. lldebugs << "geometry change: " << geom << llendl;
  167. LLRect new_rect;
  168. getParent()->screenRectToLocal(geom, &new_rect);
  169. setShape(new_rect);
  170. }
  171. // static
  172. void LLFloaterWebContent::preCreate(LLFloaterWebContent::Params& p)
  173. {
  174. lldebugs << "url = " << p.url() << ", target = " << p.target() << ", uuid = " << p.id() << llendl;
  175. if (!p.id.isProvided())
  176. {
  177. p.id = LLUUID::generateNewID().asString();
  178. }
  179. if(p.target().empty() || p.target() == "_blank")
  180. {
  181. p.target = p.id();
  182. }
  183. S32 browser_window_limit = gSavedSettings.getS32("WebContentWindowLimit");
  184. if(browser_window_limit != 0)
  185. {
  186. // showInstance will open a new window. Figure out how many web browsers are already open,
  187. // and close the least recently opened one if this will put us over the limit.
  188. LLFloaterReg::const_instance_list_t &instances = LLFloaterReg::getFloaterList(p.window_class);
  189. lldebugs << "total instance count is " << instances.size() << llendl;
  190. for(LLFloaterReg::const_instance_list_t::const_iterator iter = instances.begin(); iter != instances.end(); iter++)
  191. {
  192. lldebugs << " " << (*iter)->getKey()["target"] << llendl;
  193. }
  194. if(instances.size() >= (size_t)browser_window_limit)
  195. {
  196. // Destroy the least recently opened instance
  197. (*instances.begin())->closeFloater();
  198. }
  199. }
  200. }
  201. void LLFloaterWebContent::open_media(const Params& p)
  202. {
  203. // Specifying a mime type of text/html here causes the plugin system to skip the MIME type probe and just open a browser plugin.
  204. LLViewerMedia::proxyWindowOpened(p.target(), p.id());
  205. mWebBrowser->setHomePageUrl(p.url, "text/html");
  206. mWebBrowser->setTarget(p.target);
  207. mWebBrowser->navigateTo(p.url, "text/html");
  208. set_current_url(p.url);
  209. getChild<LLLayoutPanel>("status_bar")->setVisible(p.show_chrome);
  210. getChild<LLLayoutPanel>("nav_controls")->setVisible(p.show_chrome);
  211. bool address_entry_enabled = p.allow_address_entry && !p.trusted_content;
  212. getChildView("address")->setEnabled(address_entry_enabled);
  213. getChildView("popexternal")->setEnabled(address_entry_enabled);
  214. if (!address_entry_enabled)
  215. {
  216. mWebBrowser->setFocus(TRUE);
  217. }
  218. if (!p.show_chrome)
  219. {
  220. setResizeLimits(100, 100);
  221. }
  222. if (!p.preferred_media_size().isEmpty())
  223. {
  224. LLLayoutStack::updateClass();
  225. LLRect browser_rect = mWebBrowser->calcScreenRect();
  226. LLCoordWindow window_size;
  227. getWindow()->getSize(&window_size);
  228. geometryChanged(browser_rect.mLeft, window_size.mY - browser_rect.mTop, p.preferred_media_size().getWidth(), p.preferred_media_size().getHeight());
  229. }
  230. }
  231. void LLFloaterWebContent::onOpen(const LLSD& key)
  232. {
  233. Params params(key);
  234. if (!params.validateBlock())
  235. {
  236. closeFloater();
  237. return;
  238. }
  239. mWebBrowser->setTrustedContent(params.trusted_content);
  240. // tell the browser instance to load the specified URL
  241. open_media(params);
  242. }
  243. //virtual
  244. void LLFloaterWebContent::onClose(bool app_quitting)
  245. {
  246. LLViewerMedia::proxyWindowClosed(mUUID);
  247. destroy();
  248. }
  249. // virtual
  250. void LLFloaterWebContent::draw()
  251. {
  252. // this is asynchronous so we need to keep checking
  253. mBtnBack->setEnabled( mWebBrowser->canNavigateBack() );
  254. mBtnForward->setEnabled( mWebBrowser->canNavigateForward() );
  255. LLFloater::draw();
  256. }
  257. // virtual
  258. void LLFloaterWebContent::handleMediaEvent(LLPluginClassMedia* self, EMediaEvent event)
  259. {
  260. if(event == MEDIA_EVENT_LOCATION_CHANGED)
  261. {
  262. const std::string url = self->getLocation();
  263. if ( url.length() )
  264. mStatusBarText->setText( url );
  265. set_current_url( url );
  266. }
  267. else if(event == MEDIA_EVENT_NAVIGATE_BEGIN)
  268. {
  269. // flags are sent with this event
  270. mBtnBack->setEnabled( self->getHistoryBackAvailable() );
  271. mBtnForward->setEnabled( self->getHistoryForwardAvailable() );
  272. // toggle visibility of these buttons based on browser state
  273. mBtnReload->setVisible( false );
  274. mBtnStop->setVisible( true );
  275. // turn "on" progress bar now we're about to start loading
  276. mStatusBarProgress->setVisible( true );
  277. }
  278. else if(event == MEDIA_EVENT_NAVIGATE_COMPLETE)
  279. {
  280. // flags are sent with this event
  281. mBtnBack->setEnabled( self->getHistoryBackAvailable() );
  282. mBtnForward->setEnabled( self->getHistoryForwardAvailable() );
  283. // toggle visibility of these buttons based on browser state
  284. mBtnReload->setVisible( true );
  285. mBtnStop->setVisible( false );
  286. // turn "off" progress bar now we're loaded
  287. mStatusBarProgress->setVisible( false );
  288. // we populate the status bar with URLs as they change so clear it now we're done
  289. const std::string end_str = "";
  290. mStatusBarText->setText( end_str );
  291. // decide if secure browsing icon should be displayed
  292. std::string prefix = std::string("https://");
  293. std::string test_prefix = mCurrentURL.substr(0, prefix.length());
  294. LLStringUtil::toLower(test_prefix);
  295. if(test_prefix == prefix)
  296. {
  297. mSecureLockIcon->setVisible(true);
  298. }
  299. else
  300. {
  301. mSecureLockIcon->setVisible(false);
  302. }
  303. }
  304. else if(event == MEDIA_EVENT_CLOSE_REQUEST)
  305. {
  306. // The browser instance wants its window closed.
  307. closeFloater();
  308. }
  309. else if(event == MEDIA_EVENT_GEOMETRY_CHANGE)
  310. {
  311. geometryChanged(self->getGeometryX(), self->getGeometryY(), self->getGeometryWidth(), self->getGeometryHeight());
  312. }
  313. else if(event == MEDIA_EVENT_STATUS_TEXT_CHANGED )
  314. {
  315. const std::string text = self->getStatusText();
  316. if ( text.length() )
  317. mStatusBarText->setText( text );
  318. }
  319. else if(event == MEDIA_EVENT_PROGRESS_UPDATED )
  320. {
  321. int percent = (int)self->getProgressPercent();
  322. mStatusBarProgress->setValue( percent );
  323. }
  324. else if(event == MEDIA_EVENT_NAME_CHANGED )
  325. {
  326. std::string page_title = self->getMediaName();
  327. // simulate browser behavior - title is empty, use the current URL
  328. if (mShowPageTitle)
  329. {
  330. if ( page_title.length() > 0 )
  331. setTitle( page_title );
  332. else
  333. setTitle( mCurrentURL );
  334. }
  335. }
  336. else if(event == MEDIA_EVENT_LINK_HOVERED )
  337. {
  338. const std::string link = self->getHoverLink();
  339. mStatusBarText->setText( link );
  340. }
  341. }
  342. void LLFloaterWebContent::set_current_url(const std::string& url)
  343. {
  344. mCurrentURL = url;
  345. // serialize url history into the system URL History manager
  346. LLURLHistory::removeURL("browser", mCurrentURL);
  347. LLURLHistory::addURL("browser", mCurrentURL);
  348. mAddressCombo->remove( mCurrentURL );
  349. mAddressCombo->add( mCurrentURL );
  350. mAddressCombo->selectByValue( mCurrentURL );
  351. }
  352. void LLFloaterWebContent::onClickForward()
  353. {
  354. mWebBrowser->navigateForward();
  355. }
  356. void LLFloaterWebContent::onClickBack()
  357. {
  358. mWebBrowser->navigateBack();
  359. }
  360. void LLFloaterWebContent::onClickReload()
  361. {
  362. if( mWebBrowser->getMediaPlugin() )
  363. {
  364. bool ignore_cache = true;
  365. mWebBrowser->getMediaPlugin()->browse_reload( ignore_cache );
  366. }
  367. else
  368. {
  369. mWebBrowser->navigateTo(mCurrentURL);
  370. }
  371. }
  372. void LLFloaterWebContent::onClickStop()
  373. {
  374. if( mWebBrowser->getMediaPlugin() )
  375. mWebBrowser->getMediaPlugin()->browse_stop();
  376. // still should happen when we catch the navigate complete event
  377. // but sometimes (don't know why) that event isn't sent from Qt
  378. // and we ghetto a point where the stop button stays active.
  379. mBtnReload->setVisible( true );
  380. mBtnStop->setVisible( false );
  381. }
  382. void LLFloaterWebContent::onEnterAddress()
  383. {
  384. // make sure there is at least something there.
  385. // (perhaps this test should be for minimum length of a URL)
  386. std::string url = mAddressCombo->getValue().asString();
  387. if ( url.length() > 0 )
  388. {
  389. mWebBrowser->navigateTo( url, "text/html");
  390. };
  391. }
  392. void LLFloaterWebContent::onPopExternal()
  393. {
  394. // make sure there is at least something there.
  395. // (perhaps this test should be for minimum length of a URL)
  396. std::string url = mAddressCombo->getValue().asString();
  397. if ( url.length() > 0 )
  398. {
  399. LLWeb::loadURLExternal( url );
  400. };
  401. }