Files
SingularityViewer/indra/newview/llgroupnotify.cpp
Lirusaito e284efa648 Improve notifications a bit (mainly lets you click links in notices)
Actually respect the color they're supposed to be by setting text AFTER creation
Don't double up with setEnabled, we're setting read only through the constructor
Be Mouse Opaque, handle mouse events beyond scrolling, match group notices
Don't call things more than once, that's nonsense.
2019-01-19 05:07:27 -05:00

425 lines
12 KiB
C++

/**
* @file llgroupnotify.cpp
* @brief Non-blocking notification that doesn't take keyboard focus.
*
* $LicenseInfo:firstyear=2006&license=viewergpl$
*
* Copyright (c) 2006-2009, Linden Research, Inc.
*
* Second Life Viewer Source Code
* The source code in this file ("Source Code") is provided by Linden Lab
* to you under the terms of the GNU General Public License, version 2.0
* ("GPL"), unless you have obtained a separate licensing agreement
* ("Other License"), formally executed by you and Linden Lab. Terms of
* the GPL can be found in doc/GPL-license.txt in this distribution, or
* online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
*
* There are special exceptions to the terms and conditions of the GPL as
* it is applied to this Source Code. View the full text of the exception
* in the file doc/FLOSS-exception.txt in this software distribution, or
* online at
* http://secondlifegrid.net/programs/open_source/licensing/flossexception
*
* By copying, modifying or distributing this software, you acknowledge
* that you have read and understood your obligations described above,
* and agree to abide by those obligations.
*
* ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
* WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
* COMPLETENESS OR PERFORMANCE.
* $/LicenseInfo$
*/
#include "llviewerprecompiledheaders.h"
#include "llgroupnotify.h"
#include "llfocusmgr.h"
#include "llbutton.h"
#include "lliconctrl.h"
#include "llfloaterchat.h" // for add_chat_history()
#include "llgroupactions.h"
#include "llnotify.h"
#include "lltextbox.h"
#include "llviewertexteditor.h"
#include "lluiconstants.h"
#include "llui.h"
#include "llviewercontrol.h"
#include "llinventoryicon.h"
#include "llinventory.h"
#include "lltrans.h"
#include "llglheaders.h"
#include "llagent.h"
// Globals
const F32 ANIMATION_TIME = 0.333f;
static S32 sGroupNotifyBoxCount = 0;
//---------------------------------------------------------------------------
// LLGroupNotifyBox
//---------------------------------------------------------------------------
bool is_openable(LLAssetType::EType type)
{
switch(type)
{
case LLAssetType::AT_LANDMARK:
case LLAssetType::AT_NOTECARD:
case LLAssetType::AT_IMAGE_JPEG:
case LLAssetType::AT_IMAGE_TGA:
case LLAssetType::AT_TEXTURE:
case LLAssetType::AT_TEXTURE_TGA:
return true;
default:
return false;
}
}
LLGroupNotifyBox::LLGroupNotifyBox(const std::string& subject,
const std::string& message,
const std::string& from_name,
const LLUUID& group_id,
const LLUUID& group_insignia,
const std::string& group_name,
const LLDate& time_stamp,
const bool& has_inventory,
const std::string& inventory_name,
const LLSD& inventory_offer)
: LLPanel("groupnotify", LLGroupNotifyBox::getGroupNotifyRect(), BORDER_YES),
mAnimating(true),
mTimer(),
mGroupID(group_id),
mHasInventory(has_inventory),
mInventoryOffer(NULL)
{
const S32 VPAD = 2;
const S32 TOP = getRect().getHeight() - 32; // Get past the top menu bar
const S32 BOTTOM_PAD = VPAD * 2;
const S32 BTN_TOP = BOTTOM_PAD + BTN_HEIGHT + VPAD;
const S32 RIGHT = getRect().getWidth() - HPAD - HPAD;
const S32 LINE_HEIGHT = 16;
const S32 LABEL_WIDTH = 64;
const S32 ICON_WIDTH = 64;
time_t timestamp = (time_t)time_stamp.secondsSinceEpoch();
if (!timestamp) time(&timestamp);
std::string time_buf;
timeToFormattedString(timestamp, gSavedSettings.getString("TimestampFormat"), time_buf);
if (mHasInventory)
{
mInventoryOffer = new LLOfferInfo(inventory_offer);
}
setFocusRoot(TRUE);
setFollows(FOLLOWS_TOP|FOLLOWS_RIGHT);
setBackgroundVisible(TRUE);
setBackgroundOpaque(TRUE);
setBackgroundColor( gColors.getColor("GroupNotifyBoxColor") );
S32 y = TOP;
S32 x = HPAD + HPAD;
class NoticeText : public LLTextBox
{
public:
NoticeText(const std::string& name, const LLRect& rect, const std::string& text = LLStringUtil::null, const LLFontGL* font = NULL)
: LLTextBox(name, rect, text, font)
{
setHAlign(LLFontGL::RIGHT);
setFontShadow(LLFontGL::DROP_SHADOW_SOFT);
setBorderVisible(FALSE);
setColor( gColors.getColor("GroupNotifyTextColor") );
setBackgroundColor( gColors.getColor("GroupNotifyBoxColor") );
}
};
// Title
addChild(new NoticeText(std::string("title"),LLRect(x,y,RIGHT - HPAD,y - LINE_HEIGHT),LLTrans::getString("GroupNotifyGroupNotice"),LLFontGL::getFontSansSerifHuge()));
y -= llfloor(1.5f*LINE_HEIGHT);
x += HPAD + HPAD + ICON_WIDTH;
std::stringstream from;
from << LLTrans::getString("GroupNotifySentBy") << " " + from_name << LLTrans::getString(",") + " " << group_name;
addChild(new NoticeText(std::string("group"),LLRect(x,y,RIGHT - HPAD,y - LINE_HEIGHT),from.str(),LLFontGL::getFontSansSerif()));
y -= (LINE_HEIGHT + VPAD);
x = HPAD + HPAD;
// TODO: change this to be the group icon.
LLIconCtrl* icon = new LLIconCtrl(std::string("icon"),
LLRect(x, y, x+ICON_WIDTH, y-ICON_WIDTH),
group_insignia.isNull() ? "notify_box_icon.tga" : group_insignia.asString());
icon->setMouseOpaque(FALSE);
addChild(icon);
x += HPAD + HPAD + ICON_WIDTH;
// If we have inventory with this message, leave room for the name.
S32 box_bottom = BTN_TOP + (mHasInventory ? (LINE_HEIGHT + 2*VPAD) : 0);
LLTextEditor* text = new LLViewerTextEditor(std::string("box"),
LLRect(x, y, RIGHT, box_bottom),
DB_GROUP_NOTICE_MSG_STR_LEN,
LLStringUtil::null,
LLFontGL::getFontSansSerif(),
FALSE,
true);
static const LLStyleSP headerstyle(new LLStyle(true,LLColor4::black,"SansSerifBig"));
static const LLStyleSP datestyle(new LLStyle(true,LLColor4::black,"serif"));
text->appendText(subject + '\n',false,false,headerstyle);
text->appendText(time_buf,false,false,datestyle);
text->appendColoredText(std::string(" \n\n") + message,false,false,LLColor4::grey4);
LLColor4 semi_transparent(1.0f,1.0f,1.0f,0.8f);
text->setCursor(0,0);
text->setWordWrap(TRUE);
//text->setTabStop(FALSE); // was interfering with copy-and-paste
text->setTabsToNextField(TRUE);
text->setMouseOpaque(TRUE);
text->setBorderVisible(TRUE);
text->setTakesNonScrollClicks(TRUE);
text->setHideScrollbarForShortDocs(TRUE);
text->setReadOnlyBgColor ( semi_transparent );
text->setWriteableBgColor ( semi_transparent );
addChild(text);
y = box_bottom - VPAD;
if (mHasInventory)
{
addChild(new NoticeText(std::string("subjecttitle"),LLRect(x,y,x + LABEL_WIDTH,y - LINE_HEIGHT),LLTrans::getString("GroupNotifyAttached"),LLFontGL::getFontSansSerif()));
LLUIImagePtr item_icon = LLInventoryIcon::getIcon(mInventoryOffer->mType,
LLInventoryType::IT_TEXTURE,
0, FALSE);
x += LABEL_WIDTH + HPAD;
std::stringstream ss;
ss << " " << inventory_name;
LLTextBox *line = new LLTextBox(std::string("object_name"),LLRect(x,y,RIGHT - HPAD,y - LINE_HEIGHT),ss.str(),LLFontGL::getFontSansSerif());
line->setEnabled(FALSE);
line->setBorderVisible(TRUE);
line->setDisabledColor(LLColor4::blue4);
line->setFontStyle(LLFontGL::NORMAL);
line->setBackgroundVisible(true);
line->setBackgroundColor( semi_transparent );
addChild(line);
icon = new LLIconCtrl(std::string("icon"),
LLRect(x, y, x+16, y-16),
item_icon->getName());
icon->setMouseOpaque(FALSE);
addChild(icon);
}
mNextBtn = new LLButton(LLTrans::getString("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(&LLGroupNotifyBox::moveToBack, this),
LLFontGL::getFontSansSerif());
mNextBtn->setToolTip(LLTrans::getString("next"));
mNextBtn->setScaleImage(TRUE);
addChild(mNextBtn);
S32 btn_width = 80;
S32 wide_btn_width = 136;
LLRect btn_rect;
x = 3 * HPAD;
btn_rect.setOriginAndSize(x,
BOTTOM_PAD,
btn_width,
BTN_HEIGHT);
LLButton* btn = new LLButton(LLTrans::getString("ok"), btn_rect, LLStringUtil::null, boost::bind(&LLGroupNotifyBox::close, this));
addChild(btn, -1);
setDefaultBtn(btn);
x += btn_width + HPAD;
btn_rect.setOriginAndSize(x,
BOTTOM_PAD,
wide_btn_width,
BTN_HEIGHT);
btn = new LLButton(LLTrans::getString("GroupNotifyGroupNotices"), btn_rect, LLStringUtil::null, boost::bind(LLGroupActions::showTab, mGroupID, "notices_tab"));
btn->setToolTip(LLTrans::getString("GroupNotifyViewPastNotices"));
addChild(btn, -1);
if (mHasInventory)
{
x += wide_btn_width + HPAD;
btn_rect.setOriginAndSize(x,
BOTTOM_PAD,
wide_btn_width,
BTN_HEIGHT);
mSaveInventoryBtn = new LLButton(LLTrans::getString(is_openable(mInventoryOffer->mType) ? "GroupNotifyOpenAttachment" : "GroupNotifySaveAttachment"), btn_rect, LLStringUtil::null, boost::bind(&LLGroupNotifyBox::onClickSaveInventory,this));
mSaveInventoryBtn->setVisible(mHasInventory);
addChild(mSaveInventoryBtn);
}
// If this is the only notify box, don't show the next button
if (++sGroupNotifyBoxCount == 1)
mNextBtn->setVisible(false);
}
// virtual
LLGroupNotifyBox::~LLGroupNotifyBox()
{
sGroupNotifyBoxCount--;
}
// virtual
BOOL LLGroupNotifyBox::handleRightMouseDown(S32 x, S32 y, MASK mask)
{
if (!LLPanel::handleRightMouseDown(x, y, mask))
moveToBack();
return TRUE;
}
// virtual
void LLGroupNotifyBox::draw()
{
F32 display_time = mTimer.getElapsedTimeF32();
if (mAnimating && display_time < ANIMATION_TIME)
{
gGL.matrixMode(LLRender::MM_MODELVIEW);
gGL.pushMatrix();
S32 height = getRect().getHeight();
F32 fraction = display_time / ANIMATION_TIME;
F32 voffset = (1.f - fraction) * height;
gGL.translatef(0.f, voffset, 0.f);
LLPanel::draw();
gGL.popMatrix();
}
else
{
mAnimating = false;
LLPanel::draw();
}
}
void LLGroupNotifyBox::close()
{
// The group notice dialog may be an inventory offer.
// If it has an inventory save button and that button is still enabled
// Then we need to send the inventory declined message
if (mHasInventory)
{
mInventoryOffer->forceResponse(IOR_DECLINE);
mInventoryOffer = NULL;
mHasInventory = false;
}
gNotifyBoxView->removeChild(this);
die();
}
//static
void LLGroupNotifyBox::initClass()
{
LLNotificationChannel::buildChannel("Group Notifications", "Visible", LLNotificationFilters::filterBy<std::string>(&LLNotification::getType, "groupnotify"));
LLNotifications::instance().getChannel("Group Notifications")->connectChanged(&LLGroupNotifyBox::onNewNotification);
}
//static
bool LLGroupNotifyBox::onNewNotification(const LLSD& notify)
{
if (LLNotificationPtr notification = LLNotifications::instance().find(notify["id"].asUUID()))
{
const LLSD& payload = notification->getPayload();
// Get the group data
LLGroupData group_data;
if (!gAgent.getGroupData(payload["group_id"].asUUID(),group_data))
{
LL_WARNS() << "Group notice for unkown group: " << payload["group_id"].asUUID() << LL_ENDL;
return false;
}
gNotifyBoxView->addChild(new LLGroupNotifyBox(payload["subject"].asString(),
payload["message"].asString(),
payload["sender_name"].asString(),
payload["group_id"].asUUID(),
group_data.mInsigniaID,
group_data.mName,
notification->getDate(),
payload["inventory_offer"].isDefined(),
payload["inventory_name"].asString(),
payload["inventory_offer"]));
}
return false;
}
void LLGroupNotifyBox::moveToBack()
{
// Move this dialog to the back.
gNotifyBoxView->removeChild(this);
gNotifyBoxView->addChildInBack(this);
mNextBtn->setVisible(FALSE);
// And enable the next button on the frontmost one, if there is one
if (sGroupNotifyBoxCount > 1)
{
LLView* view = gNotifyBoxView->getFirstChild();
if (view && "groupnotify" == view->getName())
{
LLGroupNotifyBox* front = static_cast<LLGroupNotifyBox*>(view);
if (front->mNextBtn)
{
front->mNextBtn->setVisible(true);
}
}
}
}
// static
LLRect LLGroupNotifyBox::getGroupNotifyRect()
{
S32 notify_height = gSavedSettings.getS32("GroupNotifyBoxHeight");
const S32 NOTIFY_WIDTH = gSavedSettings.getS32("GroupNotifyBoxWidth");
const S32 TOP = gNotifyBoxView->getRect().getHeight();
const S32 RIGHT = gNotifyBoxView->getRect().getWidth();
const S32 LEFT = RIGHT - NOTIFY_WIDTH;
return LLRect(LEFT, TOP, RIGHT, TOP-notify_height);
}
void LLGroupNotifyBox::onClickSaveInventory()
{
mInventoryOffer->forceResponse(IOR_ACCEPT);
mInventoryOffer = NULL;
mHasInventory = false;
// Each item can only be received once, so disable the button.
mSaveInventoryBtn->setEnabled(FALSE);
}