llscriptfloater.cpp
上传用户:king477883
上传日期:2021-03-01
资源大小:9553k
文件大小:14k
源码类别:

游戏引擎

开发平台:

C++ Builder

  1. /** 
  2.  * @file llscriptfloater.cpp
  3.  * @brief LLScriptFloater class definition
  4.  *
  5.  * $LicenseInfo:firstyear=2009&license=viewergpl$
  6.  * 
  7.  * Copyright (c) 2009-2010, Linden Research, Inc.
  8.  * 
  9.  * Second Life Viewer Source Code
  10.  * The source code in this file ("Source Code") is provided by Linden Lab
  11.  * to you under the terms of the GNU General Public License, version 2.0
  12.  * ("GPL"), unless you have obtained a separate licensing agreement
  13.  * ("Other License"), formally executed by you and Linden Lab.  Terms of
  14.  * the GPL can be found in doc/GPL-license.txt in this distribution, or
  15.  * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
  16.  * 
  17.  * There are special exceptions to the terms and conditions of the GPL as
  18.  * it is applied to this Source Code. View the full text of the exception
  19.  * in the file doc/FLOSS-exception.txt in this software distribution, or
  20.  * online at
  21.  * http://secondlifegrid.net/programs/open_source/licensing/flossexception
  22.  * 
  23.  * By copying, modifying or distributing this software, you acknowledge
  24.  * that you have read and understood your obligations described above,
  25.  * and agree to abide by those obligations.
  26.  * 
  27.  * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
  28.  * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
  29.  * COMPLETENESS OR PERFORMANCE.
  30.  * $/LicenseInfo$
  31.  */
  32. #include "llviewerprecompiledheaders.h"
  33. #include "llscriptfloater.h"
  34. #include "llbottomtray.h"
  35. #include "llchannelmanager.h"
  36. #include "llchiclet.h"
  37. #include "llfloaterreg.h"
  38. #include "llnotifications.h"
  39. #include "llnotificationsutil.h"
  40. #include "llscreenchannel.h"
  41. #include "llsyswellwindow.h"
  42. #include "lltoastnotifypanel.h"
  43. #include "lltrans.h"
  44. #include "llviewerwindow.h"
  45. #include "llimfloater.h"
  46. //////////////////////////////////////////////////////////////////////////
  47. //////////////////////////////////////////////////////////////////////////
  48. //////////////////////////////////////////////////////////////////////////
  49. LLUUID notification_id_to_object_id(const LLUUID& notification_id)
  50. {
  51. LLNotificationPtr notification = LLNotifications::getInstance()->find(notification_id);
  52. if(notification)
  53. {
  54. return notification->getPayload()["object_id"].asUUID();
  55. }
  56. return LLUUID::null;
  57. }
  58. //////////////////////////////////////////////////////////////////////////
  59. //////////////////////////////////////////////////////////////////////////
  60. //////////////////////////////////////////////////////////////////////////
  61. LLScriptFloater::LLScriptFloater(const LLSD& key)
  62. : LLDockableFloater(NULL, true, key)
  63. , mScriptForm(NULL)
  64. , mSaveFloaterPosition(false)
  65. {
  66. setMouseDownCallback(boost::bind(&LLScriptFloater::onMouseDown, this));
  67. setOverlapsScreenChannel(true);
  68. }
  69. bool LLScriptFloater::toggle(const LLUUID& notification_id)
  70. {
  71. LLScriptFloater* floater = LLFloaterReg::findTypedInstance<LLScriptFloater>("script_floater", notification_id);
  72. // show existing floater
  73. if(floater)
  74. {
  75. if(floater->getVisible())
  76. {
  77. floater->setVisible(false);
  78. return false;
  79. }
  80. else
  81. {
  82. floater->setVisible(TRUE);
  83. floater->setFocus(TRUE);
  84. }
  85. }
  86. // create and show new floater
  87. else
  88. {
  89. show(notification_id);
  90. }
  91. LLBottomTray::getInstance()->getChicletPanel()->setChicletToggleState(notification_id, true);
  92. return true;
  93. }
  94. LLScriptFloater* LLScriptFloater::show(const LLUUID& notification_id)
  95. {
  96. LLScriptFloater* floater = LLFloaterReg::getTypedInstance<LLScriptFloater>("script_floater", notification_id);
  97. floater->setNotificationId(notification_id);
  98. floater->createForm(notification_id);
  99. if(LLScriptFloaterManager::OBJ_SCRIPT == LLScriptFloaterManager::getObjectType(notification_id))
  100. {
  101. floater->setSavePosition(true);
  102. floater->restorePosition();
  103. }
  104. else
  105. {
  106. floater->dockToChiclet(true);
  107. }
  108. LLFloaterReg::showTypedInstance<LLScriptFloater>("script_floater", notification_id, TRUE);
  109. return floater;
  110. }
  111. void LLScriptFloater::setNotificationId(const LLUUID& id)
  112. {
  113. mNotificationId = id;
  114. // Lets save object id now while notification exists
  115. mObjectId = notification_id_to_object_id(id);
  116. }
  117. void LLScriptFloater::getAllowedRect(LLRect& rect)
  118. {
  119. rect = gViewerWindow->getWorldViewRectRaw();
  120. }
  121. void LLScriptFloater::createForm(const LLUUID& notification_id)
  122. {
  123. // delete old form
  124. if(mScriptForm)
  125. {
  126. removeChild(mScriptForm);
  127. mScriptForm->die();
  128. }
  129. LLNotificationPtr notification = LLNotifications::getInstance()->find(notification_id);
  130. if(NULL == notification)
  131. {
  132. return;
  133. }
  134. // create new form
  135. mScriptForm = new LLToastNotifyPanel(notification);
  136. addChild(mScriptForm);
  137. // position form on floater
  138. mScriptForm->setOrigin(0, 0);
  139. // make floater size fit form size
  140. LLRect toast_rect = getRect();
  141. LLRect panel_rect = mScriptForm->getRect();
  142. toast_rect.setLeftTopAndSize(toast_rect.mLeft, toast_rect.mTop, panel_rect.getWidth(), panel_rect.getHeight() + getHeaderHeight());
  143. setShape(toast_rect);
  144. }
  145. void LLScriptFloater::onClose(bool app_quitting)
  146. {
  147. savePosition();
  148. if(getNotificationId().notNull())
  149. {
  150. LLScriptFloaterManager::getInstance()->onRemoveNotification(getNotificationId());
  151. }
  152. }
  153. void LLScriptFloater::setDocked(bool docked, bool pop_on_undock /* = true */)
  154. {
  155. LLDockableFloater::setDocked(docked, pop_on_undock);
  156. savePosition();
  157. hideToastsIfNeeded();
  158. }
  159. void LLScriptFloater::setVisible(BOOL visible)
  160. {
  161. LLDockableFloater::setVisible(visible);
  162. hideToastsIfNeeded();
  163. if(!visible)
  164. {
  165. LLIMChiclet* chiclet = LLBottomTray::getInstance()->getChicletPanel()->findChiclet<LLIMChiclet>(getNotificationId());
  166. if(chiclet)
  167. {
  168. chiclet->setToggleState(false);
  169. }
  170. }
  171. }
  172. void LLScriptFloater::onMouseDown()
  173. {
  174. if(getNotificationId().notNull())
  175. {
  176. // Remove new message icon
  177. LLIMChiclet* chiclet = LLBottomTray::getInstance()->getChicletPanel()->findChiclet<LLIMChiclet>(getNotificationId());
  178. if (chiclet == NULL)
  179. {
  180. llerror("Dock chiclet for LLScriptFloater doesn't exist", 0);
  181. }
  182. else
  183. {
  184. chiclet->setShowNewMessagesIcon(false);
  185. }
  186. }
  187. }
  188. void LLScriptFloater::savePosition()
  189. {
  190. if(getSavePosition() && mObjectId.notNull())
  191. {
  192. LLScriptFloaterManager::FloaterPositionInfo fpi = {getRect(), isDocked()};
  193. LLScriptFloaterManager::getInstance()->saveFloaterPosition(mObjectId, fpi);
  194. }
  195. }
  196. void LLScriptFloater::restorePosition()
  197. {
  198. LLScriptFloaterManager::FloaterPositionInfo fpi;
  199. if(LLScriptFloaterManager::getInstance()->getFloaterPosition(mObjectId, fpi))
  200. {
  201. dockToChiclet(fpi.mDockState);
  202. if(!fpi.mDockState)
  203. {
  204. // Un-docked floater is opened in 0,0, now move it to saved position
  205. translate(fpi.mRect.mLeft - getRect().mLeft, fpi.mRect.mTop - getRect().mTop);
  206. }
  207. }
  208. else
  209. {
  210. dockToChiclet(true);
  211. }
  212. }
  213. void LLScriptFloater::onFocusLost()
  214. {
  215. if(getNotificationId().notNull())
  216. {
  217. LLBottomTray::getInstance()->getChicletPanel()->setChicletToggleState(getNotificationId(), false);
  218. }
  219. }
  220. void LLScriptFloater::onFocusReceived()
  221. {
  222. // first focus will be received before setObjectId() call - don't toggle chiclet
  223. if(getNotificationId().notNull())
  224. {
  225. LLBottomTray::getInstance()->getChicletPanel()->setChicletToggleState(getNotificationId(), true);
  226. }
  227. }
  228. void LLScriptFloater::dockToChiclet(bool dock)
  229. {
  230. if (getDockControl() == NULL)
  231. {
  232. LLChiclet* chiclet = LLBottomTray::getInstance()->getChicletPanel()->findChiclet<LLChiclet>(getNotificationId());
  233. if (chiclet == NULL)
  234. {
  235. llwarns << "Dock chiclet for LLScriptFloater doesn't exist" << llendl;
  236. return;
  237. }
  238. else
  239. {
  240. LLBottomTray::getInstance()->getChicletPanel()->scrollToChiclet(chiclet);
  241. }
  242. // Stop saving position while we dock floater
  243. bool save = getSavePosition();
  244. setSavePosition(false);
  245. setDockControl(new LLDockControl(chiclet, this, getDockTongue(),
  246. LLDockControl::TOP,  boost::bind(&LLScriptFloater::getAllowedRect, this, _1)), dock);
  247. // Restore saving
  248. setSavePosition(save);
  249. }
  250. }
  251. void LLScriptFloater::hideToastsIfNeeded()
  252. {
  253. using namespace LLNotificationsUI;
  254. // find channel
  255. LLScreenChannel* channel = dynamic_cast<LLScreenChannel*>(LLChannelManager::getInstance()->findChannelByID(
  256. LLUUID(gSavedSettings.getString("NotificationChannelUUID"))));
  257. // update notification channel state
  258. if(channel)
  259. {
  260. channel->updateShowToastsState();
  261. channel->redrawToasts();
  262. }
  263. }
  264. //////////////////////////////////////////////////////////////////////////
  265. //////////////////////////////////////////////////////////////////////////
  266. //////////////////////////////////////////////////////////////////////////
  267. void LLScriptFloaterManager::onAddNotification(const LLUUID& notification_id)
  268. {
  269. if(notification_id.isNull())
  270. {
  271. llwarns << "Invalid notification ID" << llendl;
  272. return;
  273. }
  274. // get scripted Object's ID
  275. LLUUID object_id = notification_id_to_object_id(notification_id);
  276. // Need to indicate of "new message" for object chiclets according to requirements
  277. // specified in the Message Bar design specification. See EXT-3142.
  278. bool set_new_message = false;
  279. EObjectType obj_type = getObjectType(notification_id);
  280. // LLDialog can spawn only one instance, LLLoadURL and LLGiveInventory can spawn unlimited number of instances
  281. if(OBJ_SCRIPT == obj_type)
  282. {
  283. // If an Object spawns more-than-one floater, only the newest one is shown. 
  284. // The previous is automatically closed.
  285. script_notification_map_t::const_iterator it = findUsingObjectId(object_id);
  286. if(it != mNotifications.end())
  287. {
  288. LLIMChiclet* chiclet = LLBottomTray::getInstance()->getChicletPanel()->findChiclet<LLIMChiclet>(it->first);
  289. if(chiclet)
  290. {
  291. // Pass the new_message icon state further.
  292. set_new_message = chiclet->getShowNewMessagesIcon();
  293. }
  294. LLScriptFloater* floater = LLFloaterReg::findTypedInstance<LLScriptFloater>("script_floater", it->first);
  295. if(floater)
  296. {
  297. // Generate chiclet with a "new message" indicator if a docked window was opened but not in focus. See EXT-3142.
  298. set_new_message |= !floater->hasFocus();
  299. }
  300. onRemoveNotification(it->first);
  301. }
  302. }
  303. mNotifications.insert(std::make_pair(notification_id, object_id));
  304. // Create inventory offer chiclet for offer type notifications
  305. if( OBJ_GIVE_INVENTORY == obj_type )
  306. {
  307. LLBottomTray::instance().getChicletPanel()->createChiclet<LLInvOfferChiclet>(notification_id);
  308. }
  309. else
  310. {
  311. LLBottomTray::getInstance()->getChicletPanel()->createChiclet<LLScriptChiclet>(notification_id);
  312. }
  313. LLIMWellWindow::getInstance()->addObjectRow(notification_id, set_new_message);
  314. LLSD data;
  315. data["notification_id"] = notification_id;
  316. data["new_message"] = set_new_message;
  317. data["unread"] = 1; // each object has got only one floater
  318. mNewObjectSignal(data);
  319. toggleScriptFloater(notification_id, set_new_message);
  320. }
  321. void LLScriptFloaterManager::onRemoveNotification(const LLUUID& notification_id)
  322. {
  323. if(notification_id.isNull())
  324. {
  325. llwarns << "Invalid notification ID" << llendl;
  326. return;
  327. }
  328. // remove related chiclet
  329. LLBottomTray::getInstance()->getChicletPanel()->removeChiclet(notification_id);
  330. LLIMWellWindow::getInstance()->removeObjectRow(notification_id);
  331. // close floater
  332. LLScriptFloater* floater = LLFloaterReg::findTypedInstance<LLScriptFloater>("script_floater", notification_id);
  333. if(floater)
  334. {
  335. floater->savePosition();
  336. floater->setNotificationId(LLUUID::null);
  337. floater->closeFloater();
  338. }
  339. mNotifications.erase(notification_id);
  340. }
  341. void LLScriptFloaterManager::toggleScriptFloater(const LLUUID& notification_id, bool set_new_message)
  342. {
  343. LLSD data;
  344. data["notification_id"] = notification_id;
  345. data["new_message"] = set_new_message;
  346. mToggleFloaterSignal(data);
  347. // toggle floater
  348. LLScriptFloater::toggle(notification_id);
  349. }
  350. LLUUID LLScriptFloaterManager::findObjectId(const LLUUID& notification_id)
  351. {
  352. script_notification_map_t::const_iterator it = mNotifications.find(notification_id);
  353. if(mNotifications.end() != it)
  354. {
  355. return it->second;
  356. }
  357. return LLUUID::null;
  358. }
  359. LLUUID LLScriptFloaterManager::findNotificationId(const LLUUID& object_id)
  360. {
  361. if(object_id.notNull())
  362. {
  363. script_notification_map_t::const_iterator it = findUsingObjectId(object_id);
  364. if(mNotifications.end() != it)
  365. {
  366. return it->first;
  367. }
  368. }
  369. return LLUUID::null;
  370. }
  371. // static
  372. LLScriptFloaterManager::EObjectType LLScriptFloaterManager::getObjectType(const LLUUID& notification_id)
  373. {
  374. if(notification_id.isNull())
  375. {
  376. llwarns << "Invalid notification ID" << llendl;
  377. return OBJ_UNKNOWN;
  378. }
  379. static const object_type_map TYPE_MAP = initObjectTypeMap();
  380. LLNotificationPtr notification = LLNotificationsUtil::find(notification_id);
  381. object_type_map::const_iterator it = TYPE_MAP.find(notification->getName());
  382. if(it != TYPE_MAP.end())
  383. {
  384. return it->second;
  385. }
  386. llwarns << "Unknown object type" << llendl;
  387. return OBJ_UNKNOWN;
  388. }
  389. // static
  390. std::string LLScriptFloaterManager::getObjectName(const LLUUID& notification_id)
  391. {
  392. using namespace LLNotificationsUI;
  393. LLNotificationPtr notification = LLNotifications::getInstance()->find(notification_id);
  394. if(!notification)
  395. {
  396. llwarns << "Invalid notification" << llendl;
  397. return LLStringUtil::null;
  398. }
  399. std::string text;
  400. switch(LLScriptFloaterManager::getObjectType(notification_id))
  401. {
  402. case LLScriptFloaterManager::OBJ_SCRIPT:
  403. text = notification->getSubstitutions()["TITLE"].asString();
  404. break;
  405. case LLScriptFloaterManager::OBJ_LOAD_URL:
  406. text = notification->getSubstitutions()["OBJECTNAME"].asString();
  407. break;
  408. case LLScriptFloaterManager::OBJ_GIVE_INVENTORY:
  409. text = notification->getSubstitutions()["NAME"].asString();
  410. break;
  411. default:
  412. text = LLTrans::getString("object");
  413. break;
  414. }
  415. return text;
  416. }
  417. //static
  418. LLScriptFloaterManager::object_type_map LLScriptFloaterManager::initObjectTypeMap()
  419. {
  420. object_type_map type_map;
  421. type_map["ScriptDialog"] = OBJ_SCRIPT;
  422. type_map["ScriptDialogGroup"] = OBJ_SCRIPT;
  423. type_map["LoadWebPage"] = OBJ_LOAD_URL;
  424. type_map["ObjectGiveItem"] = OBJ_GIVE_INVENTORY;
  425. return type_map;
  426. }
  427. LLScriptFloaterManager::script_notification_map_t::const_iterator LLScriptFloaterManager::findUsingObjectId(const LLUUID& object_id)
  428. {
  429. script_notification_map_t::const_iterator it = mNotifications.begin();
  430. for(; mNotifications.end() != it; ++it)
  431. {
  432. if(object_id == it->second)
  433. {
  434. return it;
  435. }
  436. }
  437. return mNotifications.end();
  438. }
  439. void LLScriptFloaterManager::saveFloaterPosition(const LLUUID& object_id, const FloaterPositionInfo& fpi)
  440. {
  441. if(object_id.notNull())
  442. {
  443. LLScriptFloaterManager::getInstance()->mFloaterPositions[object_id] = fpi;
  444. }
  445. else
  446. {
  447. llwarns << "Invalid object id" << llendl;
  448. }
  449. }
  450. bool LLScriptFloaterManager::getFloaterPosition(const LLUUID& object_id, FloaterPositionInfo& fpi)
  451. {
  452. floater_position_map_t::const_iterator it = mFloaterPositions.find(object_id);
  453. if(LLScriptFloaterManager::getInstance()->mFloaterPositions.end() != it)
  454. {
  455. fpi = it->second;
  456. return true;
  457. }
  458. return false;
  459. }
  460. // EOF