Merging revisions 2046-2068 of https://svn.aws.productengine.com/secondlife/pe/stable-2 into P:\svn\viewer-2.0.0, respecting ancestry

* Bugs: EXT-1414 EXT-1213 EXT-1539 EXT-1253  EXT-1446 EXT-1438 EXT-1233 EXT-1466 EXT-1446 EXT-1512 EXT-1231
* Dev: EXT-719 (landmarks) EXT-747 EXT-1446 EXT-1378 EXT-397 EXT-1476
* IM changes
master
Steven Bennetts 2009-10-19 01:45:44 +00:00
parent 4ee757b45d
commit 8103710c05
72 changed files with 2624 additions and 847 deletions

View File

@ -44,6 +44,9 @@ const LLSD UNSELECTED_EVENT = LLSD().insert("selected", false);
static const std::string COMMENT_TEXTBOX = "comment_text";
//forward declaration
bool llsds_are_equal(const LLSD& llsd_1, const LLSD& llsd_2);
LLFlatListView::Params::Params()
: item_pad("item_pad"),
allow_select("allow_select"),
@ -333,6 +336,17 @@ void LLFlatListView::sort()
rearrangeItems();
}
bool LLFlatListView::updateValue(const LLSD& old_value, const LLSD& new_value)
{
if (old_value.isUndefined() || new_value.isUndefined()) return false;
if (llsds_are_equal(old_value, new_value)) return false;
item_pair_t* item_pair = getItemPair(old_value);
if (!item_pair) return false;
item_pair->second = new_value;
return true;
}
//////////////////////////////////////////////////////////////////////////
// PROTECTED STUFF

View File

@ -273,6 +273,8 @@ public:
void setComparator(const ItemComparator* comp) { mItemComparator = comp; }
void sort();
bool updateValue(const LLSD& old_value, const LLSD& new_value);
protected:
/** Pairs LLpanel representing a single item LLPanel and LLSD associated with it */

View File

@ -1262,6 +1262,12 @@ BOOL LLFloater::offerClickToButton(S32 x, S32 y, MASK mask, EFloaterButtons inde
return FALSE;
}
BOOL LLFloater::handleScrollWheel(S32 x, S32 y, S32 clicks)
{
LLPanel::handleScrollWheel(x,y,clicks);
return TRUE;//always
}
// virtual
BOOL LLFloater::handleMouseDown(S32 x, S32 y, MASK mask)
{

View File

@ -206,6 +206,9 @@ public:
virtual BOOL handleRightMouseDown(S32 x, S32 y, MASK mask);
virtual BOOL handleDoubleClick(S32 x, S32 y, MASK mask);
virtual BOOL handleMiddleMouseDown(S32 x, S32 y, MASK mask);
virtual BOOL handleScrollWheel(S32 x, S32 y, S32 mask);
virtual void draw();
virtual void onOpen(const LLSD& key) {}

View File

@ -409,8 +409,13 @@ BOOL LLScrollbar::handleHover(S32 x, S32 y, MASK mask)
BOOL LLScrollbar::handleScrollWheel(S32 x, S32 y, S32 clicks)
{
changeLine( clicks * mStepSize, TRUE );
return TRUE;
S32 pos = llclamp(mDocPos + clicks * mStepSize, 0, getDocPosMax());
if (pos != mDocPos)
{
setDocPos(pos, TRUE);
return TRUE;
}
return FALSE;
}
BOOL LLScrollbar::handleDragAndDrop(S32 x, S32 y, MASK mask, BOOL drop,

View File

@ -235,6 +235,8 @@ BOOL LLScrollContainer::handleKeyHere(KEY key, MASK mask)
BOOL LLScrollContainer::handleScrollWheel( S32 x, S32 y, S32 clicks )
{
if(LLUICtrl::handleScrollWheel(x,y,clicks))
return TRUE;
for( S32 i = 0; i < SCROLLBAR_COUNT; i++ )
{
// Note: tries vertical and then horizontal
@ -246,9 +248,7 @@ BOOL LLScrollContainer::handleScrollWheel( S32 x, S32 y, S32 clicks )
return TRUE;
}
}
// Eat scroll wheel event (to avoid scrolling nested containers?)
return TRUE;
return FALSE;
}
BOOL LLScrollContainer::handleDragAndDrop(S32 x, S32 y, MASK mask,

View File

@ -672,6 +672,26 @@ LLView* LLView::childrenHandleToolTip(S32 x, S32 y, MASK mask)
}
LLView* LLView::childFromPoint(S32 x, S32 y)
{
if (!getVisible() )
return false;
for ( child_list_iter_t child_it = mChildList.begin(); child_it != mChildList.end(); ++child_it)
{
LLView* viewp = *child_it;
S32 local_x = x - viewp->getRect().mLeft;
S32 local_y = y - viewp->getRect().mBottom;
if (!viewp->pointInView(local_x, local_y)
|| !viewp->getVisible() )
{
continue;
}
return viewp;
}
return 0;
}
BOOL LLView::handleToolTip(S32 x, S32 y, MASK mask)
{
BOOL handled = FALSE;
@ -901,12 +921,6 @@ LLView* LLView::childrenHandleScrollWheel(S32 x, S32 y, S32 clicks)
handled_view = viewp;
break;
}
if (viewp->blockMouseEvent(local_x, local_y))
{
handled_view = viewp;
break;
}
}
}
return handled_view;

View File

@ -445,6 +445,8 @@ public:
/*virtual*/ void screenPointToLocal(S32 screen_x, S32 screen_y, S32* local_x, S32* local_y) const;
/*virtual*/ void localPointToScreen(S32 local_x, S32 local_y, S32* screen_x, S32* screen_y) const;
virtual LLView* childFromPoint(S32 x, S32 y);
// view-specific handlers
virtual void onMouseEnter(S32 x, S32 y, MASK mask);
virtual void onMouseLeave(S32 x, S32 y, MASK mask);

View File

