void LLScriptHandler::onDeleteToast(LLToast* toast) { // send a signal to the counter manager mDelNotificationSignal(); // send a signal to a listener to let him perform some action // in this case listener is a SysWellWindow and it will remove a corresponding item from its list mNotificationIDSignal(toast->getNotificationID()); LLNotificationPtr notification = LLNotifications::getInstance()->find(toast->getNotificationID()); if( notification && (SCRIPT_DIALOG == notification->getName() || SCRIPT_DIALOG_GROUP == notification->getName()) ) { LLScriptFloaterManager::getInstance()->onRemoveNotification(notification->getID()); } }
// static bool LLHandlerUtil::canSpawnIMSession(const LLNotificationPtr& notification) { // return OFFER_FRIENDSHIP == notification->getName() // || USER_GIVE_ITEM == notification->getName() // || TELEPORT_OFFERED == notification->getName(); // [SL:KB] - Patch: UI-Notifications | Checked: 2011-04-11 (Catznip-2.5.0a) | Added: Catznip-2.5.0a // return // (canEmbedNotificationInIM(notification)) && // ( (OFFER_FRIENDSHIP == notification->getName()) || (USER_GIVE_ITEM == notification->getName()) || // (TELEPORT_OFFERED == notification->getName()) ); // [/SL:KB] // [RLVa:KB] - Checked: 2011-04-11 (RLVa-1.3.0h) | Added: RLVa-1.3.0h return (canEmbedNotificationInIM(notification)) && ( (!rlv_handler_t::isEnabled()) || (gRlvHandler.canStartIM(notification->getPayload()["from_id"].asUUID())) ) && ( (OFFER_FRIENDSHIP == notification->getName()) || (USER_GIVE_ITEM == notification->getName()) || (TELEPORT_OFFERED == notification->getName()) ); // [/RLVa:KB] }
bool LLNotifications::uniqueHandler(const LLSD& payload) { LLNotificationPtr pNotif = LLNotifications::instance().find(payload["id"].asUUID()); if (pNotif && pNotif->hasUniquenessConstraints()) { if (payload["sigtype"].asString() == "add") { // not a duplicate according to uniqueness criteria, so we keep it // and store it for future uniqueness checks mUniqueNotifications.insert(std::make_pair(pNotif->getName(), pNotif)); } else if (payload["sigtype"].asString() == "delete") { mUniqueNotifications.erase(pNotif->getName()); } } return false; }
void LLNotifications::cancel(LLNotificationPtr pNotif) { LLNotificationSet::iterator it=mItems.find(pNotif); if (it == mItems.end()) { llerrs << "Attempted to delete nonexistent notification " << pNotif->getName() << llendl; } updateItem(LLSD().insert("sigtype", "delete").insert("id", pNotif->id()), pNotif); pNotif->cancel(); }
bool GrowlManager::onLLNotification(const LLSD& notice) { if (notice["sigtype"].asString() != "add") { return false; } LLNotificationPtr notification = LLNotifications::instance().find(notice["id"].asUUID()); std::string name = notification->getName(); LLSD substitutions = notification->getSubstitutions(); if (gGrowlManager->mNotifications.find(name) != gGrowlManager->mNotifications.end()) { GrowlNotification* growl_notification = &gGrowlManager->mNotifications[name]; std::string body = ""; std::string title = ""; if (growl_notification->useDefaultTextForTitle) { title = notification->getMessage(); } else if (!growl_notification->growlTitle.empty()) { title = growl_notification->growlTitle; LLStringUtil::format(title, substitutions); } if (growl_notification->useDefaultTextForBody) { body = notification->getMessage(); } else if (!growl_notification->growlBody.empty()) { body = growl_notification->growlBody; LLStringUtil::format(body, substitutions); } //TM:FS no need to log whats sent to growl //LL_INFOS("GrowlLLNotification") << "Notice: " << title << ": " << body << LL_ENDL; if (name == "ObjectGiveItem" || name == "OwnObjectGiveItem" || name == "ObjectGiveItemUnknownUser" || name == "UserGiveItem" || name == "SystemMessageTip") { LLUrlMatch urlMatch; LLWString newLine = utf8str_to_wstring(body); LLWString workLine = utf8str_to_wstring(body); while (LLUrlRegistry::instance().findUrl(workLine, urlMatch) && !urlMatch.getUrl().empty()) { LLWStringUtil::replaceString(newLine, utf8str_to_wstring(urlMatch.getUrl()), utf8str_to_wstring(urlMatch.getLabel())); // Remove the URL from the work line so we don't end in a loop in case of regular URLs! // findUrl will always return the very first URL in a string workLine = workLine.erase(0, urlMatch.getEnd() + 1); } body = wstring_to_utf8str(newLine); } gGrowlManager->notify(title, body, growl_notification->growlName); } return false; }
bool filterIgnoredNotifications(LLNotificationPtr notification) { LLNotificationFormPtr form = notification->getForm(); // Check to see if the user wants to ignore this alert if (form->getIgnoreType() != LLNotificationForm::IGNORE_NO) { return LLUI::sConfigGroup->getWarning(notification->getName()); } return true; }
void LLNotifications::cancel(LLNotificationPtr pNotif) { if (pNotif == NULL || pNotif->isCancelled()) return; AILOCK_mItems; LLNotificationSet::iterator it=mItems.find(pNotif); if (it == mItems.end()) { LL_ERRS() << "Attempted to delete nonexistent notification " << pNotif->getName() << LL_ENDL; } UpdateItemSM::add(UpdateItem("delete", pNotif)); }
// static bool LLHandlerUtil::canSpawnToast(const LLNotificationPtr& notification) { if(INVENTORY_DECLINED == notification->getName() || INVENTORY_ACCEPTED == notification->getName()) { // return false for inventory accepted/declined notifications if respective IM window is open (EXT-5909) return ! isIMFloaterOpened(notification); } if(FRIENDSHIP_ACCEPTED == notification->getName()) { // don't show FRIENDSHIP_ACCEPTED if IM window is opened and focused - EXT-6441 return ! isIMFloaterFocused(notification); } if(OFFER_FRIENDSHIP == notification->getName() || USER_GIVE_ITEM == notification->getName() || TELEPORT_OFFERED == notification->getName()) { // When ANY offer arrives, show toast, unless IM window is already open - EXT-5904 return ! isIMFloaterOpened(notification); } return true; }
// static bool LLHandlerUtil::canSpawnToast(const LLNotificationPtr& notification) { if(INVENTORY_DECLINED == notification->getName() || INVENTORY_ACCEPTED == notification->getName()) { // return false for inventory accepted/declined notifications if respective IM window is open (EXT-5909) return ! isIMFloaterOpened(notification); } if(FRIENDSHIP_ACCEPTED == notification->getName()) { // don't show FRIENDSHIP_ACCEPTED if IM window is opened and focused - EXT-6441 return ! isIMFloaterFocused(notification); } if(OFFER_FRIENDSHIP == notification->getName() || USER_GIVE_ITEM == notification->getName() || TELEPORT_OFFERED == notification->getName()) { // When ANY offer arrives, show toast, unless IM window is already open - EXT-5904 // return ! isIMFloaterOpened(notification); // [SL:KB] - Patch: UI-Notifications | Checked: 2011-04-11 (Catznip-2.5.0a) | Added: Catznip-2.5.0a // Force a toast if the user opted not to embed notifications panels in IMs return (!canEmbedNotificationInIM(notification)) || (!isIMFloaterOpened(notification)); // [/SL:KB] } return true; }
bool matches(const LLNotificationPtr notification) const { for (std::set<std::string>::const_iterator it = mExclGroup.begin(); it != mExclGroup.end(); it++) { std::string from_name = LLHandlerUtil::getSubstitutionName(notification); if (notification->getName() == *it && from_name == mFromName) { return true; } } return false; }
// static void LLHandlerUtil::logToIMP2P(const LLNotificationPtr& notification, bool to_file_only) { // don't create IM p2p session with objects, it's necessary condition to log if (notification->getName() != OBJECT_GIVE_ITEM) { LLUUID from_id = notification->getPayload()["from_id"]; if (from_id.isNull()) { llwarns << " from_id for notification " << notification->getName() << " is null " << llendl; return; } if(to_file_only) { gCacheName->get(from_id, false, boost::bind(&log_name_callback, _2, "", notification->getMessage(), LLUUID())); } else { gCacheName->get(from_id, false, boost::bind(&log_name_callback, _2, INTERACTIVE_SYSTEM_FROM, notification->getMessage(), from_id)); } } }
void LLToastNotifyPanel::disableRespondedOptions(LLNotificationPtr& notification) { LLSD response = notification->getResponse(); for (LLSD::map_const_iterator response_it = response.beginMap(); response_it != response.endMap(); ++response_it) { if (response_it->second.isBoolean() && response_it->second.asBoolean()) { // that after multiple responses there can be many pressed buttons // need to process them all disableButtons(notification->getName(), response_it->first); } } }
bool LLProgressView::onAlertModal(const LLSD& notify) { // if the progress view is visible, it will obscure the notification window // in this case, we want to auto-accept WebLaunchExternalTarget notifications if (isInVisibleChain() && notify["sigtype"].asString() == "add") { LLNotificationPtr notifyp = LLNotifications::instance().find(notify["id"].asUUID()); if (notifyp && notifyp->getName() == "WebLaunchExternalTarget") { notifyp->respondWithDefault(); } } return false; }
//static bool LLNotifyBox::onNotification(const LLSD& notify) { LLNotificationPtr notification = LLNotifications::instance().find(notify["id"].asUUID()); if (!notification) return false; if(notify["sigtype"].asString() == "add" || notify["sigtype"].asString() == "change") { //bring existing notification to top //This getInstance is ugly, as LLNotifyBox is derived from both LLInstanceTracker and LLEventTimer, which also is derived from its own LLInstanceTracker //Have to explicitly determine which getInstance function to use. LLNotifyBox* boxp = LLInstanceTracker<LLNotifyBox, LLUUID>::getInstance(notification->getID()); if (boxp && !boxp->isDead()) { gNotifyBoxView->showOnly(boxp); } else { bool is_script_dialog = (notification->getName() == "ScriptDialog" || notification->getName() == "ScriptDialogGroup"); LLNotifyBox* notify_box = new LLNotifyBox( notification, is_script_dialog); //layout_script_dialog); gNotifyBoxView->addChild(notify_box); } } else if (notify["sigtype"].asString() == "delete") { LLNotifyBox* boxp = LLInstanceTracker<LLNotifyBox, LLUUID>::getInstance(notification->getID()); if (boxp && !boxp->isDead()) { boxp->close(); } } return false; }
// static void LLHandlerUtil::logToIMP2P(const LLNotificationPtr& notification, bool to_file_only) { const std::string name = LLHandlerUtil::getSubstitutionName(notification); std::string session_name = notification->getPayload().has( "SESSION_NAME") ? notification->getPayload()["SESSION_NAME"].asString() : name; // don't create IM p2p session with objects, it's necessary condition to log if (notification->getName() != OBJECT_GIVE_ITEM && notification->getName() != OBJECT_GIVE_ITEM_UNKNOWN_USER) { LLUUID from_id = notification->getPayload()["from_id"]; //*HACK for ServerObjectMessage the sesson name is really weird, see EXT-4779 if (SERVER_OBJECT_MESSAGE == notification->getName()) { session_name = "chat"; } //there still appears a log history file with weird name " .txt" if (" " == session_name || "{waiting}" == session_name || "{nobody}" == session_name) { llwarning("Weird session name (" + session_name + ") for notification " + notification->getName(), 666) } if(to_file_only) { logToIM(IM_NOTHING_SPECIAL, session_name, "", notification->getMessage(), LLUUID(), LLUUID()); } else { logToIM(IM_NOTHING_SPECIAL, session_name, INTERACTIVE_SYSTEM_FROM, notification->getMessage(), from_id, LLUUID()); } }
bool LLViewerAlertHandler::processNotification(const LLNotificationPtr& p) { if (gHeadlessClient) { LL_INFOS("LLViewerAlertHandler") << "Alert: " << p->getName() << LL_ENDL; } // If we're in mouselook, the mouse is hidden and so the user can't click // the dialog buttons. In that case, change to First Person instead. if( gAgentCamera.cameraMouselook() ) { gAgentCamera.changeCameraToDefault(); } return false; }
void LLSysHandler::removeExclusiveNotifications(const LLNotificationPtr& notif) { LLScreenChannel* channel = dynamic_cast<LLScreenChannel *>(mChannel); if (channel == NULL) { return; } class ExclusiveMatcher: public LLScreenChannel::Matcher { public: ExclusiveMatcher(const std::set<std::string>& excl_group, const std::string& from_name) : mExclGroup(excl_group), mFromName(from_name) { } bool matches(const LLNotificationPtr notification) const { for (std::set<std::string>::const_iterator it = mExclGroup.begin(); it != mExclGroup.end(); it++) { std::string from_name = LLHandlerUtil::getSubstitutionName(notification); if (notification->getName() == *it && from_name == mFromName) { return true; } } return false; } private: const std::set<std::string>& mExclGroup; const std::string& mFromName; }; for (exclusive_notif_sets::iterator it = sExclusiveNotificationGroups.begin(); it != sExclusiveNotificationGroups.end(); it++) { std::set<std::string> group = *it; std::set<std::string>::iterator g_it = group.find(notif->getName()); if (g_it != group.end()) { channel->killMatchedToasts(ExclusiveMatcher(group, LLHandlerUtil::getSubstitutionName(notif))); } } }
// static LLScriptFloaterManager::EObjectType LLScriptFloaterManager::getObjectType(const LLUUID& notification_id) { if(notification_id.isNull()) { llwarns << "Invalid notification ID" << llendl; return OBJ_UNKNOWN; } static const object_type_map TYPE_MAP = initObjectTypeMap(); LLNotificationPtr notification = LLNotificationsUtil::find(notification_id); object_type_map::const_iterator it = TYPE_MAP.find(notification->getName()); if(it != TYPE_MAP.end()) { return it->second; } llwarns << "Unknown object type" << llendl; return OBJ_UNKNOWN; }
bool LLNotifications::uniqueFilter(LLNotificationPtr pNotif) { if (!pNotif->hasUniquenessConstraints()) { return true; } // checks against existing unique notifications for (LLNotificationMap::iterator existing_it = mUniqueNotifications.find(pNotif->getName()); existing_it != mUniqueNotifications.end(); ++existing_it) { LLNotificationPtr existing_notification = existing_it->second; if (pNotif != existing_notification && pNotif->isEquivalentTo(existing_notification)) { return false; } } return true; }
//static void GrowlManager::onScriptDialog(const LLSD& data) { LLNotificationPtr notification = LLNotifications::instance().find(data["notification_id"].asUUID()); std::string name = notification->getName(); LLSD payload = notification->getPayload(); LLSD substitutions = notification->getSubstitutions(); //LL_INFOS("GrowlLLNotification") << "Script dialog: name=" << name << " - payload=" << payload << " subs=" << substitutions << LL_ENDL; if (gGrowlManager->mNotifications.find(name) != gGrowlManager->mNotifications.end()) { GrowlNotification* growl_notification = &gGrowlManager->mNotifications[name]; std::string body = ""; std::string title = ""; if (growl_notification->useDefaultTextForTitle) { title = notification->getMessage(); } else if (!growl_notification->growlTitle.empty()) { title = growl_notification->growlTitle; LLStringUtil::format(title, substitutions); } if (growl_notification->useDefaultTextForBody) { body = notification->getMessage(); } else if (!growl_notification->growlBody.empty()) { body = growl_notification->growlBody; LLStringUtil::format(body, substitutions); } gGrowlManager->notify(title, body, growl_notification->growlName); } }
bool LLNotificationChannelPanel::update(const LLSD& payload, bool passed_filter) { LLNotificationPtr notification = LLNotifications::instance().find(payload["id"].asUUID()); if (notification) { LLSD row; row["columns"][0]["value"] = notification->getName(); row["columns"][0]["column"] = "name"; row["columns"][1]["value"] = notification->getMessage(); row["columns"][1]["column"] = "content"; row["columns"][2]["value"] = notification->getDate(); row["columns"][2]["column"] = "date"; row["columns"][2]["type"] = "date"; LLScrollListItem* sli = passed_filter ? getChild<LLScrollListCtrl>("notifications_list")->addElement(row) : getChild<LLScrollListCtrl>("notification_rejects_list")->addElement(row); sli->setUserdata(&(*notification)); } return false; }
LLToastNotifyPanel::LLToastNotifyPanel(LLNotificationPtr& notification, const LLRect& rect) : LLToastPanel(notification), mTextBox(NULL), mInfoPanel(NULL), mControlPanel(NULL), mNumOptions(0), mNumButtons(0), mAddedDefaultBtn(false), mCloseNotificationOnDestroy(true) { LLUICtrlFactory::getInstance()->buildPanel(this, "panel_notification.xml"); if(rect != LLRect::null) { this->setShape(rect); } mInfoPanel = getChild<LLPanel>("info_panel"); mControlPanel = getChild<LLPanel>("control_panel"); BUTTON_WIDTH = gSavedSettings.getS32("ToastButtonWidth"); // customize panel's attributes // is it intended for displaying a tip mIsTip = notification->getType() == "notifytip"; // is it a script dialog mIsScriptDialog = (notification->getName() == "ScriptDialog" || notification->getName() == "ScriptDialogGroup"); // is it a caution // // caution flag can be set explicitly by specifying it in the notification payload, or it can be set implicitly if the // notify xml template specifies that it is a caution // tip-style notification handle 'caution' differently -they display the tip in a different color mIsCaution = notification->getPriority() >= NOTIFICATION_PRIORITY_HIGH; // setup parameters // get a notification message mMessage = notification->getMessage(); // init font variables if (!sFont) { sFont = LLFontGL::getFontSansSerif(); sFontSmall = LLFontGL::getFontSansSerifSmall(); } // clicking on a button does not steal current focus setIsChrome(TRUE); // initialize setFocusRoot(!mIsTip); // get a form for the notification LLNotificationFormPtr form(notification->getForm()); // get number of elements mNumOptions = form->getNumElements(); // customize panel's outfit // preliminary adjust panel's layout //move to the end //mIsTip ? adjustPanelForTipNotice() : adjustPanelForScriptNotice(form); // adjust text options according to the notification type // add a caution textbox at the top of a caution notification if (mIsCaution && !mIsTip) { mTextBox = getChild<LLTextBox>("caution_text_box"); } else { mTextBox = getChild<LLTextEditor>("text_editor_box"); } // *TODO: magic numbers(???) - copied from llnotify.cpp(250) const S32 MAX_LENGTH = 512 + 20 + DB_FIRST_NAME_BUF_SIZE + DB_LAST_NAME_BUF_SIZE + DB_INV_ITEM_NAME_BUF_SIZE; mTextBox->setMaxTextLength(MAX_LENGTH); mTextBox->setVisible(TRUE); mTextBox->setValue(notification->getMessage()); // add buttons for a script notification if (mIsTip) { adjustPanelForTipNotice(); } else { std::vector<index_button_pair_t> buttons; buttons.reserve(mNumOptions); S32 buttons_width = 0; // create all buttons and accumulate they total width to reshape mControlPanel for (S32 i = 0; i < mNumOptions; i++) { LLSD form_element = form->getElement(i); if (form_element["type"].asString() != "button") { continue; } LLButton* new_button = createButton(form_element, TRUE); buttons_width += new_button->getRect().getWidth(); S32 index = form_element["index"].asInteger(); buttons.push_back(index_button_pair_t(index,new_button)); } if (buttons.empty()) { addDefaultButton(); } else { const S32 button_panel_width = mControlPanel->getRect().getWidth();// do not change width of the panel S32 button_panel_height = mControlPanel->getRect().getHeight(); //try get an average h_pad to spread out buttons S32 h_pad = (button_panel_width - buttons_width) / (S32(buttons.size())); if(h_pad < 2*HPAD) { /* * Probably it is a scriptdialog toast * for a scriptdialog toast h_pad can be < 2*HPAD if we have a lot of buttons. * In last case set default h_pad to avoid heaping of buttons */ S32 button_per_row = button_panel_width / BUTTON_WIDTH; h_pad = (button_panel_width % BUTTON_WIDTH) / (button_per_row - 1);// -1 because we do not need space after last button in a row if(h_pad < 2*HPAD) // still not enough space between buttons ? { h_pad = 2*HPAD; } } if (mIsScriptDialog) { // we are using default width for script buttons so we can determinate button_rows //to get a number of rows we divide the required width of the buttons to button_panel_width S32 button_rows = llceil(F32(buttons.size() - 1) * (BUTTON_WIDTH + h_pad) / button_panel_width); //S32 button_rows = (buttons.size() - 1) * (BUTTON_WIDTH + h_pad) / button_panel_width; //reserve one row for the ignore_btn button_rows++; //calculate required panel height for scripdialog notification. button_panel_height = button_rows * (BTN_HEIGHT + VPAD) + IGNORE_BTN_TOP_DELTA + BOTTOM_PAD; } else { // in common case buttons can have different widths so we need to calculate button_rows according to buttons_width //S32 button_rows = llceil(F32(buttons.size()) * (buttons_width + h_pad) / button_panel_width); S32 button_rows = llceil(F32((buttons.size() - 1) * h_pad + buttons_width) / button_panel_width); //calculate required panel height button_panel_height = button_rows * (BTN_HEIGHT + VPAD) + BOTTOM_PAD; } // we need to keep min width and max height to make visible all buttons, because width of the toast can not be changed adjustPanelForScriptNotice(button_panel_width, button_panel_height); updateButtonsLayout(buttons, h_pad); // save buttons for later use in disableButtons() mButtons.assign(buttons.begin(), buttons.end()); } } // adjust panel's height to the text size mInfoPanel->setFollowsAll(); snapToMessageHeight(mTextBox, MAX_LENGTH); if(notification->isReusable()) { mButtonClickConnection = sButtonClickSignal.connect( boost::bind(&LLToastNotifyPanel::onToastPanelButtonClicked, this, _1, _2)); if(notification->isRespondedTo()) { // User selected an option in toast, now disable required buttons in IM window disableRespondedOptions(notification); } } }
//--------------------------------------------------------------------------- // Singu Note: We could clean a lot of this up by creating derived classes for Notifications and NotificationTips. LLNotifyBox::LLNotifyBox(LLNotificationPtr notification) : LLPanel(notification->getName(), LLRect(), BORDER_NO), LLEventTimer(notification->getExpiration() == LLDate() ? LLDate(LLDate::now().secondsSinceEpoch() + (F64)gSavedSettings.getF32("NotifyTipDuration")) : notification->getExpiration()), LLInstanceTracker<LLNotifyBox, LLUUID>(notification->getID()), mNotification(notification), mIsTip(notification->getType() == "notifytip"), mAnimating(gNotifyBoxView->getChildCount() == 0), // Only animate first window mNextBtn(NULL), mNumOptions(0), mNumButtons(0), mAddedDefaultBtn(false), mUserInputBox(NULL) { std::string edit_text_name; std::string edit_text_contents; // setup paramaters const std::string& message(notification->getMessage()); // initialize setFocusRoot(!mIsTip); // caution flag can be set explicitly by specifying it in the // notification payload, or it can be set implicitly if the // notify xml template specifies that it is a caution // // tip-style notification handle 'caution' differently - // they display the tip in a different color mIsCaution = notification->getPriority() >= NOTIFICATION_PRIORITY_HIGH; LLNotificationFormPtr form(notification->getForm()); mNumOptions = form->getNumElements(); bool is_textbox = form->getElement("message").isDefined(); bool layout_script_dialog(notification->getName() == "ScriptDialog" || notification->getName() == "ScriptDialogGroup"); LLRect rect = mIsTip ? getNotifyTipRect(message) : getNotifyRect(is_textbox ? 10 : mNumOptions, layout_script_dialog, mIsCaution); setRect(rect); setFollows(mIsTip ? (FOLLOWS_BOTTOM|FOLLOWS_RIGHT) : (FOLLOWS_TOP|FOLLOWS_RIGHT)); setBackgroundVisible(FALSE); setBackgroundOpaque(TRUE); LLIconCtrl* icon; LLTextEditor* text; const S32 TOP = getRect().getHeight() - (mIsTip ? (S32)sFont->getLineHeight() : 32); const S32 BOTTOM = (S32)sFont->getLineHeight(); S32 x = HPAD + HPAD; S32 y = TOP; if (mIsTip) { // use the tip notification icon icon = new LLIconCtrl(std::string("icon"), LLRect(x, y, x+32, TOP-32), std::string("notify_tip_icon.tga")); } else if (mIsCaution) { // use the caution notification icon icon = new LLIconCtrl(std::string("icon"), LLRect(x, y, x+32, TOP-32), std::string("notify_caution_icon.tga")); } else { // use the default notification icon icon = new LLIconCtrl(std::string("icon"), LLRect(x, y, x+32, TOP-32), std::string("notify_box_icon.tga")); } icon->setMouseOpaque(FALSE); addChild(icon); x += HPAD + HPAD + 32; // add a caution textbox at the top of a caution notification LLTextBox* caution_box = NULL; if (mIsCaution && !mIsTip) { S32 caution_height = ((S32)sFont->getLineHeight() * 2) + VPAD; caution_box = new LLTextBox( std::string("caution_box"), LLRect(x, y, getRect().getWidth() - 2, caution_height), LLStringUtil::null, sFont, FALSE); caution_box->setFontStyle(LLFontGL::BOLD); caution_box->setColor(gColors.getColor("NotifyCautionWarnColor")); caution_box->setBackgroundColor(gColors.getColor("NotifyCautionBoxColor")); caution_box->setBorderVisible(FALSE); caution_box->setWrappedText(notification->getMessage()); addChild(caution_box); // adjust the vertical position of the next control so that // it appears below the caution textbox y = y - caution_height; } else if (mIsCaution && mIsTip) { const S32 BTN_TOP = BOTTOM_PAD + (((mNumOptions-1+2)/3)) * (BTN_HEIGHT+VPAD); // Tokenization on \n is handled by LLTextBox const S32 MAX_LENGTH = 512 + 20 + DB_FIRST_NAME_BUF_SIZE + DB_LAST_NAME_BUF_SIZE + DB_INV_ITEM_NAME_BUF_SIZE; // For script dialogs: add space for title. text = new LLTextEditor(std::string("box"), LLRect(x, y, getRect().getWidth()-2, mIsTip ? BOTTOM : BTN_TOP+16), MAX_LENGTH, message, sFont, FALSE); text->setWordWrap(TRUE); text->setTabStop(FALSE); text->setMouseOpaque(FALSE); text->setBorderVisible(FALSE); text->setTakesNonScrollClicks(FALSE); text->setHideScrollbarForShortDocs(TRUE); text->setReadOnlyBgColor ( LLColor4::transparent ); // the background color of the box is manually // rendered under the text box, therefore we want // the actual text box to be transparent text->setReadOnlyFgColor ( gColors.getColor("NotifyCautionWarnColor") ); //sets caution text color for tip notifications text->setEnabled(FALSE); // makes it read-only text->setTabStop(FALSE); // can't tab to it (may be a problem for scrolling via keyboard) addChild(text); } else { const S32 BTN_TOP = BOTTOM_PAD + (((mNumOptions-1+2)/3)) * (BTN_HEIGHT+VPAD); // Tokenization on \n is handled by LLTextBox const S32 MAX_LENGTH = 512 + 20 + DB_FIRST_NAME_BUF_SIZE + DB_LAST_NAME_BUF_SIZE + DB_INV_ITEM_NAME_BUF_SIZE; // For script dialogs: add space for title. text = new LLTextEditor(std::string("box"), LLRect(x, y, getRect().getWidth()-2, mIsTip ? BOTTOM : BTN_TOP+16), MAX_LENGTH, message, sFont, FALSE); text->setWordWrap(TRUE); text->setTabStop(FALSE); text->setMouseOpaque(FALSE); text->setBorderVisible(FALSE); text->setTakesNonScrollClicks(FALSE); text->setHideScrollbarForShortDocs(TRUE); text->setReadOnlyBgColor ( LLColor4::transparent ); // the background color of the box is manually // rendered under the text box, therefore we want // the actual text box to be transparent text->setReadOnlyFgColor ( gColors.getColor("NotifyTextColor") ); text->setEnabled(FALSE); // makes it read-only text->setTabStop(FALSE); // can't tab to it (may be a problem for scrolling via keyboard) addChild(text); } if (mIsTip) { chat_notification(mNotification); } else { mNextBtn = new LLButton(std::string("next"), LLRect(getRect().getWidth()-26, BOTTOM_PAD + 20, getRect().getWidth()-2, BOTTOM_PAD), std::string("notify_next.png"), std::string("notify_next.png"), LLStringUtil::null, boost::bind(&LLNotifyBox::moveToBack, this, true), sFont); mNextBtn->setScaleImage(TRUE); mNextBtn->setToolTip(LLTrans::getString("next")); addChild(mNextBtn); for (S32 i = 0; i < mNumOptions; i++) { LLSD form_element = form->getElement(i); std::string element_type = form_element["type"].asString(); if (element_type == "button") { addButton(form_element["name"].asString(), form_element["text"].asString(), TRUE, form_element["default"].asBoolean(), layout_script_dialog); } else if (element_type == "input") { edit_text_contents = form_element["value"].asString(); edit_text_name = form_element["name"].asString(); } } if (is_textbox) { S32 button_rows = layout_script_dialog ? 2 : 1; LLRect input_rect; input_rect.setOriginAndSize(x, BOTTOM_PAD + button_rows * (BTN_HEIGHT + VPAD), 3 * 80 + 4 * HPAD, button_rows * (BTN_HEIGHT + VPAD) + BTN_HEIGHT); mUserInputBox = new LLTextEditor(edit_text_name, input_rect, 254, edit_text_contents, sFont, FALSE); mUserInputBox->setBorderVisible(TRUE); mUserInputBox->setTakesNonScrollClicks(TRUE); mUserInputBox->setHideScrollbarForShortDocs(TRUE); mUserInputBox->setWordWrap(TRUE); mUserInputBox->setTabsToNextField(FALSE); mUserInputBox->setCommitOnFocusLost(FALSE); mUserInputBox->setAcceptCallingCardNames(FALSE); mUserInputBox->setHandleEditKeysDirectly(TRUE); addChild(mUserInputBox, -1); } else { setIsChrome(TRUE); } if (mNumButtons == 0) { addButton("OK", "OK", false, true, layout_script_dialog); mAddedDefaultBtn = true; } if (++sNotifyBoxCount <= 0) LL_WARNS() << "A notification was mishandled. sNotifyBoxCount = " << sNotifyBoxCount << LL_ENDL; // If this is the only notify box, don't show the next button else if (sNotifyBoxCount == 1 && mNextBtn) mNextBtn->setVisible(false); } }
LLToastAlertPanel::LLToastAlertPanel( LLNotificationPtr notification, bool modal) : LLToastPanel(notification), mDefaultOption( 0 ), mCheck(NULL), mCaution(notification->getPriority() >= NOTIFICATION_PRIORITY_HIGH), mLabel(notification->getName()), mLineEditor(NULL) { const LLFontGL* font = LLFontGL::getFontSansSerif(); const S32 LINE_HEIGHT = llfloor(font->getLineHeight() + 0.99f); const S32 EDITOR_HEIGHT = 20; LLNotificationFormPtr form = mNotification->getForm(); std::string edit_text_name; std::string edit_text_contents; S32 edit_text_max_chars = 0; bool is_password = false; LLToastPanel::setBackgroundVisible(FALSE); LLToastPanel::setBackgroundOpaque(TRUE); typedef std::vector<std::pair<std::string, std::string> > options_t; options_t supplied_options; // for now, get LLSD to iterator over form elements LLSD form_sd = form->asLLSD(); S32 option_index = 0; for (LLSD::array_const_iterator it = form_sd.beginArray(); it != form_sd.endArray(); ++it) { std::string type = (*it)["type"].asString(); if (type == "button") { if((*it)["default"]) { mDefaultOption = option_index; } supplied_options.push_back(std::make_pair((*it)["name"].asString(), (*it)["text"].asString())); ButtonData data; if (option_index == mNotification->getURLOption()) { data.mURL = mNotification->getURL(); data.mURLExternal = mNotification->getURLOpenExternally(); } mButtonData.push_back(data); option_index++; } else if (type == "text") { edit_text_contents = (*it)["value"].asString(); edit_text_name = (*it)["name"].asString(); edit_text_max_chars = (*it)["max_length_chars"].asInteger(); } else if (type == "password") { edit_text_contents = (*it)["value"].asString(); edit_text_name = (*it)["name"].asString(); is_password = true; } } // Buttons options_t options; if (supplied_options.empty()) { options.push_back(std::make_pair(std::string("close"), LLNotifications::instance().getGlobalString("implicitclosebutton"))); // add data for ok button. ButtonData ok_button; mButtonData.push_back(ok_button); mDefaultOption = 0; } else { options = supplied_options; } S32 num_options = options.size(); // Calc total width of buttons S32 button_width = 0; S32 sp = font->getWidth(std::string("OO")); for( S32 i = 0; i < num_options; i++ ) { S32 w = S32(font->getWidth( options[i].second ) + 0.99f) + sp + 2 * LLBUTTON_H_PAD; button_width = llmax( w, button_width ); } S32 btn_total_width = button_width; if( num_options > 1 ) { btn_total_width = (num_options * button_width) + ((num_options - 1) * BTN_HPAD); } // Message: create text box using raw string, as text has been structure deliberately // Use size of created text box to generate dialog box size std::string msg = mNotification->getMessage(); llwarns << "Alert: " << msg << llendl; LLTextBox::Params params; params.name("Alert message"); params.font(font); params.tab_stop(false); params.wrap(true); params.follows.flags(FOLLOWS_LEFT | FOLLOWS_TOP); params.allow_scroll(true); LLTextBox * msg_box = LLUICtrlFactory::create<LLTextBox> (params); // Compute max allowable height for the dialog text, so we can allocate // space before wrapping the text to fit. S32 max_allowed_msg_height = gFloaterView->getRect().getHeight() - LINE_HEIGHT // title bar - 3*VPAD - BTN_HEIGHT; // reshape to calculate real text width and height msg_box->reshape( MAX_ALLOWED_MSG_WIDTH, max_allowed_msg_height ); msg_box->setValue(msg); S32 pixel_width = msg_box->getTextPixelWidth(); S32 pixel_height = msg_box->getTextPixelHeight(); // We should use some space to prevent set textbox's scroller visible when it is unnecessary. msg_box->reshape( llmin(MAX_ALLOWED_MSG_WIDTH,pixel_width + 2 * msg_box->getHPad() + HPAD), llmin(max_allowed_msg_height,pixel_height + 2 * msg_box->getVPad()) ) ; const LLRect& text_rect = msg_box->getRect(); S32 dialog_width = llmax( btn_total_width, text_rect.getWidth() ) + 2 * HPAD; S32 dialog_height = text_rect.getHeight() + 3 * VPAD + BTN_HEIGHT; if (hasTitleBar()) { dialog_height += LINE_HEIGHT; // room for title bar } // it's ok for the edit text body to be empty, but we want the name to exist if we're going to draw it if (!edit_text_name.empty()) { dialog_height += EDITOR_HEIGHT + VPAD; dialog_width = llmax(dialog_width, (S32)(font->getWidth( edit_text_contents ) + 0.99f)); } if (mCaution) { // Make room for the caution icon. dialog_width += 32 + HPAD; } LLToastPanel::reshape( dialog_width, dialog_height, FALSE ); S32 msg_y = LLToastPanel::getRect().getHeight() - VPAD; S32 msg_x = HPAD; if (hasTitleBar()) { msg_y -= LINE_HEIGHT; // room for title } static LLUIColor alert_caution_text_color = LLUIColorTable::instance().getColor("AlertCautionTextColor"); if (mCaution) { LLIconCtrl* icon = LLUICtrlFactory::getInstance()->createFromFile<LLIconCtrl>("alert_icon.xml", this, LLPanel::child_registry_t::instance()); if(icon) { icon->setRect(LLRect(msg_x, msg_y, msg_x+32, msg_y-32)); LLToastPanel::addChild(icon); } msg_x += 32 + HPAD; msg_box->setColor( alert_caution_text_color ); } LLRect rect; rect.setLeftTopAndSize( msg_x, msg_y, text_rect.getWidth(), text_rect.getHeight() ); msg_box->setRect( rect ); LLToastPanel::addChild(msg_box); // (Optional) Edit Box if (!edit_text_name.empty()) { S32 y = VPAD + BTN_HEIGHT + VPAD/2; mLineEditor = LLUICtrlFactory::getInstance()->createFromFile<LLLineEditor>("alert_line_editor.xml", this, LLPanel::child_registry_t::instance()); if (mLineEditor) { LLRect leditor_rect = LLRect( HPAD, y+EDITOR_HEIGHT, dialog_width-HPAD, y); mLineEditor->setName(edit_text_name); mLineEditor->reshape(leditor_rect.getWidth(), leditor_rect.getHeight()); mLineEditor->setRect(leditor_rect); mLineEditor->setMaxTextChars(edit_text_max_chars); mLineEditor->setText(edit_text_contents); // decrease limit of line editor of teleport offer dialog to avoid truncation of // location URL in invitation message, see EXT-6891 if ("OfferTeleport" == mNotification->getName()) { mLineEditor->setMaxTextLength(gSavedSettings.getS32( "teleport_offer_invitation_max_length")); } else { mLineEditor->setMaxTextLength(STD_STRING_STR_LEN - 1); } LLToastPanel::addChild(mLineEditor); mLineEditor->setDrawAsterixes(is_password); setEditTextArgs(notification->getSubstitutions()); mLineEditor->setFollowsLeft(); mLineEditor->setFollowsRight(); // find form text input field LLSD form_text; for (LLSD::array_const_iterator it = form_sd.beginArray(); it != form_sd.endArray(); ++it) { std::string type = (*it)["type"].asString(); if (type == "text") { form_text = (*it); } } // if form text input field has width attribute if (form_text.has("width")) { // adjust floater width to fit line editor S32 editor_width = form_text["width"]; LLRect editor_rect = mLineEditor->getRect(); U32 width_delta = editor_width - editor_rect.getWidth(); LLRect toast_rect = getRect(); reshape(toast_rect.getWidth() + width_delta, toast_rect.getHeight()); } } } // Buttons S32 button_left = (LLToastPanel::getRect().getWidth() - btn_total_width) / 2; for( S32 i = 0; i < num_options; i++ ) { LLRect button_rect; LLButton* btn = LLUICtrlFactory::getInstance()->createFromFile<LLButton>("alert_button.xml", this, LLPanel::child_registry_t::instance()); if(btn) { btn->setName(options[i].first); btn->setRect(button_rect.setOriginAndSize( button_left, VPAD, button_width, BTN_HEIGHT )); btn->setLabel(options[i].second); btn->setFont(font); btn->setClickedCallback(boost::bind(&LLToastAlertPanel::onButtonPressed, this, _2, i)); mButtonData[i].mButton = btn; LLToastPanel::addChild(btn); if( i == mDefaultOption ) { btn->setFocus(TRUE); } } button_left += button_width + BTN_HPAD; } std::string ignore_label; if (form->getIgnoreType() == LLNotificationForm::IGNORE_WITH_DEFAULT_RESPONSE) { setCheckBox(LLNotifications::instance().getGlobalString("skipnexttime"), ignore_label); } else if (form->getIgnoreType() == LLNotificationForm::IGNORE_WITH_LAST_RESPONSE) { setCheckBox(LLNotifications::instance().getGlobalString("alwayschoose"), ignore_label); } // *TODO: check necessity of this code //gFloaterView->adjustToFitScreen(this, FALSE); if (mLineEditor) { mLineEditor->selectAll(); } if(mDefaultOption >= 0) { // delay before enabling default button mDefaultBtnTimer.start(); mDefaultBtnTimer.setTimerExpirySec(DEFAULT_BUTTON_DELAY); } LLTransientFloaterMgr::instance().addControlView( LLTransientFloaterMgr::GLOBAL, this); }
// static bool LLHandlerUtil::isNotificationReusable(const LLNotificationPtr& notification) { return OFFER_FRIENDSHIP == notification->getName() || USER_GIVE_ITEM == notification->getName() || TELEPORT_OFFERED == notification->getName(); }
// static bool LLHandlerUtil::canAddNotifPanelToIM(const LLNotificationPtr& notification) { return OFFER_FRIENDSHIP == notification->getName() || USER_GIVE_ITEM == notification->getName() || TELEPORT_OFFERED == notification->getName(); }
// static bool LLHandlerUtil::canSpawnIMSession(const LLNotificationPtr& notification) { return OFFER_FRIENDSHIP == notification->getName() || USER_GIVE_ITEM == notification->getName() || TELEPORT_OFFERED == notification->getName(); }
// static bool LLHandlerUtil::canLogToIM(const LLNotificationPtr& notification) { return GRANTED_MODIFY_RIGHTS == notification->getName() || REVOKED_MODIFY_RIGHTS == notification->getName() || PAYMENT_RECIVED == notification->getName() || OFFER_FRIENDSHIP == notification->getName() || FRIENDSHIP_OFFERED == notification->getName() || FRIENDSHIP_ACCEPTED == notification->getName() || FRIENDSHIP_ACCEPTED_BYME == notification->getName() || FRIENDSHIP_DECLINED_BYME == notification->getName() || SERVER_OBJECT_MESSAGE == notification->getName() || INVENTORY_ACCEPTED == notification->getName() || INVENTORY_DECLINED == notification->getName() || USER_GIVE_ITEM == notification->getName() || TELEPORT_OFFERED == notification->getName() || TELEPORT_OFFER_SENT == notification->getName() || IM_SYSTEM_MESSAGE_TIP == notification->getName(); }
//-------------------------------------------------------------------------- bool LLTipHandler::processNotification(const LLSD& notify) { if(mChannel.isDead()) { return false; } LLNotificationPtr notification = LLNotifications::instance().find(notify["id"].asUUID()); if(!notification) return false; // arrange a channel on a screen if(!mChannel.get()->getVisible()) { initChannel(); } if(notify["sigtype"].asString() == "add" || notify["sigtype"].asString() == "change") { // archive message in nearby chat if (LLHandlerUtil::canLogToNearbyChat(notification)) { LLHandlerUtil::logToNearbyChat(notification, CHAT_SOURCE_SYSTEM); // don't show toast if Nearby Chat is opened LLFloaterNearbyChat* nearby_chat = LLFloaterNearbyChat::getInstance(); // <FS:Zi> Remove floating chat bar // LLNearbyChatBar* nearby_chat_bar = LLNearbyChatBar::getInstance(); // if (!nearby_chat_bar->isMinimized() && nearby_chat_bar->getVisible() && nearby_chat->getVisible()) if (nearby_chat->getVisible()) // </FS:Zi> { return false; } } std::string session_name = notification->getPayload()["SESSION_NAME"]; const std::string name = notification->getSubstitutions()["NAME"]; const LLUUID agent_id = notification->getSubstitutions()["AGENT-ID"]; if (session_name.empty()) { session_name = name; } LLUUID from_id = notification->getPayload()["from_id"]; if (LLHandlerUtil::canLogToIM(notification)) { // LLHandlerUtil::logToIM(IM_NOTHING_SPECIAL, session_name, name, // notification->getMessage(), from_id, from_id); // [SL:KB] - Patch: Chat-Logs | Checked: 2010-11-18 (Catznip-2.4.0c) | Added: Catznip-2.4.0c LLHandlerUtil::logToIMP2P(notification, false); // [/SL:KB] } if (LLHandlerUtil::canSpawnIMSession(notification)) { LLHandlerUtil::spawnIMSession(name, from_id); } // don't spawn toast for inventory accepted/declined offers if respective IM window is open (EXT-5909) if (!LLHandlerUtil::canSpawnToast(notification)) { return false; } // [FIRE-3522 : SJ] Only show Online/Offline toast when ChatOnlineNotification is enabled or the Friend is one you want to have on/offline notices from if (!gSavedSettings.getBOOL("ChatOnlineNotification") && ("FriendOffline" == notification->getName() || "FriendOnline" == notification->getName())) { // [FIRE-3522 : SJ] Only show Online/Offline toast for groups which have enabled "Show notice for this set" and in the settingpage of CS is checked that the messages need to be in Toasts if (!(gSavedSettings.getBOOL("FSContactSetsNotificationToast") && LGGContactSets::getInstance()->notifyForFriend(agent_id))) { return false; } } LLToastPanel* notify_box = LLToastPanel::buidPanelFromNotification(notification); LLToast::Params p; p.notif_id = notification->getID(); p.notification = notification; p.lifetime_secs = gSavedSettings.getS32("NotificationTipToastLifeTime"); p.panel = notify_box; p.is_tip = true; p.can_be_stored = false; removeExclusiveNotifications(notification); LLScreenChannel* channel = dynamic_cast<LLScreenChannel*>(mChannel.get()); if(channel) channel->addToast(p); } else if (notify["sigtype"].asString() == "delete") { mChannel.get()->killToastByNotificationID(notification->getID()); } return false; }
// internal call, for use in avoiding lookup bool LLNotificationChannelBase::updateItem(const LLSD& payload, LLNotificationPtr pNotification) { std::string cmd = payload["sigtype"]; LLNotificationSet::iterator foundItem = mItems.find(pNotification); bool wasFound = (foundItem != mItems.end()); bool passesFilter = mFilter(pNotification); // first, we offer the result of the filter test to the simple // signals for pass/fail. One of these is guaranteed to be called. // If either signal returns true, the change processing is NOT performed // (so don't return true unless you know what you're doing!) bool abortProcessing = false; if (passesFilter) { abortProcessing = mPassedFilter(payload); } else { abortProcessing = mFailedFilter(payload); } if (abortProcessing) { return true; } if (cmd == "load") { // should be no reason we'd ever get a load if we already have it // if passes filter send a load message, else do nothing assert(!wasFound); if (passesFilter) { // not in our list, add it and say so mItems.insert(pNotification); abortProcessing = mChanged(payload); onLoad(pNotification); } } else if (cmd == "change") { // if it passes filter now and was found, we just send a change message // if it passes filter now and wasn't found, we have to add it // if it doesn't pass filter and wasn't found, we do nothing // if it doesn't pass filter and was found, we need to delete it if (passesFilter) { if (wasFound) { // it already existed, so this is a change // since it changed in place, all we have to do is resend the signal abortProcessing = mChanged(payload); onChange(pNotification); } else { // not in our list, add it and say so mItems.insert(pNotification); // our payload is const, so make a copy before changing it LLSD newpayload = payload; newpayload["sigtype"] = "add"; abortProcessing = mChanged(newpayload); onChange(pNotification); } } else { if (wasFound) { // it already existed, so this is a delete mItems.erase(pNotification); // our payload is const, so make a copy before changing it LLSD newpayload = payload; newpayload["sigtype"] = "delete"; abortProcessing = mChanged(newpayload); onChange(pNotification); } // didn't pass, not on our list, do nothing } } else if (cmd == "add") { // should be no reason we'd ever get an add if we already have it // if passes filter send an add message, else do nothing assert(!wasFound); if (passesFilter) { llinfos << "Inserting " << pNotification->getName() << llendl; // not in our list, add it and say so mItems.insert(pNotification); abortProcessing = mChanged(payload); onAdd(pNotification); } } else if (cmd == "delete") { // if we have it in our list, pass on the delete, then delete it, else do nothing if (wasFound) { abortProcessing = mChanged(payload); mItems.erase(pNotification); onDelete(pNotification); } } return abortProcessing; }