@ -94,6 +94,7 @@ set(viewer_SOURCE_FILES
llchannelmanager.cpp
llchatbar.cpp
llchatitemscontainerctrl.cpp
llchathistory.cpp
llchatmsgbox.cpp
llchiclet.cpp
llclassifiedinfo.cpp
@ -246,6 +247,7 @@ set(viewer_SOURCE_FILES
llinventoryclipboard.cpp
llinventoryfilter.cpp
llinventorymodel.cpp
llinventorysubtreepanel.cpp
lljoystickbutton.cpp
lllandmarkactions.cpp
lllandmarklist.cpp
@ -344,6 +346,7 @@ set(viewer_SOURCE_FILES
llpanelvolume.cpp
llparcelselection.cpp
llpatchvertexarray.cpp
llplacesinventorybridge.cpp
llpolymesh.cpp
llpolymorph.cpp
llpreviewanim.cpp
@ -564,6 +567,7 @@ set(viewer_HEADER_FILES
llchannelmanager.h
llchatbar.h
llchatitemscontainerctrl.h
llchathistory.h
llchatmsgbox.h
llchiclet.h
llclassifiedinfo.h
@ -716,6 +720,7 @@ set(viewer_HEADER_FILES
llinventoryclipboard.h
llinventoryfilter.h
llinventorymodel.h
llinventorysubtreepanel.h
lljoystickbutton.h
lllandmarkactions.h
lllandmarklist.h
@ -811,6 +816,7 @@ set(viewer_HEADER_FILES
llpanelvolume.h
llparcelselection.h
llpatchvertexarray.h
llplacesinventorybridge.h
llpolymesh.h
llpolymorph.h
llpreview.h

View File

@ -181,16 +181,6 @@ LLAvatarIconCtrl::LLAvatarIconCtrl(const LLAvatarIconCtrl::Params& p)
rect.setOriginAndSize(left, bottom, llavatariconctrl_symbol_size, llavatariconctrl_symbol_size);
LLIconCtrl::Params icparams;
icparams.name ("Status Symbol");
icparams.follows.flags (FOLLOWS_RIGHT | FOLLOWS_BOTTOM);
icparams.rect (rect);
mStatusSymbol = LLUICtrlFactory::create<LLIconCtrl> (icparams);
mStatusSymbol->setValue("circle.tga");
mStatusSymbol->setColor(LLColor4::grey);
addChild(mStatusSymbol);
if (p.avatar_id.isProvided())
{
LLSD value(p.avatar_id);
@ -239,16 +229,13 @@ void LLAvatarIconCtrl::setValue(const LLSD& value)
mAvatarId = value.asUUID();
// *BUG: This will return stale icons if a user changes their
// profile picture. Also, the online/offline tooltips will be
// out of date. However, otherwise we send too many upstream
// profile picture. However, otherwise we send too many upstream
// AvatarPropertiesRequest messages.
//
// *TODO: Implement a timeout on the icon cache, perhaps a day?,
// and make the cache update if a user views the full-profile for
// an avatar.
// to get fresh avatar icon use
// LLAvatarIconIDCache::getInstance()->remove(avatar_id);
// Check if cache already contains image_id for that avatar
if (!updateFromCache())
{
app->addObserver(mAvatarId, this);
@ -282,36 +269,6 @@ bool LLAvatarIconCtrl::updateFromCache()
LLIconCtrl::setValue("default_profile_picture.j2c");
}
// Can only see online status of friends
if (LLAvatarTracker::instance().isBuddy(mAvatarId))
{
if (LLAvatarTracker::instance().isBuddyOnline(mAvatarId))
{
// Update color of status symbol and tool tip
mStatusSymbol->setColor(LLColor4::green);
if (mDrawTooltip)
{
setToolTip((LLStringExplicit)"Online");
}
}
else
{
mStatusSymbol->setColor(LLColor4::grey);
if (mDrawTooltip)
{
setToolTip((LLStringExplicit)"Offline");
}
}
}
else
{
// Not a buddy, no information
mStatusSymbol->setColor(LLColor4::grey);
if (mDrawTooltip)
{
setToolTip((LLStringExplicit)"");
}
}
return true;
}
@ -370,6 +327,11 @@ void LLAvatarIconCtrl::nameUpdatedCallback(
{
mFirstName = first;
mLastName = last;
if (mDrawTooltip)
{
setToolTip(mFirstName + " " + mLastName);
}
}
}

View File

@ -104,7 +104,6 @@ public:
const std::string& getLastName() const { return mLastName; }
protected:
LLIconCtrl* mStatusSymbol;
LLUUID mAvatarId;
std::string mFirstName;
std::string mLastName;

View File

@ -202,6 +202,7 @@ void LLAvatarList::addNewItem(const LLUUID& id, const std::string& name, BOOL is
item->showSpeakingIndicator(true);
item->setName(name);
item->setAvatarId(id);
item->setOnline(is_bold);
item->setContextMenu(mContextMenu);
item->childSetVisible("info_btn", false);

View File

@ -52,11 +52,17 @@ LLAvatarListItem::LLAvatarListItem()
mInfoBtn(NULL),
mProfileBtn(NULL),
mContextMenu(NULL),
mAvatarId(LLUUID::null)
mOnlineStatus(E_UNKNOWN)
{
LLUICtrlFactory::getInstance()->buildPanel(this, "panel_avatar_list_item.xml");
}
LLAvatarListItem::~LLAvatarListItem()
{
if (mAvatarId.notNull())
LLAvatarTracker::instance().removeParticularFriendObserver(mAvatarId, this);
}
BOOL LLAvatarListItem::postBuild()
{
mAvatarIcon = getChild<LLAvatarIconCtrl>("avatar_icon");
@ -138,6 +144,36 @@ void LLAvatarListItem::setStatus(const std::string& status)
mStatus->setValue(status);
}
// virtual, called by LLAvatarTracker
void LLAvatarListItem::changed(U32 mask)
{
// no need to check mAvatarId for null in this case
setOnline(LLAvatarTracker::instance().isBuddyOnline(mAvatarId));
}
void LLAvatarListItem::setOnline(bool online)
{
// *FIX: setName() overrides font style set by setOnline(). Not an issue ATM.
// *TODO: Make the colors configurable via XUI.
if (mOnlineStatus != E_UNKNOWN && (bool) mOnlineStatus == online)
return;
mOnlineStatus = (EOnlineStatus) online;
// Change avatar name font style depending on the new online status.
LLStyle::Params style_params;
style_params.color = online ? LLColor4::white : LLColor4::grey;
// Rebuild the text to change its style.
std::string text = mAvatarName->getText();
mAvatarName->setText(LLStringUtil::null);
mAvatarName->appendText(text, false, style_params);
// Make the icon fade if the avatar goes offline.
mAvatarIcon->setColor(online ? LLColor4::white : LLColor4::smoke);
}
void LLAvatarListItem::setName(const std::string& name)
{
mAvatarName->setValue(name);
@ -146,10 +182,17 @@ void LLAvatarListItem::setName(const std::string& name)
void LLAvatarListItem::setAvatarId(const LLUUID& id)
{
if (mAvatarId.notNull())
LLAvatarTracker::instance().removeParticularFriendObserver(mAvatarId, this);
mAvatarId = id;
mAvatarIcon->setValue(id);
mSpeakingIndicator->setSpeakerId(id);
// We'll be notified on avatar online status changes
if (mAvatarId.notNull())
LLAvatarTracker::instance().addParticularFriendObserver(mAvatarId, this);
// Set avatar name.
gCacheName->get(id, FALSE, boost::bind(&LLAvatarListItem::onNameCache, this, _2, _3));
}

View File

@ -38,9 +38,11 @@
#include "llbutton.h"
#include "lltextbox.h"
#include "llcallingcard.h" // for LLFriendObserver
class LLAvatarIconCtrl;
class LLAvatarListItem : public LLPanel
class LLAvatarListItem : public LLPanel, public LLFriendObserver
{
public:
class ContextMenu
@ -50,15 +52,17 @@ public:
};
LLAvatarListItem();
virtual ~LLAvatarListItem() {};
virtual ~LLAvatarListItem();
virtual BOOL postBuild();
virtual void onMouseLeave(S32 x, S32 y, MASK mask);
virtual void onMouseEnter(S32 x, S32 y, MASK mask);
virtual BOOL handleRightMouseDown(S32 x, S32 y, MASK mask);
virtual void setValue(const LLSD& value);
virtual void changed(U32 mask); // from LLFriendObserver
void setStatus(const std::string& status);
void setOnline(bool online);
void setName(const std::string& name);
void setAvatarId(const LLUUID& id);
@ -75,6 +79,13 @@ public:
void setContextMenu(ContextMenu* menu) { mContextMenu = menu; }
private:
typedef enum e_online_status {
E_OFFLINE,
E_ONLINE,
E_UNKNOWN,
} EOnlineStatus;
void onNameCache(const std::string& first_name, const std::string& last_name);
LLAvatarIconCtrl*mAvatarIcon;
@ -87,6 +98,7 @@ private:
ContextMenu* mContextMenu;
LLUUID mAvatarId;
EOnlineStatus mOnlineStatus;
};
#endif //LL_LLAVATARLISTITEM_H

View File

@ -185,6 +185,18 @@ void LLBottomTray::sessionRemoved(const LLUUID& session_id)
}
}
void LLBottomTray::sessionIDUpdated(const LLUUID& old_session_id, const LLUUID& new_session_id)
{
//this is only needed in case of outgoing ad-hoc/group chat sessions
LLChicletPanel* chiclet_panel = getChicletPanel();
if (chiclet_panel)
{
//it should be ad-hoc im chiclet or group im chiclet
LLChiclet* chiclet = chiclet_panel->findChiclet<LLChiclet>(old_session_id);
if (chiclet) chiclet->setSessionId(new_session_id);
}
}
//virtual
void LLBottomTray::onFocusLost()
{

View File

@ -67,6 +67,7 @@ public:
// LLIMSessionObserver observe triggers
virtual void sessionAdded(const LLUUID& session_id, const std::string& name, const LLUUID& other_participant_id);
virtual void sessionRemoved(const LLUUID& session_id);
void sessionIDUpdated(const LLUUID& old_session_id, const LLUUID& new_session_id);
virtual void onFocusLost();
virtual void setVisible(BOOL visible);

View File

@ -260,7 +260,7 @@ S32 LLAvatarTracker::addBuddyList(const LLAvatarTracker::buddy_map_t& buds)
++new_buddy_count;
mBuddyInfo[agent_id] = (*itr).second;
gCacheName->getName(agent_id, first, last);
mModifyMask |= LLFriendObserver::ADD;
addChangedMask(LLFriendObserver::ADD, agent_id);
lldebugs << "Added buddy " << agent_id
<< ", " << (mBuddyInfo[agent_id]->isOnline() ? "Online" : "Offline")
<< ", TO: " << mBuddyInfo[agent_id]->getRightsGrantedTo()
@ -333,7 +333,7 @@ void LLAvatarTracker::setBuddyOnline(const LLUUID& id, bool is_online)
if(info)
{
info->online(is_online);
mModifyMask |= LLFriendObserver::ONLINE;
addChangedMask(LLFriendObserver::ONLINE, id);
lldebugs << "Set buddy " << id << (is_online ? " Online" : " Offline") << llendl;
}
else
@ -488,10 +488,52 @@ void LLAvatarTracker::notifyObservers()
{
(*it)->changed(mModifyMask);
}
for (changed_buddy_t::iterator it = mChangedBuddyIDs.begin(); it != mChangedBuddyIDs.end(); it++)
{
notifyParticularFriendObservers(*it);
}
mModifyMask = LLFriendObserver::NONE;
mChangedBuddyIDs.clear();
}
void LLAvatarTracker::addParticularFriendObserver(const LLUUID& buddy_id, LLFriendObserver* observer)
{
if (buddy_id.notNull() && observer)
mParticularFriendObserverMap[buddy_id].insert(observer);
}
void LLAvatarTracker::removeParticularFriendObserver(const LLUUID& buddy_id, LLFriendObserver* observer)
{
if (buddy_id.isNull() || !observer)
return;
observer_map_t::iterator obs_it = mParticularFriendObserverMap.find(buddy_id);
if(obs_it == mParticularFriendObserverMap.end())
return;
obs_it->second.erase(observer);
// purge empty sets from the map
if (obs_it->second.size() == 0)
mParticularFriendObserverMap.erase(obs_it);
}
void LLAvatarTracker::notifyParticularFriendObservers(const LLUUID& buddy_id)
{
observer_map_t::iterator obs_it = mParticularFriendObserverMap.find(buddy_id);
if(obs_it == mParticularFriendObserverMap.end())
return;
// Notify observers interested in buddy_id.
observer_set_t& obs = obs_it->second;
for (observer_set_t::iterator ob_it = obs.begin(); ob_it != obs.end(); ob_it++)
{
(*ob_it)->changed(mModifyMask);
}
}
// store flag for change
// and id of object change applies to
void LLAvatarTracker::addChangedMask(U32 mask, const LLUUID& referent)
@ -610,8 +652,8 @@ void LLAvatarTracker::processChange(LLMessageSystem* msg)
}
}
}
mModifyMask |= LLFriendObserver::POWERS;
addChangedMask(LLFriendObserver::POWERS, agent_id);
notifyObservers();
}

View File

@ -150,6 +150,12 @@ public:
void removeObserver(LLFriendObserver* observer);
void notifyObservers();
// Observers interested in updates of a particular avatar.
// On destruction these observers are NOT deleted.
void addParticularFriendObserver(const LLUUID& buddy_id, LLFriendObserver* observer);
void removeParticularFriendObserver(const LLUUID& buddy_id, LLFriendObserver* observer);
void notifyParticularFriendObservers(const LLUUID& buddy_id);
/**
* Stores flag for change and id of object change applies to
*
@ -199,6 +205,10 @@ protected:
typedef std::vector<LLFriendObserver*> observer_list_t;
observer_list_t mObservers;
typedef std::set<LLFriendObserver*> observer_set_t;
typedef std::map<LLUUID, observer_set_t> observer_map_t;
observer_map_t mParticularFriendObserverMap;
private:
// do not implement
LLAvatarTracker(const LLAvatarTracker&);

View File

@ -0,0 +1,126 @@
/**
* @file llchathistory.cpp
* @brief LLTextEditor base class
*
* $LicenseInfo:firstyear=2001&license=viewergpl$
*
* Copyright (c) 2001-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 "llchathistory.h"
#include "llpanel.h"
#include "lltextbox.h"
#include "lluictrlfactory.h"
#include "llscrollcontainer.h"
#include "llavatariconctrl.h"
static LLDefaultChildRegistry::Register<LLChatHistory> r("chat_history");
static const std::string MESSAGE_USERNAME_DATE_SEPARATOR(" ----- ");
LLChatHistory::LLChatHistory(const LLChatHistory::Params& p)
: LLTextEditor(p),
mMessageHeaderFilename(p.message_header),
mMessageSeparatorFilename(p.message_separator),
mLeftTextPad(p.left_text_pad),
mRightTextPad(p.right_text_pad),
mLeftWidgetPad(p.left_widget_pad),
mRightWidgetPad(p.rigth_widget_pad)
{
}
LLChatHistory::~LLChatHistory()
{
this->clear();
}
/*void LLChatHistory::updateTextRect()
{
static LLUICachedControl<S32> texteditor_border ("UITextEditorBorder", 0);
LLRect old_text_rect = mTextRect;
mTextRect = mScroller->getContentWindowRect();
mTextRect.stretch(-texteditor_border);
mTextRect.mLeft += mLeftTextPad;
mTextRect.mRight -= mRightTextPad;
if (mTextRect != old_text_rect)
{
needsReflow();
}
}*/
LLView* LLChatHistory::getSeparator()
{
LLPanel* separator = LLUICtrlFactory::getInstance()->createFromFile<LLPanel>(mMessageSeparatorFilename, NULL, LLPanel::child_registry_t::instance());
return separator;
}
LLView* LLChatHistory::getHeader(const LLUUID& avatar_id, std::string& from, std::string& time)
{
LLPanel* header = LLUICtrlFactory::getInstance()->createFromFile<LLPanel>(mMessageHeaderFilename, NULL, LLPanel::child_registry_t::instance());
LLTextBox* userName = header->getChild<LLTextBox>("user_name");
userName->setValue(from);
LLTextBox* timeBox = header->getChild<LLTextBox>("time_box");
timeBox->setValue(time);
if(!avatar_id.isNull())
{
LLAvatarIconCtrl* icon = header->getChild<LLAvatarIconCtrl>("avatar_icon");
icon->setValue(avatar_id);
}
return header;
}
void LLChatHistory::appendWidgetMessage(const LLUUID& avatar_id, std::string& from, std::string& time, std::string& message, LLStyle::Params& style_params)
{
LLView* view = NULL;
std::string view_text;
if (mLastFromName == from)
{
view = getSeparator();
view_text = "\n";
}
else
{
view = getHeader(avatar_id, from, time);
view_text = from + MESSAGE_USERNAME_DATE_SEPARATOR + time;
}
//Prepare the rect for the view
LLRect target_rect = mScroller->getContentWindowRect();
target_rect.mLeft += mLeftWidgetPad;
target_rect.mRight -= mRightWidgetPad;
view->reshape(target_rect.getWidth(), view->getRect().getHeight());
view->setOrigin(target_rect.mLeft, view->getRect().mBottom);
this->appendWidget(view, view_text, FALSE, TRUE);
//Append the text message
this->appendText(message, TRUE, style_params);
mLastFromName = from;
this->blockUndo();
this->setCursorAndScrollToEnd();
}

View File

@ -0,0 +1,112 @@
/**
* @file llchathistory.h
* @brief LLTextEditor base class
*
* $LicenseInfo:firstyear=2001&license=viewergpl$
*
* Copyright (c) 2001-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$
*/
#ifndef LLCHATHISTORY_H_
#define LLCHATHISTORY_H_
#include "lltexteditor.h"
//Chat log widget allowing addition of a message as a widget
class LLChatHistory : public LLTextEditor
{
public:
struct Params : public LLInitParam::Block<Params, LLTextEditor::Params>
{
//Message header filename
Optional<std::string> message_header;
//Message separator filename
Optional<std::string> message_separator;
//Text left padding from the scroll rect
Optional<S32> left_text_pad;
//Text right padding from the scroll rect
Optional<S32> right_text_pad;
//Widget left padding from the scroll rect
Optional<S32> left_widget_pad;
//Widget right padding from the scroll rect
Optional<S32> rigth_widget_pad;
Params()
: message_header("message_header"),
message_separator("message_separator"),
left_text_pad("left_text_pad"),
right_text_pad("right_text_pad"),
left_widget_pad("left_widget_pad"),
rigth_widget_pad("rigth_widget_pad")
{
}
};
protected:
LLChatHistory(const Params&);
friend class LLUICtrlFactory;
/**
* Redefinition of LLTextEditor::updateTextRect() to considerate text
* left/right padding params.
*/
//virtual void updateTextRect();
/**
* Builds a message separator.
* @return pointer to LLView separator object.
*/
LLView* getSeparator();
/**
* Builds a message header.
* @param from owner of a message.
* @param time time of a message.
* @return pointer to LLView header object.
*/
LLView* getHeader(const LLUUID& avatar_id, std::string& from, std::string& time);
public:
~LLChatHistory();
/**
* Appends a widget message.
* If last user appended message, concurs with current user,
* separator is added before the message, otherwise header is added.
* @param from owner of a message.
* @param time time of a message.
* @param message message itself.
*/
void appendWidgetMessage(const LLUUID& avatar_id, std::string& from, std::string& time, std::string& message, LLStyle::Params& style_params);
private:
std::string mLastFromName;
std::string mMessageHeaderFilename;
std::string mMessageSeparatorFilename;
S32 mLeftTextPad;
S32 mRightTextPad;
S32 mLeftWidgetPad;
S32 mRightWidgetPad;
};
#endif /* LLCHATHISTORY_H_ */

View File

@ -1161,6 +1161,7 @@ LLUIImagePtr get_item_icon(LLAssetType::EType asset_type,
const std::string LLInventoryPanel::DEFAULT_SORT_ORDER = std::string("InventorySortOrder");
const std::string LLInventoryPanel::RECENTITEMS_SORT_ORDER = std::string("RecentItemsSortOrder");
const std::string LLInventoryPanel::INHERIT_SORT_ORDER = std::string("");
static const LLInventoryFVBridgeBuilder INVENTORY_BRIDGE_BUILDER;
LLInventoryPanel::LLInventoryPanel(const LLInventoryPanel::Params& p)
: LLPanel(p),
@ -1172,7 +1173,12 @@ LLInventoryPanel::LLInventoryPanel(const LLInventoryPanel::Params& p)
mAllowMultiSelect(p.allow_multi_select),
mHasInventoryConnection(false),
mStartFolderString(p.start_folder)
, mBuildDefaultHierarchy(true)
, mRootInventoryItemUUID(LLUUID::null)
, mInvFVBridgeBuilder(NULL)
{
mInvFVBridgeBuilder = &INVENTORY_BRIDGE_BUILDER;
// contex menu callbacks
mCommitCallbackRegistrar.add("Inventory.DoToSelected", boost::bind(&LLInventoryPanel::doToSelected, this, _2));
mCommitCallbackRegistrar.add("Inventory.EmptyTrash", boost::bind(&LLInventoryModel::emptyFolderType, &gInventory, "ConfirmEmptyTrash", LLAssetType::AT_TRASH));
@ -1237,8 +1243,8 @@ BOOL LLInventoryPanel::postBuild()
const LLAssetType::EType preferred_type = LLAssetType::lookupHumanReadable(mStartFolderString);
mStartFolderID = (preferred_type != LLAssetType::AT_NONE ? gInventory.findCategoryUUIDForType(preferred_type) : LLUUID::null);
// build view of inventory if inventory ready, otherwise wait for modelChanged() callback
if (mInventory->isInventoryUsable() && !mHasInventoryConnection)
// build view of inventory if we need default full hierarchy and inventory ready, otherwise wait for modelChanged() callback
if (mBuildDefaultHierarchy && mInventory->isInventoryUsable() && !mHasInventoryConnection)
{
rebuildViewsFor(mStartFolderID);
mHasInventoryConnection = true;
@ -1456,6 +1462,25 @@ void LLInventoryPanel::modelChanged(U32 mask)
}
}
void LLInventoryPanel::setInvFVBridgeBuilder(const LLInventoryFVBridgeBuilder* bridge_builder)
{
if (NULL == bridge_builder)
{
llwarns << "NULL is passed as Inventory Bridge Builder. Default will be used." << llendl;
}
else
{
mInvFVBridgeBuilder = bridge_builder;
}
if (mInventory->isInventoryUsable() && !mHasInventoryConnection)
{
rebuildViewsFor(mRootInventoryItemUUID);
mHasInventoryConnection = true;
}
}
void LLInventoryPanel::rebuildViewsFor(const LLUUID& id)
{
LLFolderViewItem* old_view = NULL;
@ -1493,11 +1518,11 @@ void LLInventoryPanel::buildNewViews(const LLUUID& id)
else if (objectp->getType() == LLAssetType::AT_CATEGORY &&
objectp->getActualType() != LLAssetType::AT_LINK_FOLDER)
{
LLInvFVBridge* new_listener = LLInvFVBridge::createBridge(objectp->getType(),
objectp->getType(),
LLInventoryType::IT_CATEGORY,
this,
objectp->getUUID());
LLInvFVBridge* new_listener = mInvFVBridgeBuilder->createBridge(objectp->getType(),
objectp->getType(),
LLInventoryType::IT_CATEGORY,
this,
objectp->getUUID());
if (new_listener)
{
@ -1516,12 +1541,12 @@ void LLInventoryPanel::buildNewViews(const LLUUID& id)
{
// Build new view for item
LLInventoryItem* item = (LLInventoryItem*)objectp;
LLInvFVBridge* new_listener = LLInvFVBridge::createBridge(item->getType(),
item->getActualType(),
item->getInventoryType(),
this,
item->getUUID(),
item->getFlags());
LLInvFVBridge* new_listener = mInvFVBridgeBuilder->createBridge(item->getType(),
item->getActualType(),
item->getInventoryType(),
this,
item->getUUID(),
item->getFlags());
if (new_listener)
{

View File

@ -57,6 +57,7 @@ class LLFolderViewItem;
class LLInventoryFilter;
class LLInventoryModel;
class LLInvFVBridge;
class LLInventoryFVBridgeBuilder;
class LLMenuBarGL;
class LLCheckBoxCtrl;
class LLSpinCtrl;
@ -110,7 +111,7 @@ protected:
friend class LLUICtrlFactory;
public:
~LLInventoryPanel();
virtual ~LLInventoryPanel();
LLInventoryModel* getModel() { return mInventory; }
@ -172,7 +173,10 @@ public:
protected:
// Given the id and the parent, build all of the folder views.
void rebuildViewsFor(const LLUUID& id);
void buildNewViews(const LLUUID& id);
virtual void buildNewViews(const LLUUID& id); // made virtual to support derived classes. EXT-719
// Be sure that passed pointer will be destroyed where it was created.
void setInvFVBridgeBuilder(const LLInventoryFVBridgeBuilder* bridge_builder);
protected:
LLInventoryModel* mInventory;
@ -180,12 +184,34 @@ protected:
BOOL mAllowMultiSelect;
std::string mSortOrderSetting;
private:
//private: // Can not make these private - needed by llinventorysubtreepanel
LLFolderView* mFolders;
std::string mStartFolderString;
LLUUID mStartFolderID;
LLScrollContainer* mScroller;
bool mHasInventoryConnection;
/**
* Flag specified if default inventory hierarchy should be created in postBuild()
*/
bool mBuildDefaultHierarchy;
/**
* Contains UUID of Inventory item from which hierarchy should be built.
* Should be set by derived class before modelChanged() is called.
* Default is LLUUID::null that means total Inventory hierarchy.
*/
LLUUID mRootInventoryItemUUID;
/**
* Pointer to LLInventoryFVBridgeBuilder.
*
* It is set in LLInventoryPanel's constructor and can be overridden in derived classes with
* another implementation.
* Take into account it will not be deleted by LLInventoryPanel itself.
*/
const LLInventoryFVBridgeBuilder* mInvFVBridgeBuilder;
};
class LLFloaterInventory;

View File

@ -190,6 +190,8 @@ LLFolderView::LLFolderView(const Params& p)
mDragAndDropThisFrame(FALSE),
mCallbackRegistrar(NULL),
mParentPanel(p.parent_panel)
, mUseEllipses(false)
, mDraggingOverItem(NULL)
{
LLRect rect = p.rect;
LLRect new_rect(rect.mLeft, rect.mBottom + getRect().getHeight(), rect.mLeft + getRect().getWidth(), rect.mBottom);
@ -481,6 +483,11 @@ void LLFolderView::reshape(S32 width, S32 height, BOOL called_from_parent)
scroll_rect = mScrollContainer->getContentWindowRect();
}
width = llmax(mMinWidth, scroll_rect.getWidth());
// restrict width with scroll container's width
if (mUseEllipses)
width = scroll_rect.getWidth();
LLView::reshape(width, height, called_from_parent);
mReshapeSignal(mSelectedItems, FALSE);
@ -1224,12 +1231,42 @@ void LLFolderView::copy()
BOOL LLFolderView::canCut() const
{
return FALSE;
if (!(getVisible() && getEnabled() && (mSelectedItems.size() > 0)))
{
return FALSE;
}
for (selected_items_t::const_iterator selected_it = mSelectedItems.begin(); selected_it != mSelectedItems.end(); ++selected_it)
{
const LLFolderViewItem* item = *selected_it;
const LLFolderViewEventListener* listener = item->getListener();
if (!listener || !listener->isItemMovable())
{
return FALSE;
}
}
return TRUE;
}
void LLFolderView::cut()
{
// implement Windows-style cut-and-leave
// clear the inventory clipboard
LLInventoryClipboard::instance().reset();
S32 count = mSelectedItems.size();
if(getVisible() && getEnabled() && (count > 0))
{
LLFolderViewEventListener* listener = NULL;
selected_items_t::iterator item_it;
for (item_it = mSelectedItems.begin(); item_it != mSelectedItems.end(); ++item_it)
{
listener = (*item_it)->getListener();
if(listener)
{
listener->cutToClipboard();
}
}
}
mSearchString.clear();
}
BOOL LLFolderView::canPaste() const

View File

@ -180,6 +180,9 @@ public:
BOOL startDrag(LLToolDragAndDrop::ESource source);
void setDragAndDropThisFrame() { mDragAndDropThisFrame = TRUE; }
void setDraggingOverItem(LLFolderViewItem* item) { mDraggingOverItem = item; }
LLFolderViewItem* getDraggingOverItem() { return mDraggingOverItem; }
// deletion functionality
void removeSelectedItems();
@ -248,6 +251,8 @@ public:
void setShowSingleSelection(BOOL show);
BOOL getShowSingleSelection() { return mShowSingleSelection; }
F32 getSelectionFadeElapsedTime() { return mMultiSelectionFadeTimer.getElapsedTimeF32(); }
void setUseEllipses(bool use_ellipses) { mUseEllipses = use_ellipses; }
bool getUseEllipses() { return mUseEllipses; }
void addItemID(const LLUUID& id, LLFolderViewItem* itemp);
void removeItemID(const LLUUID& id);
@ -327,6 +332,17 @@ protected:
LLPanel* mParentPanel;
/**
* Is used to determine if we need to cut text In LLFolderViewItem to avoid horizontal scroll.
* NOTE: For now it uses only to cut LLFolderViewItem::mLabel text to be used for Landmarks in Places Panel.
*/
bool mUseEllipses; // See EXT-719
/**
* Contains item under mouse pointer while dragging
*/
LLFolderViewItem* mDraggingOverItem; // See EXT-719
LLUICtrl::CommitCallbackRegistry::ScopedRegistrar* mCallbackRegistrar;
public:

View File

@ -68,7 +68,7 @@ public:
virtual void showProperties(void) = 0;
virtual BOOL isItemRenameable() const = 0;
virtual BOOL renameItem(const std::string& new_name) = 0;
virtual BOOL isItemMovable( void ) = 0; // Can be moved to another folder
virtual BOOL isItemMovable( void ) const = 0; // Can be moved to another folder
virtual BOOL isItemRemovable( void ) = 0; // Can be destroyed
virtual BOOL removeItem() = 0;
virtual void removeBatch(LLDynamicArray<LLFolderViewEventListener*>& batch) = 0;

View File

@ -36,6 +36,7 @@
// viewer includes
#include "llfolderview.h" // Items depend extensively on LLFolderViews
#include "llfoldervieweventlistener.h"
#include "llinventorybridge.h" // for LLItemBridge in LLInventorySort::operator()
#include "llinventoryfilter.h"
#include "llinventorymodel.h" // *TODO: make it take a pointer to an inventory-model interface
#include "llviewercontrol.h" // gSavedSettings
@ -130,6 +131,7 @@ LLFolderViewItem::LLFolderViewItem(LLFolderViewItem::Params p)
mListener(p.listener),
mArrowImage(p.folder_arrow_image),
mBoxImage(p.selection_image)
, mDontShowInHierarhy(false)
{
refresh();
}
@ -312,7 +314,12 @@ void LLFolderViewItem::arrangeFromRoot()
S32 height = 0;
S32 width = 0;
root->arrange( &width, &height, 0 );
S32 total_height = root->arrange( &width, &height, 0 );
LLSD params;
params["action"] = "size_changes";
params["height"] = total_height;
getParent()->notifyParent(params);
}
// Utility function for LLFolderView
@ -385,12 +392,22 @@ S32 LLFolderViewItem::arrange( S32* width, S32* height, S32 filter_generation)
}
*width = llmax(*width, mLabelWidth + mIndentation);
// determine if we need to use ellipses to avoid horizontal scroll. EXT-719
bool use_ellipses = getRoot()->getUseEllipses();
if (use_ellipses)
{
// limit to set rect to avoid horizontal scrollbar
*width = llmin(*width, getRoot()->getRect().getWidth());
}
*height = getItemHeight();
return *height;
}
S32 LLFolderViewItem::getItemHeight()
{
if (mDontShowInHierarhy) return 0;
S32 icon_height = mIcon->getHeight();
S32 label_height = llround(getLabelFontForStyle(mLabelStyle)->getLineHeight());
return llmax( icon_height, label_height ) + ICON_PAD;
@ -781,7 +798,10 @@ BOOL LLFolderViewItem::handleDragAndDrop(S32 x, S32 y, MASK mask, BOOL drop,
}
if(mParentFolder && !handled)
{
// store this item to get it in LLFolderBridge::dragItemIntoFolder on drop event.
mRoot->setDraggingOverItem(this);
handled = mParentFolder->handleDragAndDropFromChild(mask,drop,cargo_type,cargo_data,accept,tooltip_msg);
mRoot->setDraggingOverItem(NULL);
}
if (handled)
{
@ -794,6 +814,8 @@ BOOL LLFolderViewItem::handleDragAndDrop(S32 x, S32 y, MASK mask, BOOL drop,
void LLFolderViewItem::draw()
{
if (mDontShowInHierarhy) return;
static LLUIColor sFgColor = LLUIColorTable::instance().getColor("MenuItemEnabledColor", DEFAULT_WHITE);
static LLUIColor sHighlightBgColor = LLUIColorTable::instance().getColor("MenuItemHighlightBgColor", DEFAULT_WHITE);
static LLUIColor sHighlightFgColor = LLUIColorTable::instance().getColor("MenuItemHighlightFgColor", DEFAULT_WHITE);
@ -948,7 +970,8 @@ void LLFolderViewItem::draw()
font->renderUTF8( mLabel, 0, text_left, y, color,
LLFontGL::LEFT, LLFontGL::BOTTOM, LLFontGL::NORMAL, LLFontGL::NO_SHADOW,
S32_MAX, S32_MAX, &right_x, FALSE );
S32_MAX, getRect().getWidth() - (S32) text_left, &right_x, TRUE);
if (!mLabelSuffix.empty())
{
font->renderUTF8( mLabelSuffix, 0, right_x, y, sSuffixColor,
@ -2456,6 +2479,28 @@ bool LLInventorySort::updateSort(U32 order)
bool LLInventorySort::operator()(const LLFolderViewItem* const& a, const LLFolderViewItem* const& b)
{
// ignore sort order for landmarks in the Favorites folder.
// they should be always sorted as in Favorites bar. See EXT-719
if (a->getSortGroup() == SG_ITEM && b->getSortGroup() == SG_ITEM
&& a->getListener()->getInventoryType() == LLInventoryType::IT_LANDMARK
&& b->getListener()->getInventoryType() == LLInventoryType::IT_LANDMARK)
{
static LLUUID favorites_folder_id = gInventory.findCategoryUUIDForType(LLAssetType::AT_FAVORITE);
LLUUID a_uuid = a->getParentFolder()->getListener()->getUUID();
LLUUID b_uuid = b->getParentFolder()->getListener()->getUUID();
if (a_uuid == favorites_folder_id && b_uuid == favorites_folder_id)
{
// *TODO: mantipov: probably it is better to add an appropriate method to LLFolderViewItem
// or to LLInvFVBridge
S32 a_sort = (static_cast<const LLItemBridge*>(a->getListener()))->getItem()->getSortField();
S32 b_sort = (static_cast<const LLItemBridge*>(b->getListener()))->getItem()->getSortField();
return a_sort < b_sort;
}
}
// We sort by name if we aren't sorting by date
// OR if these are folders and we are sorting folders by name.
bool by_name = (!mByDate

View File

@ -158,6 +158,7 @@ protected:
LLUIImagePtr mBoxImage;
BOOL mIsLoading;
LLTimer mTimeSinceRequestStart;
bool mDontShowInHierarhy;
// helper function to change the selection from the root.
void changeSelectionFromRoot(LLFolderViewItem* selection, BOOL selected);
@ -200,6 +201,7 @@ public:
// makes sure that this view and it's children are the right size.
virtual S32 arrange( S32* width, S32* height, S32 filter_generation );
virtual S32 getItemHeight();
void setDontShowInHierarchy(bool dont_show) { mDontShowInHierarhy = dont_show; }
// applies filters to control visibility of inventory items
virtual void filter( LLInventoryFilter& filter);

View File

@ -315,7 +315,7 @@ void LLGroupListItem::setActive(bool active)
// rebuild the text. This will cause problems if the text contains
// hyperlinks, as their styles will be wrong.
std::string text = mGroupNameBox->getText();
mGroupNameBox->setText(LLStringUtil::null);// *HACK: replace with clear() when it's fixed.
mGroupNameBox->setText(LLStringUtil::null);
mGroupNameBox->appendText(text, false, style_params);
}

View File

@ -63,13 +63,15 @@ LLIMFloater::LLIMFloater(const LLUUID& session_id)
mDialog(IM_NOTHING_SPECIAL),
mHistoryEditor(NULL),
mInputEditor(NULL),
mPositioned(false)
mPositioned(false),
mSessionInitialized(false)
{
EInstantMessage type = LLIMModel::getInstance()->getType(session_id);
if(IM_COUNT != type)
LLIMModel::LLIMSession* im_session = LLIMModel::getInstance()->findIMSession(mSessionID);
if (im_session)
{
mDialog = type;
mSessionInitialized = im_session->mSessionInitialized;
mDialog = im_session->mType;
if (IM_NOTHING_SPECIAL == mDialog || IM_SESSION_P2P_INVITE == mDialog)
{
mFactoryMap["panel_im_control_panel"] = LLCallbackMap(createPanelIMControl, this);
@ -139,10 +141,16 @@ void LLIMFloater::sendMsg()
std::string utf8_text = wstring_to_utf8str(text);
utf8_text = utf8str_truncate(utf8_text, MAX_MSG_BUF_SIZE - 1);
LLIMModel::sendMessage(utf8_text,
mSessionID,
mOtherParticipantUUID,
mDialog);
if (mSessionInitialized)
{
LLIMModel::sendMessage(utf8_text, mSessionID,
mOtherParticipantUUID,mDialog);
}
else
{
//queue up the message to send once the session is initialized
mQueuedMsgsForInit.append(utf8_text);
}
mInputEditor->setText(LLStringUtil::null);
@ -200,6 +208,8 @@ BOOL LLIMFloater::postBuild()
LLLogChat::loadHistory(getTitle(), &chatFromLogFile, (void *)this);
}
//*TODO if session is not initialized yet, add some sort of a warning message like "starting session...blablabla"
//see LLFloaterIMPanel for how it is done (IB)
return LLDockableFloater::postBuild();
}
@ -337,6 +347,37 @@ bool LLIMFloater::toggle(const LLUUID& session_id)
}
}
//static
LLIMFloater* LLIMFloater::findInstance(const LLUUID& session_id)
{
return LLFloaterReg::findTypedInstance<LLIMFloater>("impanel", session_id);
}
void LLIMFloater::sessionInitReplyReceived(const LLUUID& im_session_id)
{
mSessionInitialized = true;
if (mSessionID != im_session_id)
{
mSessionID = im_session_id;
setKey(im_session_id);
}
//*TODO here we should remove "starting session..." warning message if we added it in postBuild() (IB)
//need to send delayed messaged collected while waiting for session initialization
if (!mQueuedMsgsForInit.size()) return;
LLSD::array_iterator iter;
for ( iter = mQueuedMsgsForInit.beginArray();
iter != mQueuedMsgsForInit.endArray();
++iter)
{
LLIMModel::sendMessage(iter->asString(), mSessionID,
mOtherParticipantUUID, mDialog);
}
}
void LLIMFloater::updateMessages()
{
std::list<LLSD> messages = LLIMModel::instance().getMessages(mSessionID, mLastMessageIndex+1);
@ -457,3 +498,4 @@ void LLIMFloater::chatFromLogFile(LLLogChat::ELogLineType type, std::string line
self->mHistoryEditor->appendText(message, true, LLStyle::Params().color(LLUIColorTable::instance().getColor("ChatHistoryTextColor")));
self->mHistoryEditor->blockUndo();
}

View File

@ -68,6 +68,10 @@ public:
// Returns true iff panel became visible
static bool toggle(const LLUUID& session_id);
static LLIMFloater* findInstance(const LLUUID& session_id);
void sessionInitReplyReceived(const LLUUID& im_session_id);
// get new messages from LLIMModel
void updateMessages();
static void onSendMsg( LLUICtrl*, void*);
@ -108,6 +112,9 @@ private:
LLViewerTextEditor* mHistoryEditor;
LLLineEditor* mInputEditor;
bool mPositioned;
bool mSessionInitialized;
LLSD mQueuedMsgsForInit;
};

View File

@ -144,6 +144,8 @@ LLIMModel::LLIMSession::LLIMSession(const LLUUID& session_id, const std::string&
// All participants will be added to the list of people we've recently interacted with.
mSpeakers->addListener(&LLRecentPeople::instance(), "add");
//we need to wait for session initialization for outgoing ad-hoc and group chat session
//correct session id for initiated ad-hoc chat will be received from the server
if (!LLIMModel::getInstance()->sendStartSession(mSessionID, mOtherParticipantID,
mInitialTargetIDs, mType))
{
@ -181,26 +183,44 @@ LLIMModel::LLIMSession::~LLIMSession()
mVoiceChannel = NULL;
}
void LLIMModel::LLIMSession::sessionInitReplyReceived(const LLUUID& new_session_id)
{
mSessionInitialized = true;
if (new_session_id != mSessionID)
{
mSessionID = new_session_id;
mVoiceChannel->updateSessionID(new_session_id);
}
}
LLIMModel::LLIMSession* LLIMModel::findIMSession(const LLUUID& session_id) const
{
return get_if_there(LLIMModel::instance().sSessionsMap, session_id,
(LLIMModel::LLIMSession*) NULL);
}
//*TODO change name to represent session initialization aspect (IB)
void LLIMModel::updateSessionID(const LLUUID& old_session_id, const LLUUID& new_session_id)
{
if (new_session_id == old_session_id) return;
LLIMSession* session = findIMSession(old_session_id);
if (session)
{
session->mSessionID = new_session_id;
session->mVoiceChannel->updateSessionID(new_session_id);
session->sessionInitReplyReceived(new_session_id);
session->mSessionInitialized = true;
if (old_session_id != new_session_id)
{
sSessionsMap.erase(old_session_id);
sSessionsMap[new_session_id] = session;
sSessionsMap.erase(old_session_id);
sSessionsMap[new_session_id] = session;
gIMMgr->notifyObserverSessionIDUpdated(old_session_id, new_session_id);
}
LLIMFloater* im_floater = LLIMFloater::findInstance(old_session_id);
if (im_floater)
{
im_floater->sessionInitReplyReceived(new_session_id);
}
}
//*TODO remove this "floater" stuff when Communicate Floater is gone
@ -736,18 +756,10 @@ bool LLIMModel::sendStartSession(
temp_session_id,
other_participant_id,
dialog);
switch(dialog)
{
case IM_SESSION_GROUP_START:
gMessageSystem->addBinaryDataFast(
gMessageSystem->addBinaryDataFast(
_PREHASH_BinaryBucket,
EMPTY_BINARY_BUCKET,
EMPTY_BINARY_BUCKET_SIZE);
break;
default:
break;
}
gAgent.sendReliableMessage();
return true;
@ -789,6 +801,9 @@ bool LLIMModel::sendStartSession(
other_participant_id,
agents);
}
//we also need to wait for reply from the server in case of ad-hoc chat (we'll get new session id)
return true;
}
return false;
@ -1291,9 +1306,16 @@ void LLIMMgr::addMessage(
new_session_id = computeSessionID(dialog, other_participant_id);
}
//*NOTE session_name is empty in case of incoming P2P sessions
std::string fixed_session_name = from;
if(!session_name.empty() && session_name.size()>1)
{
fixed_session_name = session_name;
}
if (!LLIMModel::getInstance()->findIMSession(new_session_id))
{
LLIMModel::instance().newSession(session_id, session_name, dialog, other_participant_id);
LLIMModel::getInstance()->newSession(session_id, fixed_session_name, dialog, other_participant_id);
}
floater = findFloaterBySession(new_session_id);
@ -1310,17 +1332,12 @@ void LLIMMgr::addMessage(
// create IM window as necessary
if(!floater)
{
std::string name = from;
if(!session_name.empty() && session_name.size()>1)
{
name = session_name;
}
floater = createFloater(
new_session_id,
other_participant_id,
name,
fixed_session_name,
dialog,
FALSE);
@ -1869,6 +1886,15 @@ void LLIMMgr::notifyObserverSessionRemoved(const LLUUID& session_id)
}
}
void LLIMMgr::notifyObserverSessionIDUpdated( const LLUUID& old_session_id, const LLUUID& new_session_id )
{
for (session_observers_list_t::iterator it = mSessionObservers.begin(); it != mSessionObservers.end(); it++)
{
(*it)->sessionIDUpdated(old_session_id, new_session_id);
}
}
void LLIMMgr::addSessionObserver(LLIMSessionObserver *observer)
{
mSessionObservers.push_back(observer);

View File

@ -56,6 +56,8 @@ public:
const EInstantMessage& type, const LLUUID& other_participant_id, const std::vector<LLUUID>& ids);
virtual ~LLIMSession();
void sessionInitReplyReceived(const LLUUID& new_session_id);
LLUUID mSessionID;
std::string mName;
EInstantMessage mType;
@ -153,6 +155,7 @@ public:
virtual ~LLIMSessionObserver() {}
virtual void sessionAdded(const LLUUID& session_id, const std::string& name, const LLUUID& other_participant_id) = 0;
virtual void sessionRemoved(const LLUUID& session_id) = 0;
virtual void sessionIDUpdated(const LLUUID& old_session_id, const LLUUID& new_session_id) = 0;
};
@ -304,6 +307,7 @@ private:
void notifyObserverSessionAdded(const LLUUID& session_id, const std::string& name, const LLUUID& other_participant_id);
void notifyObserverSessionRemoved(const LLUUID& session_id);
void notifyObserverSessionIDUpdated(const LLUUID& old_session_id, const LLUUID& new_session_id);
private:
std::set<LLHandle<LLFloater> > mFloaters;

View File

@ -54,6 +54,8 @@
#include "lltooltip.h" // positionViewNearMouse()
#include "lluictrl.h"
#include "llavatariconctrl.h"
class LLFetchAvatarData;
@ -347,6 +349,10 @@ void LLInspectAvatar::requestUpdate()
// and this may result in the image being visible sooner.
// *NOTE: This may generate a duplicate avatar properties request, but that
// will be suppressed internally in the avatar properties processor.
//remove avatar id from cache to get fresh info
LLAvatarIconIDCache::getInstance()->remove(mAvatarID);
childSetValue("avatar_icon", LLSD(mAvatarID) );
gCacheName->get(mAvatarID, FALSE,

View File

@ -257,11 +257,22 @@ void LLInvFVBridge::renameLinkedItems(const LLUUID &item_id, const std::string&
}
// Can be moved to another folder
BOOL LLInvFVBridge::isItemMovable()
BOOL LLInvFVBridge::isItemMovable() const
{
return TRUE;
}
/*virtual*/
/**
* @brief Adds this item into clipboard storage
*/
void LLInvFVBridge::cutToClipboard()
{
if(isItemMovable())
{
LLInventoryClipboard::instance().cut(mUUID);
}
}
// *TODO: make sure this does the right thing
void LLInvFVBridge::showProperties()
{
@ -911,6 +922,24 @@ void LLInvFVBridge::purgeItem(LLInventoryModel *model, const LLUUID &uuid)
}
}
// +=================================================+
// | InventoryFVBridgeBuilder |
// +=================================================+
LLInvFVBridge* LLInventoryFVBridgeBuilder::createBridge(LLAssetType::EType asset_type,
LLAssetType::EType actual_asset_type,
LLInventoryType::EType inv_type,
LLInventoryPanel* inventory,
const LLUUID& uuid,
U32 flags /* = 0x00 */) const
{
return LLInvFVBridge::createBridge(asset_type,
actual_asset_type,
inv_type,
inventory,
uuid,
flags);
}
// +=================================================+
// | LLItemBridge |
// +=================================================+
@ -1321,7 +1350,7 @@ BOOL LLItemBridge::isItemPermissive() const
LLFolderBridge* LLFolderBridge::sSelf=NULL;
// Can be moved to another folder
BOOL LLFolderBridge::isItemMovable()
BOOL LLFolderBridge::isItemMovable() const
{
LLInventoryObject* obj = getInventoryObject();
if(obj)
@ -2184,19 +2213,28 @@ void LLFolderBridge::pasteFromClipboard()
LLDynamicArray<LLUUID> objects;
LLInventoryClipboard::instance().retrieve(objects);
S32 count = objects.count();
LLUUID parent_id(mUUID);
const LLUUID parent_id(mUUID);
for(S32 i = 0; i < count; i++)
{
item = model->getItem(objects.get(i));
if (item)
{
copy_inventory_item(
gAgent.getID(),
item->getPermissions().getOwner(),
item->getUUID(),
parent_id,
std::string(),
LLPointer<LLInventoryCallback>(NULL));
if(LLInventoryClipboard::instance().isCutMode())
{
// move_inventory_item() is not enough,
//we have to update inventory locally too
changeItemParent(model, dynamic_cast<LLViewerInventoryItem*>(item), parent_id, FALSE);
}
else
{
copy_inventory_item(
gAgent.getID(),
item->getPermissions().getOwner(),
item->getUUID(),
parent_id,
std::string(),
LLPointer<LLInventoryCallback>(NULL));
}
}
}
}
@ -2668,6 +2706,56 @@ bool move_task_inventory_callback(const LLSD& notification, const LLSD& response
return false;
}
/*
Next functions intended to reorder items in the inventory folder and save order on server
Is now used for Favorites folder.
*TODO: refactoring is needed with Favorites Bar functionality. Probably should be moved in LLInventoryModel
*/
void saveItemsOrder(LLInventoryModel::item_array_t& items)
{
int sortField = 0;
// current order is saved by setting incremental values (1, 2, 3, ...) for the sort field
for (LLInventoryModel::item_array_t::iterator i = items.begin(); i != items.end(); ++i)
{
LLViewerInventoryItem* item = *i;
item->setSortField(++sortField);
item->setComplete(TRUE);
item->updateServer(FALSE);
gInventory.updateItem(item);
}
gInventory.notifyObservers();
}
LLInventoryModel::item_array_t::iterator findItemByUUID(LLInventoryModel::item_array_t& items, const LLUUID& id)
{
LLInventoryModel::item_array_t::iterator result = items.end();
for (LLInventoryModel::item_array_t::iterator i = items.begin(); i != items.end(); ++i)
{
if ((*i)->getUUID() == id)
{
result = i;
break;
}
}
return result;
}
void updateItemsOrder(LLInventoryModel::item_array_t& items, const LLUUID& srcItemId, const LLUUID& destItemId)
{
LLViewerInventoryItem* srcItem = gInventory.getItem(srcItemId);
LLViewerInventoryItem* destItem = gInventory.getItem(destItemId);
items.erase(findItemByUUID(items, srcItem->getUUID()));
items.insert(findItemByUUID(items, destItem->getUUID()), srcItem);
}
BOOL LLFolderBridge::dragItemIntoFolder(LLInventoryItem* inv_item,
BOOL drop)
{
@ -2726,7 +2814,10 @@ BOOL LLFolderBridge::dragItemIntoFolder(LLInventoryItem* inv_item,
}
}
accept = is_movable && (mUUID != inv_item->getParentUUID());
LLUUID favorites_id = model->findCategoryUUIDForType(LLAssetType::AT_FAVORITE);
// we can move item inside a folder only if this folder is Favorites. See EXT-719
accept = is_movable && ((mUUID != inv_item->getParentUUID()) || (mUUID == favorites_id));
if(accept && drop)
{
if (inv_item->getType() == LLAssetType::AT_GESTURE
@ -2748,8 +2839,28 @@ BOOL LLFolderBridge::dragItemIntoFolder(LLInventoryItem* inv_item,
}
}
LLUUID favorites_id = model->findCategoryUUIDForType(LLAssetType::AT_FAVORITE);
if (favorites_id == mUUID) // if target is the favorites folder we use copy
// if dragging from/into favorites folder only reorder items
if ((mUUID == inv_item->getParentUUID()) && (favorites_id == mUUID))
{
LLInventoryModel::cat_array_t cats;
LLInventoryModel::item_array_t items;
LLIsType is_type(LLAssetType::AT_LANDMARK);
model->collectDescendentsIf(favorites_id, cats, items, LLInventoryModel::EXCLUDE_TRASH, is_type);
LLInventoryPanel* panel = dynamic_cast<LLInventoryPanel*>(mInventoryPanel.get());
LLFolderViewItem* itemp = panel ? panel->getRootFolder()->getDraggingOverItem() : NULL;
if (itemp)
{
LLUUID srcItemId = inv_item->getUUID();
LLUUID destItemId = itemp->getListener()->getUUID();
// update order
updateItemsOrder(items, srcItemId, destItemId);
saveItemsOrder(items);
}
}
else if (favorites_id == mUUID) // if target is the favorites folder we use copy
{
copy_inventory_item(
gAgent.getID(),
@ -3023,14 +3134,14 @@ void LLLandmarkBridge::buildContextMenu(LLMenuGL& menu, U32 flags)
}
items.push_back(std::string("Landmark Separator"));
items.push_back(std::string("Teleport To Landmark"));
items.push_back(std::string("About Landmark"));
// Disable "About Landmark" menu item for
// multiple landmarks selected. Only one landmark
// info panel can be shown at a time.
if ((flags & FIRST_SELECTED_ITEM) == 0)
{
disabled_items.push_back(std::string("Teleport To Landmark"));
disabled_items.push_back(std::string("About Landmark"));
}
hideContextEntries(menu, items, disabled_items);

View File

@ -120,6 +120,11 @@ protected:
LLInventoryPanel* mIP;
};
const std::string safe_inv_type_lookup(LLInventoryType::EType inv_type);
void hideContextEntries(LLMenuGL& menu,
const std::vector<std::string> &entries_to_show,
const std::vector<std::string> &disabled_entries);
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Class LLInvFVBridge (& it's derived classes)
//
@ -168,13 +173,13 @@ public:
virtual BOOL isItemRenameable() const { return TRUE; }
//virtual BOOL renameItem(const std::string& new_name) {}
virtual BOOL isItemRemovable();
virtual BOOL isItemMovable();
virtual BOOL isItemMovable() const;
//virtual BOOL removeItem() = 0;
virtual void removeBatch(LLDynamicArray<LLFolderViewEventListener*>& batch);
virtual void move(LLFolderViewEventListener* new_parent_bridge) {}
virtual BOOL isItemCopyable() const { return FALSE; }
virtual BOOL copyToClipboard() const { return FALSE; }
virtual void cutToClipboard() {}
virtual void cutToClipboard();
virtual BOOL isClipboardPasteable() const;
virtual BOOL isClipboardPasteableAsLink() const;
virtual void pasteFromClipboard() {}
@ -221,6 +226,22 @@ protected:
void purgeItem(LLInventoryModel *model, const LLUUID &uuid);
};
/**
* This class intended to build Folder View Bridge via LLInvFVBridge::createBridge.
* It can be overridden with another way of creation necessary Inventory-Folder-View-Bridge.
*/
class LLInventoryFVBridgeBuilder
{
public:
virtual ~LLInventoryFVBridgeBuilder(){}
virtual LLInvFVBridge* createBridge(LLAssetType::EType asset_type,
LLAssetType::EType actual_asset_type,
LLInventoryType::EType inv_type,
LLInventoryPanel* inventory,
const LLUUID& uuid,
U32 flags = 0x00) const;
};
class LLItemBridge : public LLInvFVBridge
{
@ -291,7 +312,7 @@ public:
void* cargo_data);
virtual BOOL isItemRemovable();
virtual BOOL isItemMovable();
virtual BOOL isItemMovable() const ;
virtual BOOL isUpToDate() const;
virtual BOOL isItemCopyable() const;
virtual BOOL isClipboardPasteableAsLink() const;

View File

@ -47,6 +47,7 @@ LLInventoryClipboard LLInventoryClipboard::sInstance;
///----------------------------------------------------------------------------
LLInventoryClipboard::LLInventoryClipboard()
: mCutMode(false)
{
}
@ -77,6 +78,16 @@ void LLInventoryClipboard::store(const LLDynamicArray<LLUUID>& inv_objects)
}
}
void LLInventoryClipboard::cut(const LLUUID& object)
{
if(!mCutMode && !mObjects.empty())
{
//looks like there are some stored items, reset clipboard state
reset();
}
mCutMode = true;
add(object);
}
void LLInventoryClipboard::retrieve(LLDynamicArray<LLUUID>& inv_objects) const
{
inv_objects.reset();
@ -90,6 +101,7 @@ void LLInventoryClipboard::retrieve(LLDynamicArray<LLUUID>& inv_objects) const
void LLInventoryClipboard::reset()
{
mObjects.reset();
mCutMode = false;
}
// returns true if the clipboard has something pasteable in it.

View File

@ -60,6 +60,7 @@ public:
// this method stores an array of objects
void store(const LLDynamicArray<LLUUID>& inventory_objects);
void cut(const LLUUID& object);
// this method gets the objects in the clipboard by copying them
// into the array provided.
void retrieve(LLDynamicArray<LLUUID>& inventory_objects) const;
@ -69,11 +70,13 @@ public:
// returns true if the clipboard has something pasteable in it.
BOOL hasContents() const;
bool isCutMode() const { return mCutMode; }
protected:
static LLInventoryClipboard sInstance;
LLDynamicArray<LLUUID> mObjects;
bool mCutMode;
public:
// please don't actually call these

View File

@ -42,16 +42,18 @@
#include "llnotifications.h"
#include "llagent.h"
#include "llagentui.h"
#include "llinventorymodel.h"
#include "lllandmarklist.h"
#include "llslurl.h"
#include "llstring.h"
#include "llviewerinventory.h"
#include "llviewerparcelmgr.h"
#include "llviewerwindow.h"
#include "llwindow.h"
#include "llworldmap.h"
#include "lllandmark.h"
#include "llinventorymodel.h"
#include "llagentui.h"
void copy_slurl_to_clipboard_callback(const std::string& slurl);
class LLFetchlLandmarkByPos : public LLInventoryCollectFunctor
{
@ -303,15 +305,39 @@ void LLLandmarkActions::onRegionResponse(slurl_callback_t cb,
bool LLLandmarkActions::getLandmarkGlobalPos(const LLUUID& landmarkInventoryItemID, LLVector3d& posGlobal)
{
LLViewerInventoryItem* item = gInventory.getItem(landmarkInventoryItemID);
if (NULL == item)
return false;
const LLUUID& asset_id = item->getAssetUUID();
LLLandmark* landmark = gLandmarkList.getAsset(asset_id, NULL);
LLLandmark* landmark = LLLandmarkActions::getLandmark(landmarkInventoryItemID);
if (NULL == landmark)
return false;
return landmark->getGlobalPos(posGlobal);
}
LLLandmark* LLLandmarkActions::getLandmark(const LLUUID& landmarkInventoryItemID)
{
LLViewerInventoryItem* item = gInventory.getItem(landmarkInventoryItemID);
if (NULL == item)
return false;
const LLUUID& asset_id = item->getAssetUUID();
return gLandmarkList.getAsset(asset_id, NULL);
}
void LLLandmarkActions::copySLURLtoClipboard(const LLUUID& landmarkInventoryItemID)
{
LLLandmark* landmark = LLLandmarkActions::getLandmark(landmarkInventoryItemID);
if(landmark)
{
LLVector3d global_pos;
landmark->getGlobalPos(global_pos);
LLLandmarkActions::getSLURLfromPosGlobal(global_pos,&copy_slurl_to_clipboard_callback,true);
}
}
void copy_slurl_to_clipboard_callback(const std::string& slurl)
{
gViewerWindow->mWindow->copyTextToClipboard(utf8str_to_wstring(slurl));
LLSD args;
args["SLURL"] = slurl;
LLNotifications::instance().add("CopySLURL", args);
}

View File

@ -35,6 +35,7 @@
#include "llinventorymodel.h"
class LLLandmark;
/**
* @brief Provides helper functions to manage landmarks
*/
@ -101,6 +102,20 @@ public:
// *TODO: mantipov: profide callback for cases, when Landmark is not loaded yet.
static bool getLandmarkGlobalPos(const LLUUID& landmarkInventoryItemID, LLVector3d& posGlobal);
/**
* @brief Retrieve a landmark from gLandmarkList by inventory item's id
*
* @return pointer to loaded landmark from gLandmarkList or NULL if landmark does not exist.
*/
static LLLandmark* getLandmark(const LLUUID& landmarkInventoryItemID);
/**
* @brief Performs standard action of copying of SLURL from landmark to user's clipboard.
* This action requires additional server request. The user will be notified by info message,
* when URL is copied .
*/
static void copySLURLtoClipboard(const LLUUID& landmarkInventoryItemID);
private:
LLLandmarkActions();
LLLandmarkActions(const LLLandmarkActions&);

View File

@ -48,11 +48,9 @@
#include "llnearbychathandler.h"
#include "llchannelmanager.h"
//for LLViewerTextEditor support
#include "llagent.h" // gAgent
#include "llfloaterscriptdebug.h"
#include "llslurl.h"
#include "llviewertexteditor.h"
#include "llchathistory.h"
#include "llstylemap.h"
#include "lldraghandle.h"
@ -64,7 +62,7 @@ LLNearbyChat::LLNearbyChat(const LLSD& key) :
LLFloater(key),
mEChatTearofState(CHAT_PINNED),
mChatCaptionPanel(NULL),
mChatHistoryEditor(NULL)
mChatHistory(NULL)
{
m_isDirty = false;
}
@ -110,7 +108,7 @@ BOOL LLNearbyChat::postBuild()
gSavedSettings.declareS32("nearbychat_showicons_and_names",2,"NearByChat header settings",true);
mChatCaptionPanel = getChild<LLPanel>("chat_caption", false);
mChatHistoryEditor = getChild<LLViewerTextEditor>("Chat History Editor");
mChatHistory = getChild<LLChatHistory>("chat_history");
reshape(getRect().getWidth(), getRect().getHeight(), FALSE);
@ -185,44 +183,6 @@ LLColor4 nearbychat_get_text_color(const LLChat& chat)
void LLNearbyChat::add_timestamped_line(const LLChat& chat, const LLColor4& color)
{
std::string line = chat.mText;
//chat.mText starts with Avatar Name if entered message was "/me <action>".
// In this case output chat message should be "<Avatar Name> <action>". See EXT-656
// See also process_chat_from_simulator() in the llviewermessage.cpp where ircstyle = TRUE;
if (CHAT_STYLE_IRC != chat.mChatStyle)
line = chat.mFromName + ": " + line;
bool prepend_newline = true;
if (gSavedSettings.getBOOL("ChatShowTimestamps"))
{
mChatHistoryEditor->appendTime(prepend_newline);
prepend_newline = false;
}
// If the msg is from an agent (not yourself though),
// extract out the sender name and replace it with the hotlinked name.
std::string str_URL = chat.mURL;
if (chat.mSourceType == CHAT_SOURCE_AGENT &&
chat.mFromID != LLUUID::null)
{
str_URL = LLSLURL::buildCommand("agent", chat.mFromID, "inspect");
}
// If the chat line has an associated url, link it up to the name.
if (!str_URL.empty()
&& (line.length() > chat.mFromName.length() && line.find(chat.mFromName,0) == 0))
{
std::string start_line = line.substr(0, chat.mFromName.length() + 1);
line = line.substr(chat.mFromName.length() + 1);
mChatHistoryEditor->appendText(start_line, prepend_newline,
LLStyleMap::instance().lookup(chat.mFromID,str_URL));
mChatHistoryEditor->blockUndo();
prepend_newline = false;
}
S32 font_size = gSavedSettings.getS32("ChatFontSize");
const LLFontGL* fontp = NULL;
@ -240,8 +200,14 @@ void LLNearbyChat::add_timestamped_line(const LLChat& chat, const LLColor4& colo
break;
}
mChatHistoryEditor->appendText(line, prepend_newline, LLStyle::Params().color(color).font(fontp));
mChatHistoryEditor->blockUndo();
LLStyle::Params style_params;
style_params.color(color);
style_params.font(fontp);
LLUUID uuid = chat.mFromID;
std::string from = chat.mFromName;
std::string time = "";
std::string message = chat.mText;
mChatHistory->appendWidgetMessage(uuid, from, time, message, style_params);
}
void LLNearbyChat::addMessage(const LLChat& chat)
@ -315,7 +281,7 @@ void LLNearbyChat::reshape(S32 width, S32 height, BOOL called_from_parent)
mResizeBar[LLResizeBar::RIGHT]->setRect(resize_rect);
}
// *NOTE: we must check mChatCaptionPanel and mChatHistoryEditor against NULL because reshape is called from the
// *NOTE: we must check mChatCaptionPanel and mChatHistory against NULL because reshape is called from the
// LLView::initFromParams BEFORE postBuild is called and child controls are not exist yet
LLRect caption_rect;
if (NULL != mChatCaptionPanel)
@ -326,12 +292,12 @@ void LLNearbyChat::reshape(S32 width, S32 height, BOOL called_from_parent)
mChatCaptionPanel->setRect(caption_rect);
}
if (NULL != mChatHistoryEditor)
if (NULL != mChatHistory)
{
LLRect scroll_rect = mChatHistoryEditor->getRect();
LLRect scroll_rect = mChatHistory->getRect();
scroll_rect.setLeftTopAndSize( 2, height - caption_rect.getHeight() - RESIZE_BAR_THICKNESS, width - 4, height - caption_rect.getHeight() - RESIZE_BAR_THICKNESS*2);
mChatHistoryEditor->reshape( width - 4, height - caption_rect.getHeight() - RESIZE_BAR_THICKNESS*2, 1);
mChatHistoryEditor->setRect(scroll_rect);
mChatHistory->reshape( width - 4, height - caption_rect.getHeight() - RESIZE_BAR_THICKNESS*2, 1);
mChatHistory->setRect(scroll_rect);
}
//

View File

@ -38,7 +38,7 @@
#include "llchat.h"
class LLResizeBar;
class LLViewerTextEditor;
class LLChatHistory;
class LLNearbyChat: public LLFloater
{
@ -89,7 +89,7 @@ private:
LLHandle<LLView> mPopupMenuHandle;
LLPanel* mChatCaptionPanel;
LLViewerTextEditor* mChatHistoryEditor;
LLChatHistory* mChatHistory;
bool m_isDirty;
};

View File

@ -33,6 +33,8 @@
#include "llviewerprecompiledheaders.h" // must be first include
#include "llfloaterreg.h"
#include "llnearbychat.h"
#include "llnotificationhandler.h"
#include "lltoastnotifypanel.h"
#include "llviewercontrol.h"
@ -96,6 +98,14 @@ bool LLTipHandler::processNotification(const LLSD& notify)
LLScreenChannel* channel = dynamic_cast<LLScreenChannel*>(mChannel);
if(channel)
channel->addToast(p);
// archive message in nearby chat
LLNearbyChat* nearby_chat = LLFloaterReg::getTypedInstance<LLNearbyChat>("nearby_chat", LLSD());
if(nearby_chat)
{
LLChat chat_msg(notification->getMessage());
nearby_chat->addMessage(chat_msg);
}
}
else if (notify["sigtype"].asString() == "delete")
{

View File

@ -43,6 +43,7 @@
#include "lltexturectrl.h"
#include "lltooldraganddrop.h"
#include "llscrollcontainer.h"
#include "llavatariconctrl.h"
#include "llweb.h"
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@ -447,6 +448,10 @@ void LLPanelAvatarProfile::processGroupProperties(const LLAvatarGroups* avatar_g
void LLPanelAvatarProfile::fillCommonData(const LLAvatarData* avatar_data)
{
//remove avatar id from cache to get fresh info
LLAvatarIconIDCache::getInstance()->remove(avatar_data->avatar_id);
childSetValue("register_date", avatar_data->born_on );
childSetValue("sl_description_edit", avatar_data->about_text);
childSetValue("fl_description_edit",avatar_data->fl_about_text);

View File

@ -35,32 +35,50 @@
#include "llbutton.h"
#include "llfloaterreg.h"
#include "lllandmark.h"
#include "llsdutil.h"
#include "llaccordionctrltab.h"
#include "llagent.h"
#include "llagentui.h"
#include "llfloaterworldmap.h"
#include "llfloaterinventory.h"
#include "llfoldervieweventlistener.h"
#include "lllandmarklist.h"
#include "llfolderviewitem.h"
#include "llinventorysubtreepanel.h"
#include "lllandmarkactions.h"
#include "llplacesinventorybridge.h"
#include "llsidetray.h"
#include "lltabcontainer.h"
#include "llworldmap.h"
#include "llviewermenu.h"
#include "llviewerregion.h"
// Not yet implemented; need to remove buildPanel() from constructor when we switch
//static LLRegisterPanelClassWrapper<LLLandmarksPanel> t_landmarks("panel_landmarks");
LLLandmarksPanel::LLLandmarksPanel()
: LLPanelPlacesTab(),
mInventoryPanel(NULL)
{
mSavedFolderState = new LLSaveFolderState();
mSavedFolderState->setApply(FALSE);
static const std::string OPTIONS_BUTTON_NAME = "options_gear_btn";
static const std::string ADD_LANDMARK_BUTTON_NAME = "add_landmark_btn";
static const std::string ADD_FOLDER_BUTTON_NAME = "add_folder_btn";
static const std::string TRASH_BUTTON_NAME = "trash_btn";
static const LLPlacesInventoryBridgeBuilder PLACES_INVENTORY_BUILDER;
// helper functions
static void filter_list(LLInventorySubTreePanel* inventory_list, const std::string& string);
LLLandmarksPanel::LLLandmarksPanel()
: LLPanelPlacesTab()
, mFavoritesInventoryPanel(NULL)
, mLandmarksInventoryPanel(NULL)
, mMyInventoryPanel(NULL)
, mLibraryInventoryPanel(NULL)
, mCurrentSelectedList(NULL)
, mListCommands(NULL)
, mGearFolderMenu(NULL)
, mGearLandmarkMenu(NULL)
{
LLUICtrlFactory::getInstance()->buildPanel(this, "panel_landmarks.xml");
}
LLLandmarksPanel::~LLLandmarksPanel()
{
delete mSavedFolderState;
}
BOOL LLLandmarksPanel::postBuild()
@ -68,19 +86,13 @@ BOOL LLLandmarksPanel::postBuild()
if (!gInventory.isInventoryUsable())
return FALSE;
mInventoryPanel = getChild<LLInventoryPanel>("landmarks_list");
mInventoryPanel->setFilterTypes(0x1 << LLInventoryType::IT_LANDMARK);
mInventoryPanel->setShowFolderState(LLInventoryFilter::SHOW_NON_EMPTY_FOLDERS);
mInventoryPanel->openDefaultFolderForType(LLAssetType::AT_LANDMARK);
mInventoryPanel->setSelectCallback(boost::bind(&LLLandmarksPanel::onSelectionChange, this, _1, _2));
// mast be called before any other initXXX methods to init Gear menu
initListCommandsHandlers();
LLFolderView* root_folder = mInventoryPanel->getRootFolder();
root_folder->setReshapeCallback(boost::bind(&LLLandmarksPanel::onSelectionChange, this, _1, _2));
mActionBtn = getChild<LLButton>("selector");
root_folder->addChild(mActionBtn);
mActionBtn->setEnabled(TRUE);
childSetAction("selector", boost::bind(&LLLandmarksPanel::onSelectorButtonClicked, this), this);
initFavoritesInventroyPanel();
initLandmarksInventroyPanel();
initMyInventroyPanel();
initLibraryInventroyPanel();
return TRUE;
}
@ -88,53 +100,21 @@ BOOL LLLandmarksPanel::postBuild()
// virtual
void LLLandmarksPanel::onSearchEdit(const std::string& string)
{
if (string == "")
{
mInventoryPanel->setFilterSubString(LLStringUtil::null);
// re-open folders that were initially open
mSavedFolderState->setApply(TRUE);
mInventoryPanel->getRootFolder()->applyFunctorRecursively(*mSavedFolderState);
LLOpenFoldersWithSelection opener;
mInventoryPanel->getRootFolder()->applyFunctorRecursively(opener);
mInventoryPanel->getRootFolder()->scrollToShowSelection();
}
gInventory.startBackgroundFetch();
if (mInventoryPanel->getFilterSubString().empty() && string.empty())
{
// current filter and new filter empty, do nothing
return;
}
// save current folder open state if no filter currently applied
if (mInventoryPanel->getRootFolder()->getFilterSubString().empty())
{
mSavedFolderState->setApply(FALSE);
mInventoryPanel->getRootFolder()->applyFunctorRecursively(*mSavedFolderState);
}
// set new filter string
mInventoryPanel->setFilterSubString(string);
filter_list(mFavoritesInventoryPanel, string);
filter_list(mLandmarksInventoryPanel, string);
filter_list(mMyInventoryPanel, string);
filter_list(mLibraryInventoryPanel, string);
}
// virtual
void LLLandmarksPanel::onShowOnMap()
{
LLFolderViewItem* current_item = mInventoryPanel->getRootFolder()->getCurSelectedItem();
if (!current_item)
if (NULL == mCurrentSelectedList)
{
llwarns << "There are no selected list. No actions are performed." << llendl;
return;
LLFolderViewEventListener* listenerp = current_item->getListener();
if (listenerp->getInventoryType() != LLInventoryType::IT_LANDMARK)
return;
LLInventoryItem* inventory_item = gInventory.getItem(listenerp->getUUID());
if (!inventory_item)
return;
LLLandmark* landmark = gLandmarkList.getAsset(inventory_item->getAssetUUID());
}
LLLandmark* landmark = getCurSelectedLandmark();
if (!landmark)
return;
@ -153,9 +133,12 @@ void LLLandmarksPanel::onShowOnMap()
// virtual
void LLLandmarksPanel::onTeleport()
{
LLFolderViewItem* current_item = mInventoryPanel->getRootFolder()->getCurSelectedItem();
LLFolderViewItem* current_item = getCurSelectedItem();
if (!current_item)
{
llwarns << "There are no selected list. No actions are performed." << llendl;
return;
}
LLFolderViewEventListener* listenerp = current_item->getListener();
if (listenerp->getInventoryType() == LLInventoryType::IT_LANDMARK)
@ -164,104 +147,43 @@ void LLLandmarksPanel::onTeleport()
}
}
/*
// virtual
void LLLandmarksPanel::onCopySLURL()
{
LLFolderViewItem* current_item = mInventoryPanel->getRootFolder()->getCurSelectedItem();
if (!current_item)
return;
LLFolderViewEventListener* listenerp = current_item->getListener();
if (listenerp->getInventoryType() != LLInventoryType::IT_LANDMARK)
return;
LLInventoryItem* inventory_item = gInventory.getItem(listenerp->getUUID());
if (!inventory_item)
return;
LLLandmark* landmark = gLandmarkList.getAsset(inventory_item->getAssetUUID());
if (!landmark)
return;
LLVector3d landmark_global_pos;
if (!landmark->getGlobalPos(landmark_global_pos))
return;
U64 new_region_handle = to_region_handle(landmark_global_pos);
LLWorldMap::url_callback_t cb = boost::bind(
&LLPanelPlacesTab::onRegionResponse, this,
landmark_global_pos, _1, _2, _3, _4);
LLWorldMap::getInstance()->sendHandleRegionRequest(new_region_handle, cb, std::string("unused"), false);
}
*/
// virtual
void LLLandmarksPanel::updateVerbs()
{
if (!isTabVisible())
return;
BOOL enabled = FALSE;
LLFolderViewItem* current_item = mInventoryPanel->getRootFolder()->getCurSelectedItem();
if (current_item)
{
LLFolderViewEventListener* listenerp = current_item->getListener();
if (listenerp->getInventoryType() == LLInventoryType::IT_LANDMARK)
{
enabled = TRUE;
}
}
BOOL enabled = isLandmarkSelected();
mTeleportBtn->setEnabled(enabled);
mShowOnMapBtn->setEnabled(enabled);
// TODO: mantipov: Uncomment when mShareBtn is supported
// Share button should be enabled when neither a folder nor a landmark is selected
//mShareBtn->setEnabled(NULL != current_item);
updateListCommands();
}
void LLLandmarksPanel::onSelectionChange(const std::deque<LLFolderViewItem*> &items, BOOL user_action)
void LLLandmarksPanel::onSelectionChange(LLInventorySubTreePanel* inventory_list, const std::deque<LLFolderViewItem*> &items, BOOL user_action)
{
LLFolderViewItem* current_item = mInventoryPanel->getRootFolder()->getCurSelectedItem();
if (user_action && (items.size() > 0))
{
deselectOtherThan(inventory_list);
mCurrentSelectedList = inventory_list;
}
LLFolderViewItem* current_item = inventory_list->getRootFolder()->getCurSelectedItem();
if (!current_item)
return;
LLFolderViewEventListener* listenerp = current_item->getListener();
if (listenerp->getInventoryType() == LLInventoryType::IT_LANDMARK)
{
S32 bottom = 0;
LLFolderViewItem* folder = current_item->getParentFolder();
while ( folder->getParentFolder() != NULL )
{
bottom += folder->getRect().mBottom;
folder = folder->getParentFolder();
}
LLRect rect = current_item->getRect();
LLRect btn_rect(
rect.mRight - mActionBtn->getRect().getWidth(),
bottom + rect.mTop,
rect.mRight,
bottom + rect.mBottom);
mActionBtn->setRect(btn_rect);
if (!mActionBtn->getVisible())
mActionBtn->setVisible(TRUE);
}
else
{
if (mActionBtn->getVisible())
mActionBtn->setVisible(FALSE);
}
updateVerbs();
}
void LLLandmarksPanel::onSelectorButtonClicked()
{
LLFolderViewItem* cur_item = mInventoryPanel->getRootFolder()->getCurSelectedItem();
// TODO: mantipov: update getting of selected item
// TODO: bind to "i" button
LLFolderViewItem* cur_item = mFavoritesInventoryPanel->getRootFolder()->getCurSelectedItem();
LLFolderViewEventListener* listenerp = cur_item->getListener();
if (listenerp->getInventoryType() == LLInventoryType::IT_LANDMARK)
@ -274,7 +196,497 @@ void LLLandmarksPanel::onSelectorButtonClicked()
}
}
void LLLandmarksPanel::setSelectedItem(const LLUUID& obj_id)
//////////////////////////////////////////////////////////////////////////
// PROTECTED METHODS
//////////////////////////////////////////////////////////////////////////
bool LLLandmarksPanel::isLandmarkSelected() const
{
mInventoryPanel->setSelection(obj_id, FALSE);
LLFolderViewItem* current_item = getCurSelectedItem();
if(current_item && current_item->getListener()->getInventoryType() == LLInventoryType::IT_LANDMARK)
{
return true;
}
return false;
}
LLLandmark* LLLandmarksPanel::getCurSelectedLandmark() const
{
LLFolderViewItem* cur_item = getCurSelectedItem();
if(cur_item && cur_item->getListener()->getInventoryType() == LLInventoryType::IT_LANDMARK)
{
return LLLandmarkActions::getLandmark(cur_item->getListener()->getUUID());
}
return NULL;
}
LLFolderViewItem* LLLandmarksPanel::getCurSelectedItem () const
{
return mCurrentSelectedList ? mCurrentSelectedList->getRootFolder()->getCurSelectedItem() : NULL;
}
// virtual
void LLLandmarksPanel::processParcelInfo(const LLParcelData& parcel_data)
{
//this function will be called after user will try to create a pick for selected landmark.
// We have to make request to sever to get parcel_id and snaption_id.
if(isLandmarkSelected())
{
LLLandmark* landmark = getCurSelectedLandmark();
LLFolderViewItem* cur_item = getCurSelectedItem();
LLUUID id = cur_item->getListener()->getUUID();
LLInventoryItem* inv_item = mCurrentSelectedList->getModel()->getItem(id);
if(landmark)
{
LLPanelPick* panel_pick = new LLPanelPick(TRUE);
LLSD params;
LLVector3d landmark_global_pos;
landmark->getGlobalPos(landmark_global_pos);
panel_pick->prepareNewPick(landmark_global_pos,cur_item->getName(),inv_item->getDescription(),
parcel_data.snapshot_id,parcel_data.parcel_id);
// by default save button should be enabled
panel_pick->childSetEnabled("save_changes_btn", TRUE);
// let's toggle pick panel into panel places
LLPanel* panel_places = LLSideTray::getInstance()->getChild<LLPanel>("panel_places");//-> sidebar_places
panel_places->addChild(panel_pick);
LLRect paren_rect(panel_places->getRect());
panel_pick->reshape(paren_rect.getWidth(),paren_rect.getHeight(), TRUE);
panel_pick->setRect(paren_rect);
params["parcel_id"] =parcel_data.parcel_id;
/* set exit callback to get back onto panel places
in callback we will make cleaning up( delete pick_panel instance,
remove landmark panel from observer list
*/
panel_pick->setExitCallback(boost::bind(&LLLandmarksPanel::onPickPanelExit,this,
panel_pick, panel_places,params));
}
}
}
// virtual
void LLLandmarksPanel::setParcelID(const LLUUID& parcel_id)
{
if (!parcel_id.isNull())
{
LLRemoteParcelInfoProcessor::getInstance()->addObserver(parcel_id, this);
LLRemoteParcelInfoProcessor::getInstance()->sendParcelInfoRequest(parcel_id);
}
}
// virtual
void LLLandmarksPanel::setErrorStatus(U32 status, const std::string& reason)
{
llerrs<< "Can't handle remote parcel request."<< " Http Status: "<< status << ". Reason : "<< reason<<llendl;
}
//////////////////////////////////////////////////////////////////////////
// PRIVATE METHODS
//////////////////////////////////////////////////////////////////////////
void LLLandmarksPanel::initFavoritesInventroyPanel()
{
mFavoritesInventoryPanel = getChild<LLInventorySubTreePanel>("favorites_list");
LLUUID start_folder_id = mFavoritesInventoryPanel->getModel()->findCategoryUUIDForType(LLAssetType::AT_FAVORITE);
initLandmarksPanel(mFavoritesInventoryPanel, start_folder_id);
initAccordion("tab_favorites", mFavoritesInventoryPanel);
}
void LLLandmarksPanel::initLandmarksInventroyPanel()
{
mLandmarksInventoryPanel = getChild<LLInventorySubTreePanel>("landmarks_list");
LLUUID start_folder_id = mLandmarksInventoryPanel->getModel()->findCategoryUUIDForType(LLAssetType::AT_LANDMARK);
initLandmarksPanel(mLandmarksInventoryPanel, start_folder_id);
mLandmarksInventoryPanel->setShowFolderState(LLInventoryFilter::SHOW_ALL_FOLDERS);
// subscribe to have auto-rename functionality while creating New Folder
mLandmarksInventoryPanel->setSelectCallback(boost::bind(&LLInventoryPanel::onSelectionChange, mLandmarksInventoryPanel, _1, _2));
initAccordion("tab_landmarks", mLandmarksInventoryPanel);
}
void LLLandmarksPanel::initMyInventroyPanel()
{
mMyInventoryPanel= getChild<LLInventorySubTreePanel>("my_inventory_list");
LLUUID start_folder_id = mMyInventoryPanel->getModel()->getRootFolderID();
initLandmarksPanel(mMyInventoryPanel, start_folder_id);
initAccordion("tab_inventory", mMyInventoryPanel);
}
void LLLandmarksPanel::initLibraryInventroyPanel()
{
mLibraryInventoryPanel = getChild<LLInventorySubTreePanel>("library_list");
LLUUID start_folder_id = mLibraryInventoryPanel->getModel()->getLibraryRootFolderID();
initLandmarksPanel(mLibraryInventoryPanel, start_folder_id);
initAccordion("tab_library", mLibraryInventoryPanel);
}
void LLLandmarksPanel::initLandmarksPanel(LLInventorySubTreePanel* inventory_list, const LLUUID& start_folder_id)
{
inventory_list->buildSubtreeViewsFor(start_folder_id, &PLACES_INVENTORY_BUILDER);
inventory_list->setFilterTypes(0x1 << LLInventoryType::IT_LANDMARK);
inventory_list->setSelectCallback(boost::bind(&LLLandmarksPanel::onSelectionChange, this, inventory_list, _1, _2));
inventory_list->setShowFolderState(LLInventoryFilter::SHOW_NON_EMPTY_FOLDERS);
LLPlacesFolderView* root_folder = dynamic_cast<LLPlacesFolderView*>(inventory_list->getRootFolder());
if (root_folder)
{
root_folder->setupMenuHandle(LLInventoryType::IT_CATEGORY, mGearFolderMenu->getHandle());
root_folder->setupMenuHandle(LLInventoryType::IT_LANDMARK, mGearLandmarkMenu->getHandle());
}
}
void LLLandmarksPanel::initAccordion(const std::string& accordion_tab_name, LLInventorySubTreePanel* inventory_list)
{
LLAccordionCtrlTab* accordion_tab = getChild<LLAccordionCtrlTab>(accordion_tab_name);
accordion_tab->setDropDownStateChangedCallback(
boost::bind(&LLLandmarksPanel::onAccordionExpandedCollapsed, this, _2, inventory_list));
}
void LLLandmarksPanel::onAccordionExpandedCollapsed(const LLSD& param, LLInventorySubTreePanel* inventory_list)
{
bool expanded = param.asBoolean();
if(!expanded && (mCurrentSelectedList == inventory_list))
{
inventory_list->getRootFolder()->clearSelection();
mCurrentSelectedList = NULL;
updateVerbs();
}
}
void LLLandmarksPanel::deselectOtherThan(const LLInventorySubTreePanel* inventory_list)
{
if (inventory_list != mFavoritesInventoryPanel)
{
mFavoritesInventoryPanel->getRootFolder()->clearSelection();
}
if (inventory_list != mLandmarksInventoryPanel)
{
mLandmarksInventoryPanel->getRootFolder()->clearSelection();
}
if (inventory_list != mMyInventoryPanel)
{
mMyInventoryPanel->getRootFolder()->clearSelection();
}
if (inventory_list != mLibraryInventoryPanel)
{
mLibraryInventoryPanel->getRootFolder()->clearSelection();
}
}
// List Commands Handlers
void LLLandmarksPanel::initListCommandsHandlers()
{
mListCommands = getChild<LLPanel>("bottom_panel");
mListCommands->childSetAction(OPTIONS_BUTTON_NAME, boost::bind(&LLLandmarksPanel::onActionsButtonClick, this));
mListCommands->childSetAction(ADD_LANDMARK_BUTTON_NAME, boost::bind(&LLLandmarksPanel::onAddLandmarkButtonClick, this));
mListCommands->childSetAction(ADD_FOLDER_BUTTON_NAME, boost::bind(&LLLandmarksPanel::onAddFolderButtonClick, this));
mListCommands->childSetAction(TRASH_BUTTON_NAME, boost::bind(&LLLandmarksPanel::onTrashButtonClick, this));
mCommitCallbackRegistrar.add("Places.LandmarksGear.Add.Action", boost::bind(&LLLandmarksPanel::onAddAction, this, _2));
mCommitCallbackRegistrar.add("Places.LandmarksGear.CopyPaste.Action", boost::bind(&LLLandmarksPanel::onCopyPasteAction, this, _2));
mCommitCallbackRegistrar.add("Places.LandmarksGear.Custom.Action", boost::bind(&LLLandmarksPanel::onCustomAction, this, _2));
mCommitCallbackRegistrar.add("Places.LandmarksGear.Folding.Action", boost::bind(&LLLandmarksPanel::onFoldingAction, this, _2));
mEnableCallbackRegistrar.add("Places.LandmarksGear.Enable", boost::bind(&LLLandmarksPanel::isActionEnabled, this, _2));
mGearLandmarkMenu = LLUICtrlFactory::getInstance()->createFromFile<LLMenuGL>("menu_places_gear_landmark.xml", gMenuHolder, LLViewerMenuHolderGL::child_registry_t::instance());
mGearFolderMenu = LLUICtrlFactory::getInstance()->createFromFile<LLMenuGL>("menu_places_gear_folder.xml", gMenuHolder, LLViewerMenuHolderGL::child_registry_t::instance());
}
void LLLandmarksPanel::updateListCommands()
{
// TODO: should be false when "Received" folder is selected
bool add_folder_enabled = mCurrentSelectedList == mLandmarksInventoryPanel;
bool trash_enabled = false; // TODO: should be false when "Received" folder is selected
LLFolderViewItem* current_item = getCurSelectedItem();
if (current_item)
{
LLFolderViewEventListener* listenerp = current_item->getListener();
if (listenerp->getInventoryType() == LLInventoryType::IT_LANDMARK)
{
trash_enabled = mCurrentSelectedList != mLibraryInventoryPanel;
}
}
// keep Options & Add Landmark buttons always enabled
mListCommands->childSetEnabled(ADD_FOLDER_BUTTON_NAME, add_folder_enabled);
mListCommands->childSetEnabled(TRASH_BUTTON_NAME, trash_enabled);
}
void LLLandmarksPanel::onActionsButtonClick()
{
LLFolderViewItem* cur_item = NULL;
if(mCurrentSelectedList)
cur_item = mCurrentSelectedList->getRootFolder()->getCurSelectedItem();
if(!cur_item)
return;
LLFolderViewEventListener* listenerp = cur_item->getListener();
LLMenuGL* menu =NULL;
if (listenerp->getInventoryType() == LLInventoryType::IT_LANDMARK)
{
menu = mGearLandmarkMenu;
}
else if (listenerp->getInventoryType() == LLInventoryType::IT_CATEGORY)
{
mGearFolderMenu->getChild<LLMenuItemCallGL>("expand")->setVisible(!cur_item->isOpen());
mGearFolderMenu->getChild<LLMenuItemCallGL>("collapse")->setVisible(cur_item->isOpen());
menu = mGearFolderMenu;
}
if(menu)
{
menu->buildDrawLabels();
menu->updateParent(LLMenuGL::sMenuContainer);
LLView* actions_btn = getChild<LLView>(OPTIONS_BUTTON_NAME);
S32 menu_x, menu_y;
actions_btn->localPointToOtherView(0,actions_btn->getRect().getHeight(),&menu_x,&menu_y, this);
menu_y += menu->getRect().getHeight();
LLMenuGL::showPopup(this, menu, menu_x,menu_y);
}
}
void LLLandmarksPanel::onAddLandmarkButtonClick() const
{
if(LLLandmarkActions::landmarkAlreadyExists())
{
std::string location;
LLAgentUI::buildLocationString(location, LLAgentUI::LOCATION_FORMAT_FULL);
llwarns<<" Landmark already exists at location: "<< location<<llendl;
return;
}
LLSideTray::getInstance()->showPanel("panel_places", LLSD().insert("type", "create_landmark"));
}
void LLLandmarksPanel::onAddFolderButtonClick() const
{
LLFolderViewItem* item = getCurSelectedItem();
if(item && mCurrentSelectedList == mLandmarksInventoryPanel)
{
LLFolderBridge *parentBridge = NULL;
if(item-> getListener()->getInventoryType() == LLInventoryType::IT_LANDMARK)
{
parentBridge = dynamic_cast<LLFolderBridge*>(item->getParentFolder()->getListener());
/*WORKAROUND:*
LLFolderView::doIdle() is calling in each frame,
it changes selected items before LLFolderView::startRenamingSelectedItem.
To avoid it we have to change keyboardFocus.
*/
gFocusMgr.setKeyboardFocus(item->getParentFolder());
}
else if (item-> getListener()->getInventoryType() == LLInventoryType::IT_CATEGORY)
{
parentBridge = dynamic_cast<LLFolderBridge*>(item->getListener());
gFocusMgr.setKeyboardFocus(item);
}
menu_create_inventory_item(mCurrentSelectedList->getRootFolder(),parentBridge, LLSD("category"));
}
}
void LLLandmarksPanel::onTrashButtonClick() const
{
if(!mCurrentSelectedList) return;
mCurrentSelectedList->getRootFolder()->doToSelected(mCurrentSelectedList->getModel(), "delete");
}
void LLLandmarksPanel::onAddAction(const LLSD& userdata) const
{
std::string command_name = userdata.asString();
if("add_landmark" == command_name)
{
onAddLandmarkButtonClick();
}
else if ("category" == command_name)
{
onAddFolderButtonClick();
}
}
void LLLandmarksPanel::onCopyPasteAction(const LLSD& userdata) const
{
if(!mCurrentSelectedList)
return;
std::string command_name = userdata.asString();
if("copy_slurl" == command_name)
{
LLFolderViewItem* cur_item = getCurSelectedItem();
if(cur_item)
LLLandmarkActions::copySLURLtoClipboard(cur_item->getListener()->getUUID());
}
else if ( "paste" == command_name)
{
mCurrentSelectedList->getRootFolder()->paste();
}
else if ( "cut" == command_name)
{
mCurrentSelectedList->getRootFolder()->cut();
}
else
{
mCurrentSelectedList->getRootFolder()->doToSelected(mCurrentSelectedList->getModel(),command_name);
}
}
void LLLandmarksPanel::onFoldingAction(const LLSD& userdata) const
{
if(!mCurrentSelectedList) return;
LLFolderView* root_folder = mCurrentSelectedList->getRootFolder();
std::string command_name = userdata.asString();
if ("expand_all" == command_name)
{
root_folder->setOpenArrangeRecursively(TRUE, LLFolderViewFolder::RECURSE_DOWN);
root_folder->arrangeAll();
}
else if ("collapse_all" == command_name)
{
root_folder->closeAllFolders();
}
else
{
root_folder->doToSelected(&gInventory, userdata);
}
}
bool LLLandmarksPanel::isActionEnabled(const LLSD& userdata) const
{
std::string command_name = userdata.asString();
if("category" == command_name)
{
return mCurrentSelectedList == mLandmarksInventoryPanel;
}
else if("paste" == command_name)
{
return mCurrentSelectedList ? mCurrentSelectedList->getRootFolder()->canPaste() : false;
}
return true;
}
void LLLandmarksPanel::onCustomAction(const LLSD& userdata)
{
LLFolderViewItem* cur_item = getCurSelectedItem();
if(!cur_item)
return ;
std::string command_name = userdata.asString();
if("more_info" == command_name)
{
cur_item->getListener()->performAction(mCurrentSelectedList->getRootFolder(),mCurrentSelectedList->getModel(),"about");
}
else if ("teleport" == command_name)
{
onTeleport();
}
else if ("show_on_map" == command_name)
{
onShowOnMap();
}
else if ("create_pick" == command_name)
{
LLLandmark* landmark = getCurSelectedLandmark();
if(!landmark) return;
LLViewerRegion* region = gAgent.getRegion();
if (!region) return;
LLGlobalVec pos_global;
LLUUID region_id;
landmark->getGlobalPos(pos_global);
landmark->getRegionID(region_id);
LLVector3 region_pos((F32)fmod(pos_global.mdV[VX], (F64)REGION_WIDTH_METERS),
(F32)fmod(pos_global.mdV[VY], (F64)REGION_WIDTH_METERS),
(F32)pos_global.mdV[VZ]);
LLSD body;
std::string url = region->getCapability("RemoteParcelRequest");
if (!url.empty())
{
body["location"] = ll_sd_from_vector3(region_pos);
if (!region_id.isNull())
{
body["region_id"] = region_id;
}
if (!pos_global.isExactlyZero())
{
U64 region_handle = to_region_handle(pos_global);
body["region_handle"] = ll_sd_from_U64(region_handle);
}
LLHTTPClient::post(url, body, new LLRemoteParcelRequestResponder(getObserverHandle()));
}
else
{
llwarns << "Can't create pick for landmark for region" << region_id
<< ". Region: " << region->getName()
<< " does not support RemoteParcelRequest" << llendl;
}
}
}
void LLLandmarksPanel::onPickPanelExit( LLPanelPick* pick_panel, LLView* owner, const LLSD& params)
{
pick_panel->setVisible(FALSE);
owner->removeChild(pick_panel);
//we need remove observer to avoid processParcelInfo in the future.
LLRemoteParcelInfoProcessor::getInstance()->removeObserver(params["parcel_id"].asUUID(), this);
delete pick_panel;
pick_panel = NULL;
}
//////////////////////////////////////////////////////////////////////////
// HELPER FUNCTIONS
//////////////////////////////////////////////////////////////////////////
static void filter_list(LLInventorySubTreePanel* inventory_list, const std::string& string)
{
if (string == "")
{
inventory_list->setFilterSubString(LLStringUtil::null);
// re-open folders that were initially open
inventory_list->restoreFolderState();
}
gInventory.startBackgroundFetch();
if (inventory_list->getFilterSubString().empty() && string.empty())
{
// current filter and new filter empty, do nothing
return;
}
// save current folder open state if no filter currently applied
if (inventory_list->getRootFolder()->getFilterSubString().empty())
{
inventory_list->saveFolderState();
}
// set new filter string
inventory_list->setFilterSubString(string);
}
// EOF

View File

@ -33,14 +33,20 @@
#ifndef LL_LLPANELLANDMARKS_H
#define LL_LLPANELLANDMARKS_H
#include "lllandmark.h"
// newview
#include "llinventorymodel.h"
#include "llpanelplacestab.h"
#include "llpanelpick.h"
#include "llremoteparcelrequest.h"
class LLFolderViewItem;
class LLMenuGL;
class LLInventoryPanel;
class LLSaveFolderState;
class LLInventorySubTreePanel;
class LLLandmarksPanel : public LLPanelPlacesTab
class LLLandmarksPanel : public LLPanelPlacesTab, LLRemoteParcelInfoObserver
{
public:
LLLandmarksPanel();
@ -50,17 +56,58 @@ public:
/*virtual*/ void onSearchEdit(const std::string& string);
/*virtual*/ void onShowOnMap();
/*virtual*/ void onTeleport();
///*virtual*/ void onCopySLURL();
/*virtual*/ void updateVerbs();
void onSelectionChange(const std::deque<LLFolderViewItem*> &items, BOOL user_action);
void onSelectionChange(LLInventorySubTreePanel* inventory_list, const std::deque<LLFolderViewItem*> &items, BOOL user_action);
void onSelectorButtonClicked();
void setSelectedItem(const LLUUID& obj_id);
protected:
/**
* @return true - if current selected panel is not null and selected item is a landmark
*/
bool isLandmarkSelected() const;
LLLandmark* getCurSelectedLandmark() const;
LLFolderViewItem* getCurSelectedItem () const;
//LLRemoteParcelInfoObserver interface
/*virtual*/ void processParcelInfo(const LLParcelData& parcel_data);
/*virtual*/ void setParcelID(const LLUUID& parcel_id);
/*virtual*/ void setErrorStatus(U32 status, const std::string& reason);
private:
void initFavoritesInventroyPanel();
void initLandmarksInventroyPanel();
void initMyInventroyPanel();
void initLibraryInventroyPanel();
void initLandmarksPanel(LLInventorySubTreePanel* inventory_list, const LLUUID& start_folder_id);
void initAccordion(const std::string& accordion_tab_name, LLInventorySubTreePanel* inventory_list);
void onAccordionExpandedCollapsed(const LLSD& param, LLInventorySubTreePanel* inventory_list);
void deselectOtherThan(const LLInventorySubTreePanel* inventory_list);
// List Commands Handlers
void initListCommandsHandlers();
void updateListCommands();
void onActionsButtonClick();
void onAddLandmarkButtonClick() const;
void onAddFolderButtonClick() const;
void onTrashButtonClick() const;
void onAddAction(const LLSD& command_name) const;
void onCopyPasteAction(const LLSD& command_name) const;
void onFoldingAction(const LLSD& command_name) const;
bool isActionEnabled(const LLSD& command_name) const;
void onCustomAction(const LLSD& command_name);
void onPickPanelExit( LLPanelPick* pick_panel, LLView* owner, const LLSD& params);
private:
LLInventoryPanel* mInventoryPanel;
LLSaveFolderState* mSavedFolderState;
LLButton* mActionBtn;
LLInventorySubTreePanel* mFavoritesInventoryPanel;
LLInventorySubTreePanel* mLandmarksInventoryPanel;
LLInventorySubTreePanel* mMyInventoryPanel;
LLInventorySubTreePanel* mLibraryInventoryPanel;
LLMenuGL* mGearLandmarkMenu;
LLMenuGL* mGearFolderMenu;
LLInventorySubTreePanel* mCurrentSelectedList;
LLPanel* mListCommands;
};
#endif //LL_LLPANELLANDMARKS_H

View File

@ -39,6 +39,7 @@
#include "llpanel.h"
#include "llremoteparcelrequest.h"
#include "llavatarpropertiesprocessor.h"
class LLTextureCtrl;
class LLMessageSystem;

View File

@ -650,6 +650,23 @@ void LLPanelPlaces::onOverflowMenuItemClicked(const LLSD& param)
mPlaceInfo->createPick(mPosGlobal, mPickPanel);
}
else if (item == "add_to_favbar")
{
if ( mItem.notNull() )
{
LLUUID favorites_id = gInventory.findCategoryUUIDForType(LLAssetType::AT_FAVORITE);
if ( favorites_id.notNull() )
{
copy_inventory_item(gAgent.getID(),
mItem->getPermissions().getOwner(),
mItem->getUUID(),
favorites_id,
std::string(),
LLPointer<LLInventoryCallback>(NULL));
llinfos << "Copied inventory item #" << mItem->getUUID() << " to favorites." << llendl;
}
}
}
}
void LLPanelPlaces::onBackButtonClicked()

View File

@ -47,6 +47,10 @@
#include "lllandmarkactions.h"
#include "llclipboard.h"
// Maximum number of items that can be added to a list in one pass.
// Used to limit time spent for items list update per frame.
static const U32 ADD_LIMIT = 50;
class LLTeleportHistoryFlatItem : public LLPanel
{
public:
@ -56,6 +60,7 @@ public:
virtual BOOL postBuild();
S32 getIndex() { return mIndex; }
const std::string& getRegionName() { return mRegionName;}
/*virtual*/ void setValue(const LLSD& value);
@ -211,9 +216,10 @@ void LLTeleportHistoryPanel::ContextMenu::onCopy()
LLTeleportHistoryPanel::LLTeleportHistoryPanel()
: LLPanelPlacesTab(),
mFilterSubString(LLStringUtil::null),
mDirty(true),
mCurrentItem(0),
mTeleportHistory(NULL),
mHistoryAccordion(NULL),
mStarButton(NULL),
mAccordionTabMenu(NULL),
mLastSelectedScrollList(NULL)
{
@ -277,12 +283,18 @@ BOOL LLTeleportHistoryPanel::postBuild()
if(gear_menu)
mGearMenuHandle = gear_menu->getHandle();
mStarButton = getChild<LLButton>("star_btn");
mStarButton->setCommitCallback(boost::bind(&LLTeleportHistoryPanel::onStarButtonCommit, this));
return TRUE;
}
// virtual
void LLTeleportHistoryPanel::draw()
{
if (mDirty)
refresh();
LLPanelPlacesTab::draw();
}
// virtual
void LLTeleportHistoryPanel::onSearchEdit(const std::string& string)
{
@ -361,8 +373,6 @@ void LLTeleportHistoryPanel::updateVerbs()
{
mTeleportBtn->setEnabled(false);
mShowOnMapBtn->setEnabled(false);
mStarButton->setEnabled(false);
mStarButton->setToolTip(LLStringExplicit(""));
return;
}
@ -370,141 +380,138 @@ void LLTeleportHistoryPanel::updateVerbs()
mTeleportBtn->setEnabled(NULL != itemp && itemp->getIndex() < (S32)mTeleportHistory->getItems().size() - 1);
mShowOnMapBtn->setEnabled(NULL != itemp);
if (NULL != itemp)
{
LLViewerInventoryItem *landmark = LLLandmarkActions::findLandmarkForGlobalPos(
mTeleportHistory->getItems()[itemp->getIndex()].mGlobalPos);
mStarButton->setEnabled(true);
if (!landmark || landmark->getUUID().isNull())
{
mStarButton->setToggleState(true);
// Landmark can be created only for current agent positon, which is most recent (last) item in teleport history.
// mTeleportBtn is disabled only for that item.
mStarButton->setToolTip(mTeleportBtn->getEnabled() ? getString("cant_create_lm_here") : getString("create_landmark"));
}
else
{
mStarButton->setToggleState(false);
mStarButton->setToolTip(getString("open_landmark"));
}
}
else
{
mStarButton->setEnabled(false);
mStarButton->setToolTip(LLStringExplicit(""));
}
}
void LLTeleportHistoryPanel::showTeleportHistory()
void LLTeleportHistoryPanel::getNextTab(const LLDate& item_date, S32& tab_idx, LLDate& tab_date)
{
if (!mHistoryAccordion)
return;
const LLTeleportHistoryStorage::slurl_list_t& hist_items = mTeleportHistory->getItems();
const U32 seconds_in_day = 24 * 60 * 60;
LLDate curr_date = LLDate::now();
S32 curr_tab = -1;
S32 tabs_cnt = mItemContainers.size();
S32 curr_year = 0, curr_month = 0, curr_day = 0;
curr_date.split(&curr_year, &curr_month, &curr_day);
curr_date.fromYMDHMS(curr_year, curr_month, curr_day); // Set hour, min, and sec to 0
curr_date.secondsSinceEpoch(curr_date.secondsSinceEpoch() + seconds_in_day);
tab_date = LLDate::now();
tab_date.split(&curr_year, &curr_month, &curr_day);
tab_date.fromYMDHMS(curr_year, curr_month, curr_day); // Set hour, min, and sec to 0
tab_date.secondsSinceEpoch(tab_date.secondsSinceEpoch() + seconds_in_day);
tab_idx = -1;
while (tab_idx < tabs_cnt - 1 && item_date < tab_date)
{
tab_idx++;
if (tab_idx <= tabs_cnt - 4)
{
tab_date.secondsSinceEpoch(tab_date.secondsSinceEpoch() - seconds_in_day);
}
else if (tab_idx == tabs_cnt - 3) // 6 day and older, low boundary is 1 month
{
tab_date = LLDate::now();
tab_date.split(&curr_year, &curr_month, &curr_day);
curr_month--;
if (0 == curr_month)
{
curr_month = 12;
curr_year--;
}
tab_date.fromYMDHMS(curr_year, curr_month, curr_day);
}
else if (tab_idx == tabs_cnt - 2) // 1 month and older, low boundary is 6 months
{
tab_date = LLDate::now();
tab_date.split(&curr_year, &curr_month, &curr_day);
if (curr_month > 6)
{
curr_month -= 6;
}
else
{
curr_month += 6;
curr_year--;
}
tab_date.fromYMDHMS(curr_year, curr_month, curr_day);
}
else // 6 months and older
{
tab_date.secondsSinceEpoch(0);
}
}
}
void LLTeleportHistoryPanel::refresh()
{
if (!mHistoryAccordion)
{
mDirty = false;
return;
}
const LLTeleportHistoryStorage::slurl_list_t& items = mTeleportHistory->getItems();
LLDate tab_boundary_date = LLDate::now();
LLFlatListView* curr_flat_view = NULL;
S32 index = hist_items.size() - 1;
for (LLTeleportHistoryStorage::slurl_list_t::const_reverse_iterator iter = hist_items.rbegin();
iter != hist_items.rend(); ++iter, --index)
U32 added_items = 0;
while (mCurrentItem >= 0)
{
std::string landmark_title = (*iter).mTitle;
std::string landmark_title = items[mCurrentItem].mTitle;
LLStringUtil::toUpper(landmark_title);
std::string::size_type match_offset = mFilterSubString.size() ? landmark_title.find(mFilterSubString) : std::string::npos;
bool passed = mFilterSubString.size() == 0 || match_offset != std::string::npos;
if (!passed)
continue;
if (curr_tab < tabs_cnt - 1)
{
const LLDate &date = (*iter).mDate;
mCurrentItem--;
continue;
}
if (date < curr_date)
{
LLAccordionCtrlTab* tab = NULL;
while (curr_tab < tabs_cnt - 1 && date < curr_date)
{
curr_tab++;
const LLDate &date = items[mCurrentItem].mDate;
tab = mItemContainers.get(mItemContainers.size() - 1 - curr_tab);
tab->setVisible(false);
if (date < tab_boundary_date)
{
S32 tab_idx = 0;
getNextTab(date, tab_idx, tab_boundary_date);
if (curr_tab <= tabs_cnt - 4)
{
curr_date.secondsSinceEpoch(curr_date.secondsSinceEpoch() - seconds_in_day);
}
else if (curr_tab == tabs_cnt - 3) // 6 day and older, low boundary is 1 month
{
curr_date = LLDate::now();
curr_date.split(&curr_year, &curr_month, &curr_day);
curr_month--;
if (0 == curr_month)
{
curr_month = 12;
curr_year--;
}
curr_date.fromYMDHMS(curr_year, curr_month, curr_day);
}
else if (curr_tab == tabs_cnt - 2) // 1 month and older, low boundary is 6 months
{
curr_date = LLDate::now();
curr_date.split(&curr_year, &curr_month, &curr_day);
if (curr_month > 6)
{
curr_month -= 6;
}
else
{
curr_month += 6;
curr_year--;
}
curr_date.fromYMDHMS(curr_year, curr_month, curr_day);
}
else // 6 months and older
{
curr_date.secondsSinceEpoch(0);
}
}
LLAccordionCtrlTab* tab = mItemContainers.get(mItemContainers.size() - 1 - tab_idx);
tab->setVisible(true);
tab->setVisible(true);
curr_flat_view = getFlatListViewFromTab(tab);
if (curr_flat_view)
{
curr_flat_view->clear();
}
}
curr_flat_view = getFlatListViewFromTab(tab);
}
if (curr_flat_view)
{
curr_flat_view->addItem(new LLTeleportHistoryFlatItem(index, &mContextMenu, (*iter).mTitle));
}
}
curr_flat_view->addItem(new LLTeleportHistoryFlatItem(mCurrentItem, &mContextMenu, items[mCurrentItem].mTitle));
// Hide empty tabs from current to bottom
for (curr_tab++; curr_tab < tabs_cnt; curr_tab++)
mItemContainers.get(mItemContainers.size() - 1 - curr_tab)->setVisible(false);
mCurrentItem--;
if (++added_items >= ADD_LIMIT)
break;
}
mHistoryAccordion->arrange();
updateVerbs();
if (mCurrentItem < 0)
mDirty = false;
}
void LLTeleportHistoryPanel::showTeleportHistory()
{
mDirty = true;
mCurrentItem = mTeleportHistory->getItems().size() - 1;
for (S32 n = mItemContainers.size() - 1; n >= 0; --n)
{
LLAccordionCtrlTab* tab = mItemContainers.get(n);
tab->setVisible(false);
LLFlatListView* fv = getFlatListViewFromTab(tab);
if (fv)
fv->clear();
}
refresh();
}
void LLTeleportHistoryPanel::handleItemSelect(LLFlatListView* selected)
@ -667,28 +674,3 @@ void LLTeleportHistoryPanel::onGearButtonClicked()
LLMenuGL::showPopup(this, menu, menu_x, menu_y);
}
void LLTeleportHistoryPanel::onStarButtonCommit()
{
if (!mLastSelectedScrollList)
return;
LLTeleportHistoryFlatItem* itemp = dynamic_cast<LLTeleportHistoryFlatItem *> (mLastSelectedScrollList->getSelectedItem());
if(!itemp)
return;
if (itemp->getIndex() < (S32)mTeleportHistory->getItems().size() - 1)
{
LLTeleportHistoryFlatItem::showPlaceInfoPanel(itemp->getIndex());
}
else
{
LLViewerInventoryItem *landmark = LLLandmarkActions::findLandmarkForGlobalPos(
mTeleportHistory->getItems()[itemp->getIndex()].mGlobalPos);
if (!landmark || landmark->getUUID().isNull())
LLSideTray::getInstance()->showPanel("panel_places", LLSD().insert("type", "create_landmark"));
else
LLTeleportHistoryFlatItem::showPlaceInfoPanel(itemp->getIndex());
}
}

View File

@ -69,6 +69,8 @@ public:
virtual ~LLTeleportHistoryPanel();
/*virtual*/ BOOL postBuild();
/*virtual*/ void draw();
/*virtual*/ void onSearchEdit(const std::string& string);
/*virtual*/ void onShowOnMap();
/*virtual*/ void onTeleport();
@ -86,17 +88,19 @@ private:
void onClearTeleportHistory();
bool onClearTeleportHistoryDialog(const LLSD& notification, const LLSD& response);
void refresh();
void getNextTab(const LLDate& item_date, S32& curr_tab, LLDate& tab_date);
void showTeleportHistory();
void handleItemSelect(LLFlatListView* );
LLFlatListView* getFlatListViewFromTab(LLAccordionCtrlTab *);
void onGearButtonClicked();
void onStarButtonCommit();
LLTeleportHistoryStorage* mTeleportHistory;
LLAccordionCtrl* mHistoryAccordion;
LLButton * mStarButton;
LLFlatListView* mLastSelectedScrollList;
bool mDirty;
S32 mCurrentItem;
std::string mFilterSubString;
typedef LLDynamicArray<LLAccordionCtrlTab*> item_containers_t;

View File

@ -0,0 +1,212 @@
/**
* @file llplacesinventorybridge.cpp
* @brief Implementation of the Inventory-Folder-View-Bridge classes for Places Panel.
*
* $LicenseInfo:firstyear=2009&license=viewergpl$
*
* Copyright (c) 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 "llmenugl.h"
#include "llplacesinventorybridge.h"
#include "llfloaterinventory.h" // for LLInventoryPanel
#include "llfolderview.h" // for FIRST_SELECTED_ITEM
static const std::string LANDMARKS_INVENTORY_LIST_NAME("landmarks_list");
bool is_landmarks_panel(const LLInventoryPanel* inv_panel)
{
if (NULL == inv_panel)
return false;
return inv_panel->getName() == LANDMARKS_INVENTORY_LIST_NAME;
}
void fill_items_with_menu_items(std::vector<std::string>& items, LLMenuGL& menu)
{
LLView::child_list_const_iter_t itor;
for (itor = menu.beginChild(); itor != menu.endChild(); ++itor)
{
std::string name = (*itor)->getName();
items.push_back(name);
}
}
// virtual
void LLPlacesLandmarkBridge::buildContextMenu(LLMenuGL& menu, U32 flags)
{
std::vector<std::string> items;
std::vector<std::string> disabled_items;
if(isInTrash())
{
items.push_back(std::string("Purge Item"));
if (!isItemRemovable())
{
disabled_items.push_back(std::string("Purge Item"));
}
items.push_back(std::string("Restore Item"));
}
else
{
fill_items_with_menu_items(items, menu);
// Disable "Landmark More Information" menu item for
// multiple landmarks selected. Only one landmark
// info panel can be shown at a time.
if ((flags & FIRST_SELECTED_ITEM) == 0)
{
disabled_items.push_back(std::string("more_info"));
}
}
hideContextEntries(menu, items, disabled_items);
}
void LLPlacesFolderBridge::buildContextMenu(LLMenuGL& menu, U32 flags)
{
{
std::vector<std::string> items;
std::vector<std::string> disabled_items;
LLInventoryPanel* inv_panel = dynamic_cast<LLInventoryPanel*>(mInventoryPanel.get());
bool is_open = false;
bool disable_changing = true;
if (inv_panel)
{
LLFolderViewFolder* folder = dynamic_cast<LLFolderViewFolder*>(inv_panel->getRootFolder()->getItemByID(mUUID));
is_open = (NULL != folder) && folder->isOpen();
disable_changing = !is_landmarks_panel(inv_panel);
}
// collect all items' names
fill_items_with_menu_items(items, menu);
// remove expand or collapse menu item depend on folder state
std::string collapse_expand_item_to_hide(is_open ? "expand" : "collapse");
std::vector<std::string>::iterator it = std::find(items.begin(), items.end(), collapse_expand_item_to_hide);
if (it != items.end()) items.erase(it);
if (disable_changing)
{
disabled_items.push_back(std::string("add_folder"));
disabled_items.push_back(std::string("rename"));
disabled_items.push_back(std::string("delete"));
}
// repeat parent functionality
sSelf = this; // necessary for "New Folder" functionality
hideContextEntries(menu, items, disabled_items);
}
}
//virtual
void LLPlacesFolderBridge::performAction(LLFolderView* folder, LLInventoryModel* model, std::string action)
{
if ("expand" == action)
{
LLFolderViewFolder* act_folder = getFolder();
act_folder->toggleOpen();
}
else if ("collapse" == action)
{
LLFolderViewFolder* act_folder = getFolder();
act_folder->toggleOpen();
}
else
{
LLFolderBridge::performAction(folder, model, action);
}
}
LLFolderViewFolder* LLPlacesFolderBridge::getFolder()
{
LLFolderViewFolder* folder = NULL;
LLInventoryPanel* inv_panel = dynamic_cast<LLInventoryPanel*>(mInventoryPanel.get());
if (inv_panel)
{
folder = dynamic_cast<LLFolderViewFolder*>(inv_panel->getRootFolder()->getItemByID(mUUID));
}
return folder;
}
// virtual
LLInvFVBridge* LLPlacesInventoryBridgeBuilder::createBridge(
LLAssetType::EType asset_type,
LLAssetType::EType actual_asset_type,
LLInventoryType::EType inv_type,
LLInventoryPanel* inventory,
const LLUUID& uuid,
U32 flags/* = 0x00*/) const
{
LLInvFVBridge* new_listener = NULL;
switch(asset_type)
{
case LLAssetType::AT_LANDMARK:
if(!(inv_type == LLInventoryType::IT_LANDMARK))
{
llwarns << LLAssetType::lookup(asset_type) << " asset has inventory type " << safe_inv_type_lookup(inv_type) << " on uuid " << uuid << llendl;
}
new_listener = new LLPlacesLandmarkBridge(inv_type, inventory, uuid, flags);
break;
case LLAssetType::AT_CATEGORY:
if (actual_asset_type == LLAssetType::AT_LINK_FOLDER)
{
// *TODO: Create a link folder handler instead if it is necessary
new_listener = LLInventoryFVBridgeBuilder::createBridge(
asset_type,
actual_asset_type,
inv_type,
inventory,
uuid,
flags);
break;
}
new_listener = new LLPlacesFolderBridge(inv_type, inventory, uuid);
break;
default:
new_listener = LLInventoryFVBridgeBuilder::createBridge(
asset_type,
actual_asset_type,
inv_type,
inventory,
uuid,
flags);
}
return new_listener;
}
// EOF

View File

@ -0,0 +1,91 @@
/**
* @file llplacesinventorybridge.h
* @brief Declaration of the Inventory-Folder-View-Bridge classes for Places Panel.
*
* $LicenseInfo:firstyear=2009&license=viewergpl$
*
* Copyright (c) 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$
*/
#ifndef LL_LLPLACESINVENTORYBRIDGE_H
#define LL_LLPLACESINVENTORYBRIDGE_H
#include "llinventorybridge.h"
class LLFolderViewFolder;
/**
* Overridden version of the Inventory-Folder-View-Bridge for Places Panel (Landmarks Tab)
*/
class LLPlacesLandmarkBridge : public LLLandmarkBridge
{
friend class LLPlacesInventoryBridgeBuilder;
public:
/*virtual*/ void buildContextMenu(LLMenuGL& menu, U32 flags);
protected:
LLPlacesLandmarkBridge(LLInventoryType::EType type, LLInventoryPanel* inventory, const LLUUID& uuid, U32 flags = 0x00)
: LLLandmarkBridge(inventory, uuid, flags) {mInvType = type;}
};
/**
* Overridden version of the Inventory-Folder-View-Bridge for Folders
*/
class LLPlacesFolderBridge : public LLFolderBridge
{
friend class LLPlacesInventoryBridgeBuilder;
public:
/*virtual*/ void buildContextMenu(LLMenuGL& menu, U32 flags);
/*virtual*/ void performAction(LLFolderView* folder, LLInventoryModel* model, std::string action);
protected:
LLPlacesFolderBridge(LLInventoryType::EType type, LLInventoryPanel* inventory, const LLUUID& uuid)
: LLFolderBridge(inventory, uuid) {mInvType = type;}
LLFolderViewFolder* getFolder();
};
/**
* This class intended to override default InventoryBridgeBuilder for Inventory Panel.
*
* It builds Bridges for Landmarks and Folders in Places Landmarks Panel
*/
class LLPlacesInventoryBridgeBuilder : public LLInventoryFVBridgeBuilder
{
public:
/*virtual*/ LLInvFVBridge* createBridge(
LLAssetType::EType asset_type,
LLAssetType::EType actual_asset_type,
LLInventoryType::EType inv_type,
LLInventoryPanel* inventory,
const LLUUID& uuid,
U32 flags = 0x00) const;
};
#endif // LL_LLPLACESINVENTORYBRIDGE_H

View File

@ -559,6 +559,15 @@ void LLSideTray::highlightFocused()
}
BOOL LLSideTray::handleScrollWheel(S32 x, S32 y, S32 mask)
{
BOOL ret = LLPanel::handleScrollWheel(x,y,mask);
if(!ret && childFromPoint(x,y) != 0 )
return TRUE;//mouse wheel over sidetray buttons, eat mouse wheel
return ret;
}
//virtual
BOOL LLSideTray::handleMouseDown (S32 x, S32 y, MASK mask)
{
@ -641,7 +650,9 @@ LLPanel* LLSideTray::showPanel (const std::string& panel_name, const LLSD& para
LLView* view = (*child_it)->findChildView(panel_name,true);
if(view)
{
onTabButtonClick((*child_it)->getName());
selectTabByName ((*child_it)->getName());
if(mCollapsed)
expandSideBar();
LLSideTrayPanelContainer* container = dynamic_cast<LLSideTrayPanelContainer*>(view->getParent());
if(container)

View File

@ -203,6 +203,7 @@ public:
bool addChild (LLView* view, S32 tab_group);
BOOL handleMouseDown (S32 x, S32 y, MASK mask);
BOOL handleScrollWheel(S32 x, S32 y, S32 mask);
void reshape (S32 width, S32 height, BOOL called_from_parent = TRUE);
S32 getTrayWidth();

View File

@ -45,29 +45,6 @@
#include "llnotificationmanager.h"
// IM session ID can be the same as Avatar UUID. (See LLIMMgr::computeSessionID)
// Probably notification ID also can be the same as Avatar UUID.
// In case when session ID & notification ID are the same it will be impossible to add both
// appropriate Items into Flat List.
// Functions below are intended to wrap passed LLUUID into LLSD value with different "type".
// Use them anywhere you need to add, get, remove items via the list
inline
LLSD get_notification_value(const LLUUID& notification_id)
{
return LLSD()
.insert("type", "notification")
.insert("uuid", notification_id);
}
inline
LLSD get_session_value(const LLUUID& session_id)
{
return LLSD()
.insert("type", "im_chiclet")
.insert("uuid", session_id);
}
//---------------------------------------------------------------------------------
LLSysWellWindow::LLSysWellWindow(const LLSD& key) : LLDockableFloater(NULL, key),
mChannel(NULL),
@ -157,7 +134,7 @@ LLSysWellWindow::~LLSysWellWindow()
//---------------------------------------------------------------------------------
void LLSysWellWindow::addItem(LLSysWellItem::Params p)
{
LLSD value = get_notification_value(p.notification_id);
LLSD value = p.notification_id;
// do not add clones
if( mMessageList->getItemByValue(value))
return;
@ -191,7 +168,7 @@ void LLSysWellWindow::clear()
//---------------------------------------------------------------------------------
void LLSysWellWindow::removeItemByID(const LLUUID& id)
{
if(mMessageList->removeItemByValue(get_notification_value(id)))
if(mMessageList->removeItemByValue(id))
{
handleItemRemoved(IT_NOTIFICATION);
reshapeWindow();
@ -357,7 +334,7 @@ void LLSysWellWindow::reshapeWindow()
LLChiclet* LLSysWellWindow::findIMChiclet(const LLUUID& sessionId)
{
LLChiclet* res = NULL;
RowPanel* panel = mMessageList->getTypedItemByValue<RowPanel>(get_session_value(sessionId));
RowPanel* panel = mMessageList->getTypedItemByValue<RowPanel>(sessionId);
if (panel != NULL)
{
res = panel->mChiclet;
@ -371,7 +348,7 @@ void LLSysWellWindow::addIMRow(const LLUUID& sessionId, S32 chicletCounter,
const std::string& name, const LLUUID& otherParticipantId)
{
RowPanel* item = new RowPanel(this, sessionId, chicletCounter, name, otherParticipantId);
if (mMessageList->insertItemAfter(mSeparator, item, get_session_value(sessionId)))
if (mMessageList->insertItemAfter(mSeparator, item, sessionId))
{
handleItemAdded(IT_INSTANT_MESSAGE);
}
@ -389,7 +366,7 @@ void LLSysWellWindow::addIMRow(const LLUUID& sessionId, S32 chicletCounter,
//---------------------------------------------------------------------------------
void LLSysWellWindow::delIMRow(const LLUUID& sessionId)
{
if (mMessageList->removeItemByValue(get_session_value(sessionId)))
if (mMessageList->removeItemByValue(sessionId))
{
handleItemRemoved(IT_INSTANT_MESSAGE);
}
@ -423,7 +400,7 @@ void LLSysWellWindow::sessionAdded(const LLUUID& session_id,
const std::string& name, const LLUUID& other_participant_id)
{
//*TODO get rid of get_session_value, session_id's are unique, cause performance degradation with lots chiclets (IB)
if (mMessageList->getItemByValue(get_session_value(session_id)) == NULL)
if (mMessageList->getItemByValue(session_id) == NULL)
{
S32 chicletCounter = LLIMModel::getInstance()->getNumUnread(session_id);
if (chicletCounter > -1)
@ -443,6 +420,17 @@ void LLSysWellWindow::sessionRemoved(const LLUUID& sessionId)
LLBottomTray::getInstance()->getSysWell()->updateUreadIMNotifications();
}
void LLSysWellWindow::sessionIDUpdated(const LLUUID& old_session_id, const LLUUID& new_session_id)
{
//for outgoing ad-hoc and group im sessions only
LLChiclet* chiclet = findIMChiclet(old_session_id);
if (chiclet)
{
chiclet->setSessionId(new_session_id);
mMessageList->updateValue(old_session_id, new_session_id);
}
}
void LLSysWellWindow::handleItemAdded(EItemType added_item_type)
{
bool should_be_shown = ++mTypedItemsCount[added_item_type] == 1 && anotherTypeExists(added_item_type);

View File

@ -108,6 +108,7 @@ private:
// LLIMSessionObserver observe triggers
virtual void sessionAdded(const LLUUID& session_id, const std::string& name, const LLUUID& other_participant_id);
virtual void sessionRemoved(const LLUUID& session_id);
void sessionIDUpdated(const LLUUID& old_session_id, const LLUUID& new_session_id);
// pointer to a corresponding channel's instance
LLNotificationsUI::LLScreenChannel* mChannel;

View File

@ -36,178 +36,106 @@
#include "llviewercontrol.h"
#include "lluiconstants.h"
#include "llrect.h"
#include "lliconctrl.h"
#include "lltexteditor.h"
#include "lltextbox.h"
#include "lldbstrings.h"
#include "llchat.h"
#include "llfloaterchat.h"
#include "lltrans.h"
#include "lloverlaybar.h"
const S32 BOTTOM_PAD = VPAD * 3;
const S32 BUTTON_WIDTH = 90;
//static
const LLFontGL* LLToastNotifyPanel::sFont = NULL;
const LLFontGL* LLToastNotifyPanel::sFontSmall = NULL;
LLToastNotifyPanel::LLToastNotifyPanel(LLNotificationPtr& notification) : LLToastPanel(notification) {
LLToastNotifyPanel::LLToastNotifyPanel(LLNotificationPtr& notification) :
LLToastPanel(notification),
mTextBox(NULL),
mIcon(NULL),
mInfoPanel(NULL),
mControlPanel(NULL),
mNumOptions(0),
mNumButtons(0),
mAddedDefaultBtn(false)
{
LLUICtrlFactory::getInstance()->buildPanel(this, "panel_notification.xml");
mInfoPanel = getChild<LLPanel>("info_panel");
mControlPanel = getChild<LLPanel>("control_panel");
mIcon = getChild<LLIconCtrl>("info_icon");
// customize panel's attributes
// is it intended for displaying a tip
mIsTip = notification->getType() == "notifytip";
mNumOptions = 0;
mNumButtons = 0;
mIsScriptDialog = (notification->getName() == "ScriptDialog"
|| notification->getName() == "ScriptDialogGroup");
mAddedDefaultBtn = false;
// 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;
// clicking on a button does not steal current focus
setIsChrome(TRUE);
// class init
// setup parameters
// get a notification message
mMessage = notification->getMessage();
// init font variables
if (!sFont)
{
sFont = LLFontGL::getFontSansSerif();
sFontSmall = LLFontGL::getFontSansSerifSmall();
}
// setup paramaters
mMessage = notification->getMessage();
// clicking on a button does not steal current focus
setIsChrome(TRUE);
// 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;
// get a form for the notification
LLNotificationFormPtr form(notification->getForm());
// get number of elements
mNumOptions = form->getNumElements();
LLRect rect = mIsTip ? getNotifyTipRect(mMessage)
: getNotifyRect(mNumOptions, mIsScriptDialog, 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;
LLIconCtrl::Params common_params;
common_params.rect(LLRect(x, y, x+32, TOP-32));
common_params.mouse_opaque(false);
common_params.follows.flags(FOLLOWS_LEFT | FOLLOWS_TOP);
// customize panel's outfit
// preliminary adjust panel's layout
mIsTip ? adjustPanelForTipNotice() : adjustPanelForScriptNotice(form);
// choose a right icon
if (mIsTip)
{
// use the tip notification icon
common_params.image(LLUI::getUIImage("notify_tip_icon.tga"));
icon = LLUICtrlFactory::create<LLIconCtrl> (common_params);
mIcon->setValue("notify_tip_icon.tga");
LLRect icon_rect = mIcon->getRect();
icon_rect.setLeftTopAndSize(icon_rect.mLeft, getRect().getHeight() - VPAD, icon_rect.getWidth(), icon_rect.getHeight());
mIcon->setRect(icon_rect);
}
else if (mIsCaution)
{
// use the caution notification icon
common_params.image(LLUI::getUIImage("notify_caution_icon.tga"));
icon = LLUICtrlFactory::create<LLIconCtrl> (common_params);
mIcon->setValue("notify_caution_icon.tga");
}
else
{
// use the default notification icon
common_params.image(LLUI::getUIImage("notify_box_icon.tga"));
icon = LLUICtrlFactory::create<LLIconCtrl> (common_params);
mIcon->setValue("notify_box_icon.tga");
}
icon->setMouseOpaque(FALSE);
addChild(icon);
x += HPAD + HPAD + 32;
// adjust text options according to the notification type
// 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;
LLTextBox::Params params;
params.name("caution_box");
params.rect(LLRect(x, y, getRect().getWidth() - 2, caution_height));
params.font(sFont);
params.mouse_opaque(false);
params.font.style("BOLD");
params.text_color(LLUIColorTable::instance().getColor("NotifyCautionWarnColor"));
params.bg_readonly_color(LLUIColorTable::instance().getColor("NotifyCautionBoxColor"));
params.border_visible(false);
params.wrap(true);
caution_box = LLUICtrlFactory::create<LLTextBox> (params);
caution_box->setValue(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;
mTextBox = getChild<LLTextBox>("caution_text_box");
}
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.
LLTextEditor::Params params;
params.name("box");
params.rect(LLRect(x, y, getRect().getWidth()-2, mIsTip ? BOTTOM : BTN_TOP+16));
params.max_text_length(MAX_LENGTH);
params.read_only(true);
params.default_text(mMessage);
params.font(sFont);
params.embedded_items(false);
params.wrap(true);
params.tab_stop(false);
params.mouse_opaque(false);
params.bg_readonly_color(LLColor4::transparent);
params.text_readonly_color(LLUIColorTable::instance().getColor("NotifyTextColor"));
params.enabled(false);
params.border_visible(false);
text = LLUICtrlFactory::create<LLTextEditor> (params);
addChild(text);
mTextBox = getChild<LLTextEditor>("text_editor_box");
}
if (mIsTip)
{
// TODO: Make a separate archive for these.
LLChat chat(mMessage);
chat.mSourceType = CHAT_SOURCE_SYSTEM;
LLFloaterChat::addChatHistory(chat);
}
else
{
LLButton::Params p;
p.name(std::string("next"));
p.rect(LLRect(getRect().getWidth()-26, BOTTOM_PAD + 20, getRect().getWidth()-2, BOTTOM_PAD));
p.image_selected.name("notify_next.png");
p.image_unselected.name("notify_next.png");
p.font(sFont);
p.scale_image(true);
p.tool_tip(LLTrans::getString("next").c_str());
// *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->setVisible(TRUE);
mTextBox->setValue(notification->getMessage());
// add buttons for a script notification
if (!mIsTip)
{
for (S32 i = 0; i < mNumOptions; i++)
{
LLSD form_element = form->getElement(i);
if (form_element["type"].asString() != "button")
{
@ -222,136 +150,62 @@ LLToastNotifyPanel::LLToastNotifyPanel(LLNotificationPtr& notification) : LLToas
addButton("OK", LLTrans::getString("ok"), FALSE, TRUE);
mAddedDefaultBtn = true;
}
}
// adjust panel's height to the text size
mInfoPanel->setFollowsAll();
snapToMessageHeight(mTextBox, MAX_LENGTH);
}
LLToastNotifyPanel::~LLToastNotifyPanel() {
LLToastNotifyPanel::~LLToastNotifyPanel()
{
std::for_each(mBtnCallbackData.begin(), mBtnCallbackData.end(), DeletePointer());
}
LLRect LLToastNotifyPanel::getNotifyRect(S32 num_options, BOOL mIsScriptDialog, BOOL is_caution)
void LLToastNotifyPanel::adjustPanelForScriptNotice(const LLNotificationFormPtr form)
{
S32 notify_height = gSavedSettings.getS32("NotifyBoxHeight");
if (is_caution)
F32 buttons_num = 0;
S32 button_rows = 0;
// calculate number of buttons
for (S32 i = 0; i < mNumOptions; i++)
{
// make caution-style dialog taller to accomodate extra text,
// as well as causing the accept/decline buttons to be drawn
// in a different position, to help prevent "quick-click-through"
// of many permissions prompts
notify_height = gSavedSettings.getS32("PermissionsCautionNotifyBoxHeight");
}
const S32 NOTIFY_WIDTH = gSavedSettings.getS32("NotifyBoxWidth");
const S32 TOP = getRect().getHeight();
const S32 RIGHT =getRect().getWidth();
const S32 LEFT = RIGHT - NOTIFY_WIDTH;
if (num_options < 1)
{
num_options = 1;
}
// Add two "blank" option spaces.
if (mIsScriptDialog)
{
num_options += 2;
}
S32 additional_lines = (num_options-1) / 3;
notify_height += additional_lines * (BTN_HEIGHT + VPAD);
return LLRect(LEFT, TOP, RIGHT, TOP-notify_height);
}
// static
LLRect LLToastNotifyPanel::getNotifyTipRect(const std::string &utf8message)
{
S32 line_count = 1;
LLWString message = utf8str_to_wstring(utf8message);
S32 message_len = message.length();
const S32 NOTIFY_WIDTH = gSavedSettings.getS32("NotifyBoxWidth");
// Make room for the icon area.
const S32 text_area_width = NOTIFY_WIDTH - HPAD * 4 - 32;
const llwchar* wchars = message.c_str();
const llwchar* start = wchars;
const llwchar* end;
S32 total_drawn = 0;
BOOL done = FALSE;
do
{
line_count++;
for (end=start; *end != 0 && *end != '\n'; end++)
;
if( *end == 0 )
if (form->getElement(i)["type"].asString() == "button")
{
end = wchars + message_len;
done = TRUE;
buttons_num++;
}
}
S32 remaining = end - start;
while( remaining )
{
S32 drawn = sFont->maxDrawableChars( start, (F32)text_area_width, remaining, TRUE );
if( 0 == drawn )
{
drawn = 1; // Draw at least one character, even if it doesn't all fit. (avoids an infinite loop)
}
total_drawn += drawn;
start += drawn;
remaining -= drawn;
if( total_drawn < message_len )
{
if( (wchars[ total_drawn ] != '\n') )
{
// wrap because line was too long
line_count++;
}
}
else
{
done = TRUE;
}
}
total_drawn++; // for '\n'
end++;
start = end;
} while( !done );
const S32 MIN_NOTIFY_HEIGHT = 72;
const S32 MAX_NOTIFY_HEIGHT = 600;
S32 notify_height = llceil((F32) (line_count+1) * sFont->getLineHeight());
if(gOverlayBar)
// calculate necessary height for the button panel
// if notification form contains no buttons - reserve a place for OK button
// script notifications have extra line for an IGNORE button
if(mIsScriptDialog)
{
notify_height += gOverlayBar->getBoundingRect().mTop;
button_rows = llceil((buttons_num - 1) / 3.0f) + 1;
}
else
{
// *FIX: this is derived from the padding caused by the
// rounded rects, shouldn't be a const here.
notify_height += 10;
button_rows = llmax( 1, llceil(buttons_num / 3.0f));
}
notify_height += VPAD;
notify_height = llclamp(notify_height, MIN_NOTIFY_HEIGHT, MAX_NOTIFY_HEIGHT);
const S32 RIGHT = getRect().getWidth();
const S32 LEFT = RIGHT - NOTIFY_WIDTH;
S32 button_panel_height = button_rows * BTN_HEIGHT + (button_rows + 1) * VPAD + BOTTOM_PAD;
return LLRect(LEFT, notify_height, RIGHT, 0);
//adjust layout
LLRect button_rect = mControlPanel->getRect();
reshape(getRect().getWidth(), mInfoPanel->getRect().getHeight() + button_panel_height);
mControlPanel->reshape(button_rect.getWidth(), button_panel_height);
}
// static
void LLToastNotifyPanel::adjustPanelForTipNotice()
{
LLRect info_rect = mInfoPanel->getRect();
LLRect this_rect = getRect();
mControlPanel->setVisible(FALSE);
reshape(getRect().getWidth(), mInfoPanel->getRect().getHeight());
}
// static
void LLToastNotifyPanel::onClickButton(void* data)
@ -371,10 +225,6 @@ void LLToastNotifyPanel::onClickButton(void* data)
// virtual
LLButton* LLToastNotifyPanel::addButton(const std::string& name, const std::string& label, BOOL is_option, BOOL is_default)
{
// make caution notification buttons slightly narrower
// so that 3 of them can fit without overlapping the "next" button
S32 btn_width = mIsCaution? 84 : 90;
LLRect btn_rect;
LLButton* btn;
S32 btn_height= BTN_HEIGHT;
@ -397,9 +247,9 @@ LLButton* LLToastNotifyPanel::addButton(const std::string& name, const std::stri
}
}
btn_rect.setOriginAndSize(x + (index % 3) * (btn_width+HPAD+HPAD) + ignore_pad,
btn_rect.setOriginAndSize(x + (index % 3) * (BUTTON_WIDTH+HPAD+HPAD) + ignore_pad,
BOTTOM_PAD + (index / 3) * (BTN_HEIGHT+VPAD),
btn_width - 2*ignore_pad,
BUTTON_WIDTH - 2*ignore_pad,
btn_height);
InstanceAndS32* userdata = new InstanceAndS32;
@ -422,7 +272,7 @@ LLButton* LLToastNotifyPanel::addButton(const std::string& name, const std::stri
btn = LLUICtrlFactory::create<LLButton>(p);
addChild(btn, -1);
mControlPanel->addChild(btn, -1);
if (is_default)
{

View File

@ -38,6 +38,9 @@
#include "llnotifications.h"
#include "llbutton.h"
#include "lltoastpanel.h"
#include "lliconctrl.h"
#include "lltexteditor.h"
#include "lltextbox.h"
/**
@ -46,15 +49,15 @@
*
* Replaces class LLNotifyBox.
*/
class LLToastNotifyPanel: public LLToastPanel {
class LLToastNotifyPanel: public LLToastPanel
{
public:
LLToastNotifyPanel(LLNotificationPtr&);
virtual ~LLToastNotifyPanel();
bool isTip() {return mIsTip;}
static LLToastNotifyPanel * buildNotifyPanel(LLNotificationPtr notification);
protected:
LLButton* addButton(std::string const &name, const std::string& label, BOOL is_option, BOOL is_default);
// Used for callbacks
struct InstanceAndS32
{
@ -65,16 +68,23 @@ protected:
private:
// Returns the rect, relative to gNotifyView, where this
// notify box should be placed.
LLRect getNotifyRect(S32 num_options, BOOL layout_script_dialog, BOOL is_caution);
LLRect getNotifyTipRect(const std::string &message);
void adjustPanelForScriptNotice(const LLNotificationFormPtr form);
void adjustPanelForTipNotice();
// panel elements
LLTextBase* mTextBox;
LLIconCtrl* mIcon;
LLPanel* mInfoPanel; // a panel, that contains an information
LLPanel* mControlPanel; // a panel, that contains buttons (if present)
// internal handler for button being clicked
static void onClickButton(void* data);
bool mIsTip;
bool mAddedDefaultBtn;
bool mIsScriptDialog;
bool mIsCaution; // is this a caution notification?
bool mIsCaution;
std::string mMessage;
S32 mNumOptions;
S32 mNumButtons;

View File

@ -34,6 +34,9 @@
#include "lltoastpanel.h"
//static
const S32 LLToastPanel::MIN_PANEL_HEIGHT = 40; // VPAD(4)*2 + ICON_HEIGHT(32)
LLToastPanel::LLToastPanel(LLNotificationPtr& notification)
{
mNotification = notification;
@ -50,8 +53,13 @@ std::string LLToastPanel::getTitle()
}
//snap to the message height if it is visible
void LLToastPanel::snapToMessageHeight(LLTextBox* message, S32 maxLineCount)
void LLToastPanel::snapToMessageHeight(LLTextBase* message, S32 maxLineCount)
{
if(!message)
{
return;
}
//Add message height if it is visible
if (message->getVisible())
{
@ -61,22 +69,16 @@ void LLToastPanel::snapToMessageHeight(LLTextBox* message, S32 maxLineCount)
LLRect messageRect = message->getRect();
S32 oldTextHeight = messageRect.getHeight();
//Reshape the toast to give the message max height.
//This needed to calculate lines count according to specified text
heightDelta = maxTextHeight - oldTextHeight;
reshape( getRect().getWidth(), getRect().getHeight() + heightDelta);
//Knowing the height is set to max allowed, getTextPixelHeight returns needed text height
//Perhaps we need to pass maxLineCount as parameter to getTextPixelHeight to avoid previous reshape.
S32 requiredTextHeight = message->getTextPixelHeight();
S32 requiredTextHeight = message->getContentsRect().getHeight();
S32 newTextHeight = llmin(requiredTextHeight, maxTextHeight);
//Calculate last delta height deducting previous heightDelta
heightDelta = newTextHeight - oldTextHeight - heightDelta;
//reshape the panel with new height
reshape( getRect().getWidth(), getRect().getHeight() + heightDelta);
reshape( getRect().getWidth(), llmax(getRect().getHeight() + heightDelta, MIN_PANEL_HEIGHT));
}
}

View File

@ -58,9 +58,11 @@ public:
virtual std::string getTitle();
virtual const LLUUID& getID() { return mNotification->id();}
static const S32 MIN_PANEL_HEIGHT;
protected:
LLNotificationPtr mNotification;
void snapToMessageHeight(LLTextBox* message, S32 maxLineCount);
void snapToMessageHeight(LLTextBase* message, S32 maxLineCount);
};
#endif /* LL_TOASTPANEL_H */

View File

@ -2293,7 +2293,9 @@ void LLViewerWindow::handleScrollWheel(S32 clicks)
}
// Zoom the camera in and out behavior
gAgent.handleScrollWheel(clicks);
if(top_ctrl == 0 && mWorldViewRect.pointInRect(mCurrentMousePoint.mX, mCurrentMousePoint.mY) )
gAgent.handleScrollWheel(clicks);
return;
}
@ -4168,8 +4170,9 @@ void LLViewerWindow::drawMouselookInstructions()
instructions, 0,
getVirtualWorldViewRect().getCenterX(),
getVirtualWorldViewRect().mBottom + INSTRUCTIONS_PAD,
LLColor4( 0.0f, 0.0f, 0.0f, 0.6f ),
LLFontGL::HCENTER, LLFontGL::TOP);
LLColor4( 1.0f, 1.0f, 1.0f, 0.5f ),
LLFontGL::HCENTER, LLFontGL::TOP,
LLFontGL::NORMAL,LLFontGL::DROP_SHADOW);
}
S32 LLViewerWindow::getWindowHeight() const

View File

@ -30,23 +30,18 @@
color="1 1 1 1" enabled="true" image_name="closebox.tga"
name="close_btn"/>
</panel>
<text_editor
<chat_history
allow_html="true"
bg_readonly_color="ChatHistoryBgColor"
bg_writeable_color="ChatHistoryBgColor"
follows="left|top|right|bottom"
follows="left|top|right"
font="SansSerif"
layout="topleft"
height="320"
max_length="2147483647"
name="Chat History Editor"
height="320"
name="chat_history"
parse_highlights="true"
read_only="true"
text_color="ChatHistoryTextColor"
text_readonly_color="ChatHistoryTextColor"
bottom="0"
track_bottom="true"
width="250"
word_wrap="true" />
width="250"/>
</floater>

View File

@ -478,11 +478,12 @@
parameter="open" />
</menu_item_call>
<menu_item_separator
layout="topleft" />
layout="topleft"
name="Landmark Separator" />
<menu_item_call
label="About Landmark"
layout="topleft"
name="Teleport To Landmark">
name="About Landmark">
<menu_item_call.on_click
function="Inventory.DoToSelected"
parameter="about" />

View File

@ -29,4 +29,12 @@
function="Places.OverflowMenu.Action"
parameter="pick" />
</menu_item_call>
<menu_item_call
label="Add to Favorites Bar"
layout="topleft"
name="add_to_favbar">
<menu_item_call.on_click
function="Places.OverflowMenu.Action"
parameter="add_to_favbar" />
</menu_item_call>
</toggleable_menu>

View File

@ -0,0 +1,45 @@
<menu name="menu_folder_gear"
left="0" bottom="0" visible="false"
mouse_opaque="false" opaque="true"
color="MenuDefaultBgColor" drop_shadow="true">
<menu_item_call name="add_landmark" label="Add Landmark">
<menu_item_call.on_click function="Places.LandmarksGear.Add.Action" userdata="add_landmark" />
</menu_item_call>
<menu_item_call name="add_folder" label="Add Folder">
<menu_item_call.on_click function="Places.LandmarksGear.Add.Action" userdata="category" />
<menu_item_call.on_enable function="Places.LandmarksGear.Enable" userdata="category" />
</menu_item_call>
<menu_item_separator layout="topleft" />
<menu_item_call name="cut" label="Cut">
<menu_item_call.on_click function="Places.LandmarksGear.CopyPaste.Action" userdata="cut" />
</menu_item_call>
<menu_item_call name="copy_folder" label="Copy">
<menu_item_call.on_click function="Places.LandmarksGear.CopyPaste.Action" userdata="copy" />
</menu_item_call>
<menu_item_call name="paste" label="Paste">
<menu_item_call.on_click function="Places.LandmarksGear.CopyPaste.Action" userdata="paste" />
<menu_item_call.on_enable function="Places.LandmarksGear.Enable" userdata="paste" />
</menu_item_call>
<menu_item_call name="rename" label="Rename">
<menu_item_call.on_click function="Places.LandmarksGear.CopyPaste.Action" userdata="rename" />
</menu_item_call>
<menu_item_call name="delete" label="Delete">
<menu_item_call.on_click function="Places.LandmarksGear.CopyPaste.Action" userdata="delete" />
</menu_item_call>
<menu_item_separator layout="topleft" />
<menu_item_call name="expand" label="Expand">
<menu_item_call.on_click function="Places.LandmarksGear.Folding.Action" userdata="expand" />
</menu_item_call>
<menu_item_call name="collapse" label="Collapse">
<menu_item_call.on_click function="Places.LandmarksGear.Folding.Action" userdata="collapse" />
</menu_item_call>
<menu_item_call name="expand_all" label="Expand all folders">
<menu_item_call.on_click function="Places.LandmarksGear.Folding.Action" userdata="expand_all" />
</menu_item_call>
<menu_item_call name="collapse_all" label="Collapse all folders">
<menu_item_call.on_click function="Places.LandmarksGear.Folding.Action" userdata="collapse_all" />
</menu_item_call>
<menu_item_call name="sort_by_date" label="Sort by Date">
<menu_item_call.on_click function="Places.LandmarksGear.Folding.Action" userdata="sort_by_date" />
</menu_item_call>
</menu>

View File

@ -0,0 +1,56 @@
<menu name="menu_ladmark_gear"
left="0" bottom="0" visible="false"
mouse_opaque="false" opaque="true"
color="MenuDefaultBgColor" drop_shadow="true">
<menu_item_call name="teleport" label="Teleport">
<menu_item_call.on_click function="Places.LandmarksGear.Custom.Action" userdata="teleport" />
</menu_item_call>
<menu_item_call name="more_info" label="More Information">
<menu_item_call.on_click function="Places.LandmarksGear.Custom.Action" userdata="more_info" />
</menu_item_call>
<menu_item_call name="show_on_map" label="Show on Map">
<menu_item_call.on_click function="Places.LandmarksGear.Custom.Action" userdata="show_on_map" />
</menu_item_call>
<menu_item_separator layout="topleft" />
<menu_item_call name="add_landmark" label="Add Landmark">
<menu_item_call.on_click function="Places.LandmarksGear.Add.Action" userdata="add_landmark" />
</menu_item_call>
<menu_item_call name="add_folder" label="Add Folder">
<menu_item_call.on_click function="Places.LandmarksGear.Add.Action" userdata="category" />
<menu_item_call.on_enable function="Places.LandmarksGear.Enable" userdata="category" />
</menu_item_call>
<menu_item_separator layout="topleft" />
<menu_item_call name="cut" label="Cut">
<menu_item_call.on_click function="Places.LandmarksGear.CopyPaste.Action" userdata="cut" />
</menu_item_call>
<menu_item_call name="copy_landmark" label="Copy Landmark">
<menu_item_call.on_click function="Places.LandmarksGear.CopyPaste.Action" userdata="copy" />
</menu_item_call>
<menu_item_call name="copy_slurl" label="Copy SLURL">
<menu_item_call.on_click function="Places.LandmarksGear.CopyPaste.Action" userdata="copy_slurl" />
</menu_item_call>
<menu_item_call name="paste" label="Paste">
<menu_item_call.on_click function="Places.LandmarksGear.CopyPaste.Action" userdata="paste" />
<menu_item_call.on_enable function="Places.LandmarksGear.Enable" userdata="paste" />
</menu_item_call>
<menu_item_call name="rename" label="Rename">
<menu_item_call.on_click function="Places.LandmarksGear.CopyPaste.Action" userdata="rename" />
</menu_item_call>
<menu_item_call name="delete" label="Delete">
<menu_item_call.on_click function="Places.LandmarksGear.CopyPaste.Action" userdata="delete" />
</menu_item_call>
<menu_item_separator layout="topleft" />
<menu_item_call name="expand_all" label="Expand all folders">
<menu_item_call.on_click function="Places.LandmarksGear.Folding.Action" userdata="expand_all" />
</menu_item_call>
<menu_item_call name="collapse_all" label="Collapse all folders">
<menu_item_call.on_click function="Places.LandmarksGear.Folding.Action" userdata="collapse_all" />
</menu_item_call>
<menu_item_call name="sort_by_date" label="Sort by Date">
<menu_item_call.on_click function="Places.LandmarksGear.Folding.Action" userdata="sort_by_date" />
</menu_item_call>
<menu_item_separator layout="topleft" />
<menu_item_call name="create_pick" label="Create Pick">
<menu_item_call.on_click function="Places.LandmarksGear.Custom.Action" userdata="create_pick" />
</menu_item_call>
</menu>

View File

@ -38,12 +38,13 @@
width="20" />
<text
follows="left|right"
font="SansSerifSmallBold"
font="SansSerifSmall"
font.style="BOLD"
height="20"
layout="topleft"
left_pad="5"
name="avatar_name"
text_color="white"
text_color="grey"
top="4"
use_ellipses="true"
value="Unknown"

View File

@ -0,0 +1,53 @@
<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
<panel
follows="left|top|right"
height="57"
label="im_header_container"
layout="topleft"
left="8"
name="im_header_container">
<panel
background_visible="true"
bevel_style="in"
bg_alpha_color="black"
follows="left|top|right"
height="30"
label="im_header"
layout="topleft"
name="im_header"
top_pad="17">
<avatar_icon
follows="left"
height="20"
image_name="icon_avatar_online.tga"
layout="topleft"
left="5"
mouse_opaque="true"
name="avatar_icon"
top="5"
width="20" />
<text
follows="left|right"
font="SansSerifBigBold"
height="20"
layout="topleft"
left_pad="10"
right="-50"
name="user_name"
text_color="white"
top="5"
value="Darth Vader"
use_ellipses="true" />
<text
follows="right"
font="SansSerifBig"
height="20"
layout="topleft"
name="time_box"
right="0"
text_color="white"
top="5"
value="23:30"
width="50" />
</panel>
</panel>

View File

@ -0,0 +1,16 @@
<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
<panel
follows="left|right|top"
height="10"
layout="topleft"
left="8"
name="chat_separator_container">
<panel
background_visible="true"
bg_alpha_color="black"
follows="left|right|top"
height="1"
layout="topleft"
name="chat_separator_panel"
top_pad="5" />
</panel>

View File

@ -1,35 +1,143 @@
<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
<panel
name="Landmarks"
bottom="0"
height="326"
top="0"
height="400"
layout="topleft"
left="0"
width="380"
border="true"
background_visible="true"
bg_alpha_color="DkGray2"
follows="left|top|right|bottom">
<inventory_panel
allow_multi_select="true"
border="true"
bottom="0"
follows="left|top|right|bottom"
height="326"
left="0"
mouse_opaque="true"
name="landmarks_list"
start_folder="landmark"
width="380"/>
<button
bottom="0"
halign="center"
height="16"
label=">"
enabled="false"
mouse_opaque="false"
name="selector"
width="20"
left="0"
follows="right|bottom"
tool_tip="View landmark properties"/>
<accordion
follows="left|top|right|bottom"
height="368"
layout="topleft"
left="0"
name="landmarks_accordion"
top="2"
width="380">
<accordion_tab
layout="topleft"
name="tab_favorites"
title="Favorites bar">
<inventory_subtree_panel
allow_multi_select="true"
border="true"
bottom="0"
follows="left|top|right|bottom"
height="126"
left="0"
mouse_opaque="true"
name="favorites_list"
width="380"/>
</accordion_tab>
<accordion_tab
layout="topleft"
name="tab_landmarks"
title="Landmarks">
<inventory_subtree_panel
allow_multi_select="true"
border="true"
bottom="0"
follows="left|top|right|bottom"
height="126"
left="0"
mouse_opaque="true"
name="landmarks_list"
start_folder="landmark"
width="380"/>
</accordion_tab>
<accordion_tab
layout="topleft"
name="tab_inventory"
title="My Inventory">
<inventory_subtree_panel
allow_multi_select="true"
border="true"
bottom="0"
follows="left|top|right|bottom"
height="126"
left="0"
mouse_opaque="true"
name="my_inventory_list"
width="380"/>
</accordion_tab>
<accordion_tab
layout="topleft"
name="tab_library"
title="Library">
<inventory_subtree_panel
allow_multi_select="true"
border="true"
bottom="0"
follows="left|top|right|bottom"
height="120"
left="0"
mouse_opaque="true"
name="library_list"
width="380"/>
</accordion_tab>
</accordion>
<panel
background_visible="true"
bevel_style="none"
bottom="0"
follows="left|right|bottom"
height="30"
layout="bottomleft"
left="0"
name="bottom_panel"
width="380">
<button
follows="bottom|left"
tool_tip="Show additional options"
height="18"
image_disabled="OptionsMenu_Disabled"
image_selected="OptionsMenu_Press"
image_unselected="OptionsMenu_Off"
layout="topleft"
left="10"
name="options_gear_btn"
picture_style="true"
top="6"
width="18" />
<button
follows="bottom|left"
height="18"
image_selected="AddItem_Press"
image_unselected="AddItem_Off"
image_disabled="AddItem_Disabled"
layout="topleft"
left_pad="5"
name="add_landmark_btn"
picture_style="true"
tool_tip="Add New Landmark"
width="18" />
<button
follows="bottom|left"
height="18"
image_selected="AddItem_Press"
image_unselected="AddItem_Off"
image_disabled="AddItem_Disabled"
layout="topleft"
left_pad="5"
name="add_folder_btn"
picture_style="true"
tool_tip="Add New Folder"
width="18" />
<button
follows="bottom|right"
height="18"
image_selected="TrashItem_Press"
image_unselected="TrashItem_Off"
layout="topleft"
right="-5"
name="trash_btn"
picture_style="true"
tool_tip="Remove selected Landmark"
top="6"
width="18" />
</panel>
</panel>

View File

@ -0,0 +1,92 @@
<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
<panel
background_opaque="true"
background_visible="false"
bg_alpha_color="0.3 0.3 0.3 0"
height="140"
label="notification_panel"
layout="topleft"
left="0"
name="notification_panel"
top="0"
width="350">
<panel
background_visible="true"
follows="left|right|top"
height="100"
label="info_panel"
layout="topleft"
left="0"
name="info_panel"
top="0"
width="350">
<text
border_visible="false"
follows="left|right|top|bottom"
font="SansSerif"
height="90"
layout="topleft"
left="45"
name="text_box"
read_only="true"
text_color="white"
top="5"
visible="false"
width="300"
wrap="true"/>
<text
border_visible="false"
follows="left|right|top|bottom"
font="SansSerifBold"
height="90"
layout="topleft"
left="45"
name="caution_text_box"
text_color="1 0.82 0.46 1"
top="5"
visible="false"
width="300"
wrap="true"/>
<text_editor
bg_readonly_color="0.0 0.0 0.0 0"
border_visible="false"
embedded_items="false"
enabled="false"
follows="left|right|top|bottom"
font="SansSerif"
height="90"
layout="topleft"
left="45"
mouse_opaque="false"
name="text_editor_box"
read_only="true"
tab_stop="false"
text_color="white"
text_readonly_color="white"
top="5"
visible="false"
width="300"
wrap="true"/>
</panel>
<panel
background_visible="true"
follows="left|right|bottom"
height="40"
label="control_panel"
layout="topleft"
left="0"
name="control_panel"
top_pad="0"
width="350">
</panel>
<icon
follows="left|top"
height="32"
image_name="notify_tip_icon.tga"
layout="topleft"
left="8"
mouse_opaque="false"
name="info_icon"
top="20"
width="32" />
</panel>

View File

@ -1,15 +1,6 @@
<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
<panel name="Teleport History" bottom="0" height="326" left="0" width="380"
border="true" follows="left|top|right|bottom">
<string
name="cant_create_lm_here"
value="Please teleport to selected location before creating Landmark. " />
<string
name="create_landmark"
value="Create Landmark" />
<string
name="open_landmark"
value="Open Landmark panel" />
<accordion
follows="left|top|right|bottom"
height="300"
@ -188,19 +179,5 @@
picture_style="true"
top="5"
width="18" />
<button
follows="bottom|left"
font="SansSerifBigBold"
height="18"
image_selected="Favorite_Star_Active"
image_disabled="Favorite_Star_Off"
image_unselected="Favorite_Star_Press"
layout="topleft"
left_pad="5"
name="star_btn"
picture_style="true"
tool_tip=""
top_delta="0"
width="18" />
</panel>
</panel>

View File

@ -0,0 +1,14 @@
<?xml version="1.0" encoding="UTF-8"?>
<chat_history
message_header="panel_chat_header.xml"
message_separator="panel_chat_separator.xml"
left_text_pad="10"
right_text_pad="15"
left_widget_pad="5"
rigth_widget_pad="10"
max_length="2147483647"
enabled="false"
track_bottom="true"
name="chat_history"
type="string"
word_wrap="true" />