llfloaterfriends.cpp

Go to the documentation of this file.
00001 
00035 #include "llviewerprecompiledheaders.h"
00036 
00037 #include "llfloaterfriends.h"
00038 
00039 #include <sstream>
00040 
00041 #include "lldir.h"
00042 
00043 #include "llagent.h"
00044 #include "llfloateravatarpicker.h"
00045 #include "llviewerwindow.h"
00046 #include "llbutton.h"
00047 #include "llcallingcard.h"
00048 #include "llfloateravatarinfo.h"
00049 #include "llinventorymodel.h"
00050 #include "llnamelistctrl.h"
00051 #include "llnotify.h"
00052 #include "llresmgr.h"
00053 #include "llimview.h"
00054 #include "lluictrlfactory.h"
00055 #include "llmenucommands.h"
00056 #include "llviewercontrol.h"
00057 #include "llviewermessage.h"
00058 #include "lltimer.h"
00059 #include "lltextbox.h"
00060 
00061 //Maximum number of people you can select to do an operation on at once.
00062 #define MAX_FRIEND_SELECT 20
00063 #define DEFAULT_PERIOD 5.0
00064 #define RIGHTS_CHANGE_TIMEOUT 5.0
00065 #define OBSERVER_TIMEOUT 0.5
00066 
00067 // simple class to observe the calling cards.
00068 class LLLocalFriendsObserver : public LLFriendObserver, public LLEventTimer
00069 {
00070 public: 
00071         LLLocalFriendsObserver(LLPanelFriends* floater) : mFloater(floater), LLEventTimer(OBSERVER_TIMEOUT)
00072         {
00073                 mEventTimer.stop();
00074         }
00075         virtual ~LLLocalFriendsObserver()
00076         {
00077                 mFloater = NULL;
00078         }
00079         virtual void changed(U32 mask)
00080         {
00081                 // events can arrive quickly in bulk - we need not process EVERY one of them -
00082                 // so we wait a short while to let others pile-in, and process them in aggregate.
00083                 mEventTimer.start();
00084 
00085                 // save-up all the mask-bits which have come-in
00086                 mMask |= mask;
00087         }
00088         virtual BOOL tick()
00089         {
00090                 mFloater->updateFriends(mMask);
00091 
00092                 mEventTimer.stop();
00093                 mMask = 0;
00094 
00095                 return FALSE;
00096         }
00097         
00098 protected:
00099         LLPanelFriends* mFloater;
00100         U32 mMask;
00101 };
00102 
00103 LLPanelFriends::LLPanelFriends() :
00104         LLPanel(),
00105         LLEventTimer(DEFAULT_PERIOD),
00106         mObserver(NULL),
00107         mShowMaxSelectWarning(TRUE),
00108         mAllowRightsChange(TRUE),
00109         mNumRightsChanged(0)
00110 {
00111         mEventTimer.stop();
00112         mObserver = new LLLocalFriendsObserver(this);
00113         LLAvatarTracker::instance().addObserver(mObserver);
00114 }
00115 
00116 LLPanelFriends::~LLPanelFriends()
00117 {
00118         LLAvatarTracker::instance().removeObserver(mObserver);
00119         delete mObserver;
00120 }
00121 
00122 BOOL LLPanelFriends::tick()
00123 {
00124         mEventTimer.stop();
00125         mPeriod = DEFAULT_PERIOD;
00126         mAllowRightsChange = TRUE;
00127         updateFriends(LLFriendObserver::ADD);
00128         return FALSE;
00129 }
00130 
00131 void LLPanelFriends::updateFriends(U32 changed_mask)
00132 {
00133         LLUUID selected_id;
00134         LLCtrlListInterface *friends_list = childGetListInterface("friend_list");
00135         if (!friends_list) return;
00136         LLCtrlScrollInterface *friends_scroll = childGetScrollInterface("friend_list");
00137         if (!friends_scroll) return;
00138         
00139         // We kill the selection warning, otherwise we'll spam with warning popups
00140         // if the maximum amount of friends are selected
00141         mShowMaxSelectWarning = false;
00142 
00143         LLDynamicArray<LLUUID> selected_friends = getSelectedIDs();
00144         if(changed_mask & (LLFriendObserver::ADD | LLFriendObserver::REMOVE | LLFriendObserver::ONLINE))
00145         {
00146                 refreshNames();
00147         }
00148         else if(changed_mask & LLFriendObserver::POWERS)
00149         {
00150                 --mNumRightsChanged;
00151                 if(mNumRightsChanged > 0)
00152                 {
00153                         mPeriod = RIGHTS_CHANGE_TIMEOUT;        
00154                         mEventTimer.start();
00155                         mAllowRightsChange = FALSE;
00156                 }
00157                 else
00158                 {
00159                         tick();
00160                 }
00161         }
00162         if(selected_friends.size() > 0)
00163         {
00164                 // only non-null if friends was already found. This may fail,
00165                 // but we don't really care here, because refreshUI() will
00166                 // clean up the interface.
00167                 friends_list->setCurrentByID(selected_id);
00168                 for(LLDynamicArray<LLUUID>::iterator itr = selected_friends.begin(); itr != selected_friends.end(); ++itr)
00169                 {
00170                         friends_list->setSelectedByValue(*itr, true);
00171                 }
00172         }
00173 
00174         refreshUI();
00175         mShowMaxSelectWarning = true;
00176 }
00177 
00178 // virtual
00179 BOOL LLPanelFriends::postBuild()
00180 {
00181         mFriendsList = getChild<LLScrollListCtrl>("friend_list");
00182         mFriendsList->setMaxSelectable(MAX_FRIEND_SELECT);
00183         mFriendsList->setMaximumSelectCallback(onMaximumSelect);
00184         mFriendsList->setCommitOnSelectionChange(TRUE);
00185         childSetCommitCallback("friend_list", onSelectName, this);
00186         childSetDoubleClickCallback("friend_list", onClickIM);
00187 
00188         refreshNames();
00189 
00190         childSetAction("im_btn", onClickIM, this);
00191         childSetAction("profile_btn", onClickProfile, this);
00192         childSetAction("offer_teleport_btn", onClickOfferTeleport, this);
00193         childSetAction("pay_btn", onClickPay, this);
00194         childSetAction("add_btn", onClickAddFriend, this);
00195         childSetAction("remove_btn", onClickRemove, this);
00196 
00197         setDefaultBtn("im_btn");
00198 
00199         updateFriends(LLFriendObserver::ADD);
00200         refreshUI();
00201 
00202         // primary sort = online status, secondary sort = name
00203         mFriendsList->sortByColumn("friend_name", TRUE);
00204         mFriendsList->sortByColumn("icon_online_status", FALSE);
00205 
00206         return TRUE;
00207 }
00208 
00209 
00210 BOOL LLPanelFriends::addFriend(const LLUUID& agent_id)
00211 {
00212         LLAvatarTracker& at = LLAvatarTracker::instance();
00213         const LLRelationship* relationInfo = at.getBuddyInfo(agent_id);
00214         if(!relationInfo) return FALSE;
00215         BOOL online = relationInfo->isOnline();
00216 
00217         std::string fullname;
00218         BOOL have_name = gCacheName->getFullName(agent_id, fullname);
00219         
00220         LLSD element;
00221         element["id"] = agent_id;
00222         LLSD& friend_column = element["columns"][LIST_FRIEND_NAME];
00223         friend_column["column"] = "friend_name";
00224         friend_column["value"] = fullname;
00225         friend_column["font"] = "SANSSERIF";
00226         friend_column["font-style"] = "NORMAL"; 
00227 
00228         LLSD& online_status_column = element["columns"][LIST_ONLINE_STATUS];
00229         online_status_column["column"] = "icon_online_status";
00230         online_status_column["type"] = "icon";
00231 
00232         if (online)
00233         {
00234                 friend_column["font-style"] = "BOLD";   
00235                 online_status_column["value"] = "icon_avatar_online.tga";
00236         }
00237 
00238         LLSD& online_column = element["columns"][LIST_VISIBLE_ONLINE];
00239         online_column["column"] = "icon_visible_online";
00240         online_column["type"] = "checkbox";
00241         online_column["value"] = relationInfo->isRightGrantedTo(LLRelationship::GRANT_ONLINE_STATUS);
00242 
00243         LLSD& visible_map_column = element["columns"][LIST_VISIBLE_MAP];
00244         visible_map_column["column"] = "icon_visible_map";
00245         visible_map_column["type"] = "checkbox";
00246         visible_map_column["value"] = relationInfo->isRightGrantedTo(LLRelationship::GRANT_MAP_LOCATION);
00247 
00248         LLSD& edit_my_object_column = element["columns"][LIST_EDIT_MINE];
00249         edit_my_object_column["column"] = "icon_edit_mine";
00250         edit_my_object_column["type"] = "checkbox";
00251         edit_my_object_column["value"] = relationInfo->isRightGrantedTo(LLRelationship::GRANT_MODIFY_OBJECTS);
00252 
00253         LLSD& edit_their_object_column = element["columns"][LIST_EDIT_THEIRS];
00254         edit_their_object_column["column"] = "icon_edit_theirs";
00255         edit_their_object_column["type"] = "checkbox";
00256         edit_their_object_column["enabled"] = "";
00257         edit_their_object_column["value"] = relationInfo->isRightGrantedFrom(LLRelationship::GRANT_MODIFY_OBJECTS);
00258 
00259         LLSD& update_gen_column = element["columns"][LIST_FRIEND_UPDATE_GEN];
00260         update_gen_column["column"] = "friend_last_update_generation";
00261         update_gen_column["value"] = have_name ? relationInfo->getChangeSerialNum() : -1;
00262 
00263         mFriendsList->addElement(element, ADD_BOTTOM);
00264         return have_name;
00265 }
00266 
00267 // propagate actual relationship to UI
00268 BOOL LLPanelFriends::updateFriendItem(const LLUUID& agent_id, const LLRelationship* info)
00269 {
00270         if (!info) return FALSE;
00271         LLScrollListItem* itemp = mFriendsList->getItem(agent_id);
00272         if (!itemp) return FALSE;
00273 
00274         std::string fullname;
00275         BOOL have_name = gCacheName->getFullName(agent_id, fullname);
00276 
00277         itemp->getColumn(LIST_ONLINE_STATUS)->setValue(info->isOnline() ? "icon_avatar_online.tga" : LLString::null);
00278         itemp->getColumn(LIST_FRIEND_NAME)->setValue(fullname);
00279         // render name of online friends in bold text
00280         ((LLScrollListText*)itemp->getColumn(LIST_FRIEND_NAME))->setFontStyle(info->isOnline() ? LLFontGL::BOLD : LLFontGL::NORMAL);    
00281         itemp->getColumn(LIST_VISIBLE_ONLINE)->setValue(info->isRightGrantedTo(LLRelationship::GRANT_ONLINE_STATUS));
00282         itemp->getColumn(LIST_VISIBLE_MAP)->setValue(info->isRightGrantedTo(LLRelationship::GRANT_MAP_LOCATION));
00283         itemp->getColumn(LIST_EDIT_MINE)->setValue(info->isRightGrantedTo(LLRelationship::GRANT_MODIFY_OBJECTS));
00284         S32 change_generation = have_name ? info->getChangeSerialNum() : -1;
00285         itemp->getColumn(LIST_FRIEND_UPDATE_GEN)->setValue(change_generation);
00286 
00287         // enable this item, in case it was disabled after user input
00288         itemp->setEnabled(TRUE);
00289 
00290         // changed item in place, need to request sort
00291         mFriendsList->sortItems();
00292 
00293         return have_name;
00294 }
00295 
00296 void LLPanelFriends::refreshRightsChangeList()
00297 {
00298         LLDynamicArray<LLUUID> friends = getSelectedIDs();
00299         S32 num_selected = friends.size();
00300 
00301         bool can_offer_teleport = num_selected >= 1;
00302         bool selected_friends_online = true;
00303 
00304         LLTextBox* processing_label = getChild<LLTextBox>("process_rights_label");
00305 
00306         if(!mAllowRightsChange)
00307         {
00308                 if(processing_label)
00309                 {
00310                         processing_label->setVisible(true);
00311                         // ignore selection for now
00312                         friends.clear();
00313                         num_selected = 0;
00314                 }
00315         }
00316         else if(processing_label)
00317         {
00318                 processing_label->setVisible(false);
00319         }
00320 
00321         const LLRelationship* friend_status = NULL;
00322         for(LLDynamicArray<LLUUID>::iterator itr = friends.begin(); itr != friends.end(); ++itr)
00323         {
00324                 friend_status = LLAvatarTracker::instance().getBuddyInfo(*itr);
00325                 if (friend_status)
00326                 {
00327                         if(!friend_status->isOnline())
00328                         {
00329                                 can_offer_teleport = false;
00330                                 selected_friends_online = false;
00331                         }
00332                 }
00333                 else // missing buddy info, don't allow any operations
00334                 {
00335                         can_offer_teleport = false;
00336                 }
00337         }
00338         
00339         if (num_selected == 0)  // nothing selected
00340         {
00341                 childSetEnabled("im_btn", FALSE);
00342                 childSetEnabled("offer_teleport_btn", FALSE);
00343         }
00344         else // we have at least one friend selected...
00345         {
00346                 // only allow IMs to groups when everyone in the group is online
00347                 // to be consistent with context menus in inventory and because otherwise
00348                 // offline friends would be silently dropped from the session
00349                 childSetEnabled("im_btn", selected_friends_online || num_selected == 1);
00350                 childSetEnabled("offer_teleport_btn", can_offer_teleport);
00351         }
00352 }
00353 
00354 struct SortFriendsByID
00355 {
00356         bool operator() (const LLScrollListItem* const a, const LLScrollListItem* const b) const
00357         {
00358                 return a->getValue().asUUID() < b->getValue().asUUID();
00359         }
00360 };
00361 
00362 void LLPanelFriends::refreshNames()
00363 {
00364         LLDynamicArray<LLUUID> selected_ids = getSelectedIDs(); 
00365         S32 pos = mFriendsList->getScrollPos(); 
00366         
00367         // get all buddies we know about
00368         LLAvatarTracker::buddy_map_t all_buddies;
00369         LLAvatarTracker::instance().copyBuddyList(all_buddies);
00370         
00371         // get all friends in list and sort by UUID
00372         std::vector<LLScrollListItem*> items = mFriendsList->getAllData();
00373         std::sort(items.begin(), items.end(), SortFriendsByID());
00374 
00375         std::vector<LLScrollListItem*>::iterator item_it = items.begin();
00376         std::vector<LLScrollListItem*>::iterator item_end = items.end();
00377 
00378         BOOL have_names = TRUE;
00379         LLAvatarTracker::buddy_map_t::iterator buddy_it;
00380         for (buddy_it = all_buddies.begin() ; buddy_it != all_buddies.end(); ++buddy_it)
00381         {
00382                 // erase any items that reflect residents who are no longer buddies
00383                 while(item_it != item_end && buddy_it->first > (*item_it)->getValue().asUUID())
00384                 {
00385                         mFriendsList->deleteItems((*item_it)->getValue());
00386                         ++item_it;
00387                 }
00388 
00389                 // update existing friends with new info
00390                 if (item_it != item_end && buddy_it->first == (*item_it)->getValue().asUUID())
00391                 {
00392                         const LLRelationship* info = buddy_it->second;
00393                         if (!info) 
00394                         {       
00395                                 ++item_it;
00396                                 continue;
00397                         }
00398                         
00399                         S32 last_change_generation = (*item_it)->getColumn(LIST_FRIEND_UPDATE_GEN)->getValue().asInteger();
00400                         if (last_change_generation < info->getChangeSerialNum())
00401                         {
00402                                 // update existing item in UI
00403                                 have_names &= updateFriendItem(buddy_it->first, info);
00404                         }
00405                         ++item_it;
00406                 }
00407                 // add new friend to list
00408                 else 
00409                 {
00410                         have_names &= addFriend(buddy_it->first);
00411                 }
00412         }
00413         if (!have_names)
00414         {
00415                 mEventTimer.start();
00416         }
00417         // changed item in place, need to request sort and update columns
00418         mFriendsList->sortItems();
00419 
00420         // re-select items
00421         mFriendsList->selectMultiple(selected_ids);
00422         mFriendsList->setScrollPos(pos);
00423 }
00424 
00425 
00426 void LLPanelFriends::refreshUI()
00427 {       
00428         BOOL single_selected = FALSE;
00429         BOOL multiple_selected = FALSE;
00430         int num_selected = mFriendsList->getAllSelected().size();
00431         if(num_selected > 0)
00432         {
00433                 single_selected = TRUE;
00434                 if(num_selected > 1)
00435                 {
00436                         childSetText("friend_name_label", getString("Multiple"));
00437                         multiple_selected = TRUE;               
00438                 }
00439                 else
00440                 {                       
00441                         childSetText("friend_name_label", mFriendsList->getFirstSelected()->getColumn(LIST_FRIEND_NAME)->getValue().asString() + "...");
00442                 }
00443         }
00444         else
00445         {
00446                 childSetText("friend_name_label", LLString::null);
00447         }
00448 
00449 
00450         //Options that can only be performed with one friend selected
00451         childSetEnabled("profile_btn", single_selected && !multiple_selected);
00452         childSetEnabled("pay_btn", single_selected && !multiple_selected);
00453 
00454         //Options that can be performed with up to MAX_FRIEND_SELECT friends selected
00455         //(single_selected will always be true in this situations)
00456         childSetEnabled("remove_btn", single_selected);
00457         childSetEnabled("im_btn", single_selected);
00458         childSetEnabled("friend_rights", single_selected);
00459 
00460         refreshRightsChangeList();
00461 }
00462 
00463 LLDynamicArray<LLUUID> LLPanelFriends::getSelectedIDs()
00464 {
00465         LLUUID selected_id;
00466         LLDynamicArray<LLUUID> friend_ids;
00467         std::vector<LLScrollListItem*> selected = mFriendsList->getAllSelected();
00468         for(std::vector<LLScrollListItem*>::iterator itr = selected.begin(); itr != selected.end(); ++itr)
00469         {
00470                 friend_ids.push_back((*itr)->getUUID());
00471         }
00472         return friend_ids;
00473 }
00474 
00475 // static
00476 void LLPanelFriends::onSelectName(LLUICtrl* ctrl, void* user_data)
00477 {
00478         LLPanelFriends* panelp = (LLPanelFriends*)user_data;
00479 
00480         if(panelp)
00481         {
00482                 panelp->refreshUI();
00483                 // check to see if rights have changed
00484                 panelp->applyRightsToFriends();
00485         }
00486 }
00487 
00488 //static
00489 void LLPanelFriends::onMaximumSelect(void* user_data)
00490 {
00491         LLString::format_map_t args;
00492         args["[MAX_SELECT]"] = llformat("%d", MAX_FRIEND_SELECT);
00493         LLNotifyBox::showXml("MaxListSelectMessage", args);
00494 };
00495 
00496 // static
00497 void LLPanelFriends::onClickProfile(void* user_data)
00498 {
00499         LLPanelFriends* panelp = (LLPanelFriends*)user_data;
00500 
00501         //llinfos << "LLPanelFriends::onClickProfile()" << llendl;
00502         LLDynamicArray<LLUUID> ids = panelp->getSelectedIDs();
00503         if(ids.size() > 0)
00504         {
00505                 LLUUID agent_id = ids[0];
00506                 BOOL online;
00507                 online = LLAvatarTracker::instance().isBuddyOnline(agent_id);
00508                 LLFloaterAvatarInfo::showFromFriend(agent_id, online);
00509         }
00510 }
00511 
00512 // static
00513 void LLPanelFriends::onClickIM(void* user_data)
00514 {
00515         LLPanelFriends* panelp = (LLPanelFriends*)user_data;
00516 
00517         //llinfos << "LLPanelFriends::onClickIM()" << llendl;
00518         LLDynamicArray<LLUUID> ids = panelp->getSelectedIDs();
00519         if(ids.size() > 0)
00520         {
00521                 if(ids.size() == 1)
00522                 {
00523                         LLUUID agent_id = ids[0];
00524                         const LLRelationship* info = LLAvatarTracker::instance().getBuddyInfo(agent_id);
00525                         std::string fullname;
00526                         if(info && gCacheName->getFullName(agent_id, fullname))
00527                         {
00528                                 gIMMgr->setFloaterOpen(TRUE);
00529                                 gIMMgr->addSession(fullname, IM_NOTHING_SPECIAL, agent_id);
00530                         }               
00531                 }
00532                 else
00533                 {
00534                         gIMMgr->setFloaterOpen(TRUE);
00535                         gIMMgr->addSession("Friends Conference", IM_SESSION_CONFERENCE_START, ids[0], ids);
00536                 }
00537                 make_ui_sound("UISndStartIM");
00538         }
00539 }
00540 
00541 // static
00542 void LLPanelFriends::requestFriendship(const LLUUID& target_id, const LLString& target_name)
00543 {
00544         // HACK: folder id stored as "message"
00545         LLUUID calling_card_folder_id = gInventory.findCategoryUUIDForType(LLAssetType::AT_CALLINGCARD);
00546         std::string message = calling_card_folder_id.asString();
00547         send_improved_im(target_id,
00548                                          target_name.c_str(),
00549                                          message.c_str(),
00550                                          IM_ONLINE,
00551                                          IM_FRIENDSHIP_OFFERED);
00552 }
00553 
00554 struct LLAddFriendData
00555 {
00556         LLUUID mID;
00557         std::string mName;
00558 };
00559 
00560 // static
00561 void LLPanelFriends::callbackAddFriend(S32 option, void* data)
00562 {
00563         LLAddFriendData* add = (LLAddFriendData*)data;
00564         if (option == 0)
00565         {
00566                 requestFriendship(add->mID, add->mName);
00567         }
00568         delete add;
00569 }
00570 
00571 // static
00572 void LLPanelFriends::onPickAvatar(const std::vector<std::string>& names,
00573                                                                         const std::vector<LLUUID>& ids,
00574                                                                         void* )
00575 {
00576         if (names.empty()) return;
00577         if (ids.empty()) return;
00578         requestFriendshipDialog(ids[0], names[0]);
00579 }
00580 
00581 // static
00582 void LLPanelFriends::requestFriendshipDialog(const LLUUID& id,
00583                                                                                            const std::string& name)
00584 {
00585         if(id == gAgentID)
00586         {
00587                 LLNotifyBox::showXml("AddSelfFriend");
00588                 return;
00589         }
00590 
00591         LLAddFriendData* data = new LLAddFriendData();
00592         data->mID = id;
00593         data->mName = name;
00594         
00595         // TODO: accept a line of text with this dialog
00596         LLString::format_map_t args;
00597         args["[NAME]"] = name;
00598         gViewerWindow->alertXml("AddFriend", args, callbackAddFriend, data);
00599 }
00600 
00601 // static
00602 void LLPanelFriends::onClickAddFriend(void* user_data)
00603 {
00604         LLPanelFriends* panelp = (LLPanelFriends*)user_data;
00605         LLFloater* root_floater = gFloaterView->getParentFloater(panelp);
00606         LLFloaterAvatarPicker* picker = LLFloaterAvatarPicker::show(onPickAvatar, user_data, FALSE, TRUE);
00607         if (root_floater)
00608         {
00609                 root_floater->addDependentFloater(picker);
00610         }
00611 }
00612 
00613 // static
00614 void LLPanelFriends::onClickRemove(void* user_data)
00615 {
00616         LLPanelFriends* panelp = (LLPanelFriends*)user_data;
00617 
00618         //llinfos << "LLPanelFriends::onClickRemove()" << llendl;
00619         LLDynamicArray<LLUUID> ids = panelp->getSelectedIDs();
00620         LLStringBase<char>::format_map_t args;
00621         if(ids.size() > 0)
00622         {
00623                 LLString msgType = "RemoveFromFriends";
00624                 if(ids.size() == 1)
00625                 {
00626                         LLUUID agent_id = ids[0];
00627                         std::string first, last;
00628                         if(gCacheName->getName(agent_id, first, last))
00629                         {
00630                                 args["[FIRST_NAME]"] = first;
00631                                 args["[LAST_NAME]"] = last;     
00632                         }
00633                 }
00634                 else
00635                 {
00636                         msgType = "RemoveMultipleFromFriends";
00637                 }
00638                 gViewerWindow->alertXml(msgType,
00639                         args,
00640                         &handleRemove,
00641                         (void*)new LLDynamicArray<LLUUID>(ids));
00642         }
00643 }
00644 
00645 // static
00646 void LLPanelFriends::onClickOfferTeleport(void* user_data)
00647 {
00648         LLPanelFriends* panelp = (LLPanelFriends*)user_data;
00649 
00650         LLDynamicArray<LLUUID> ids = panelp->getSelectedIDs();
00651         if(ids.size() > 0)
00652         {       
00653                 handle_lure(ids);
00654         }
00655 }
00656 
00657 // static
00658 void LLPanelFriends::onClickPay(void* user_data)
00659 {
00660         LLPanelFriends* panelp = (LLPanelFriends*)user_data;
00661 
00662         LLDynamicArray<LLUUID> ids = panelp->getSelectedIDs();
00663         if(ids.size() == 1)
00664         {       
00665                 handle_pay_by_id(ids[0]);
00666         }
00667 }
00668 
00669 void LLPanelFriends::confirmModifyRights(rights_map_t& ids, EGrantRevoke command)
00670 {
00671         if (ids.empty()) return;
00672         
00673         LLStringBase<char>::format_map_t args;
00674         if(ids.size() > 0)
00675         {
00676                 // copy map of ids onto heap
00677                 rights_map_t* rights = new rights_map_t(ids); 
00678                 // package with panel pointer
00679                 std::pair<LLPanelFriends*, rights_map_t*>* user_data = new std::pair<LLPanelFriends*, rights_map_t*>(this, rights);
00680 
00681                 // for single friend, show their name
00682                 if(ids.size() == 1)
00683                 {
00684                         LLUUID agent_id = ids.begin()->first;
00685                         std::string first, last;
00686                         if(gCacheName->getName(agent_id, first, last))
00687                         {
00688                                 args["[FIRST_NAME]"] = first;
00689                                 args["[LAST_NAME]"] = last;     
00690                         }
00691                         if (command == GRANT)
00692                         {
00693                                 gViewerWindow->alertXml("GrantModifyRights", args, modifyRightsConfirmation, user_data);
00694                         }
00695                         else
00696                         {
00697                                 gViewerWindow->alertXml("RevokeModifyRights", args, modifyRightsConfirmation, user_data);
00698                         }
00699                 }
00700                 else
00701                 {
00702                         if (command == GRANT)
00703                         {
00704                                 gViewerWindow->alertXml("GrantModifyRightsMultiple", args, modifyRightsConfirmation, user_data);
00705                         }
00706                         else
00707                         {
00708                                 gViewerWindow->alertXml("RevokeModifyRightsMultiple", args, modifyRightsConfirmation, user_data);
00709                         }
00710                 }
00711         }
00712 }
00713 
00714 // static
00715 void LLPanelFriends::modifyRightsConfirmation(S32 option, void* user_data)
00716 {
00717         std::pair<LLPanelFriends*, rights_map_t*>* data = (std::pair<LLPanelFriends*, rights_map_t*>*)user_data;
00718         LLPanelFriends* panelp = data->first;
00719 
00720         if(panelp)
00721         {
00722                 if(0 == option)
00723                 {
00724                         panelp->sendRightsGrant(*(data->second));
00725                 }
00726                 else
00727                 {
00728                         // need to resync view with model, since user cancelled operation
00729                         rights_map_t* rights = data->second;
00730                         rights_map_t::iterator rights_it;
00731                         for (rights_it = rights->begin(); rights_it != rights->end(); ++rights_it)
00732                         {
00733                                 const LLRelationship* info = LLAvatarTracker::instance().getBuddyInfo(rights_it->first);
00734                                 panelp->updateFriendItem(rights_it->first, info);
00735                         }
00736                 }
00737                 panelp->refreshUI();
00738         }
00739 
00740         delete data->second;
00741         delete data;
00742 }
00743 
00744 void LLPanelFriends::applyRightsToFriends()
00745 {
00746         BOOL rights_changed = FALSE;
00747 
00748         // store modify rights separately for confirmation
00749         rights_map_t rights_updates;
00750 
00751         BOOL need_confirmation = FALSE;
00752         EGrantRevoke confirmation_type = GRANT;
00753 
00754         // this assumes that changes only happened to selected items
00755         std::vector<LLScrollListItem*> selected = mFriendsList->getAllSelected();
00756         for(std::vector<LLScrollListItem*>::iterator itr = selected.begin(); itr != selected.end(); ++itr)
00757         {
00758                 LLUUID id = (*itr)->getValue();
00759                 const LLRelationship* buddy_relationship = LLAvatarTracker::instance().getBuddyInfo(id);
00760                 if (buddy_relationship == NULL) continue;
00761 
00762                 bool show_online_staus = (*itr)->getColumn(LIST_VISIBLE_ONLINE)->getValue().asBoolean();
00763                 bool show_map_location = (*itr)->getColumn(LIST_VISIBLE_MAP)->getValue().asBoolean();
00764                 bool allow_modify_objects = (*itr)->getColumn(LIST_EDIT_MINE)->getValue().asBoolean();
00765 
00766                 S32 rights = buddy_relationship->getRightsGrantedTo();
00767                 if(buddy_relationship->isRightGrantedTo(LLRelationship::GRANT_ONLINE_STATUS) != show_online_staus)
00768                 {
00769                         rights_changed = TRUE;
00770                         if(show_online_staus) 
00771                         {
00772                                 rights |= LLRelationship::GRANT_ONLINE_STATUS;
00773                         }
00774                         else 
00775                         {
00776                                 // ONLINE_STATUS necessary for MAP_LOCATION
00777                                 rights &= ~LLRelationship::GRANT_ONLINE_STATUS;
00778                                 rights &= ~LLRelationship::GRANT_MAP_LOCATION;
00779                                 // propagate rights constraint to UI
00780                                 (*itr)->getColumn(LIST_VISIBLE_MAP)->setValue(FALSE);
00781                         }
00782                 }
00783                 if(buddy_relationship->isRightGrantedTo(LLRelationship::GRANT_MAP_LOCATION) != show_map_location)
00784                 {
00785                         rights_changed = TRUE;
00786                         if(show_map_location) 
00787                         {
00788                                 // ONLINE_STATUS necessary for MAP_LOCATION
00789                                 rights |= LLRelationship::GRANT_MAP_LOCATION;
00790                                 rights |= LLRelationship::GRANT_ONLINE_STATUS;
00791                                 (*itr)->getColumn(LIST_VISIBLE_ONLINE)->setValue(TRUE);
00792                         }
00793                         else 
00794                         {
00795                                 rights &= ~LLRelationship::GRANT_MAP_LOCATION;
00796                         }
00797                 }
00798                 
00799                 // now check for change in modify object rights, which requires confirmation
00800                 if(buddy_relationship->isRightGrantedTo(LLRelationship::GRANT_MODIFY_OBJECTS) != allow_modify_objects)
00801                 {
00802                         rights_changed = TRUE;
00803                         need_confirmation = TRUE;
00804 
00805                         if(allow_modify_objects)
00806                         {
00807                                 rights |= LLRelationship::GRANT_MODIFY_OBJECTS;
00808                                 confirmation_type = GRANT;
00809                         }
00810                         else
00811                         {
00812                                 rights &= ~LLRelationship::GRANT_MODIFY_OBJECTS;
00813                                 confirmation_type = REVOKE;
00814                         }
00815                 }
00816 
00817                 if (rights_changed)
00818                 {
00819                         rights_updates.insert(std::make_pair(id, rights));
00820                         // disable these ui elements until response from server
00821                         // to avoid race conditions
00822                         (*itr)->setEnabled(FALSE);
00823                 }
00824         }
00825 
00826         // separately confirm grant and revoke of modify rights
00827         if (need_confirmation)
00828         {
00829                 confirmModifyRights(rights_updates, confirmation_type);
00830         }
00831         else
00832         {
00833                 sendRightsGrant(rights_updates);
00834         }
00835 }
00836 
00837 void LLPanelFriends::sendRightsGrant(rights_map_t& ids)
00838 {
00839         if (ids.empty()) return;
00840 
00841         LLMessageSystem* msg = gMessageSystem;
00842 
00843         // setup message header
00844         msg->newMessageFast(_PREHASH_GrantUserRights);
00845         msg->nextBlockFast(_PREHASH_AgentData);
00846         msg->addUUID(_PREHASH_AgentID, gAgent.getID());
00847         msg->addUUID(_PREHASH_SessionID, gAgent.getSessionID());
00848 
00849         rights_map_t::iterator id_it;
00850         rights_map_t::iterator end_it = ids.end();
00851         for(id_it = ids.begin(); id_it != end_it; ++id_it)
00852         {
00853                 msg->nextBlockFast(_PREHASH_Rights);
00854                 msg->addUUID(_PREHASH_AgentRelated, id_it->first);
00855                 msg->addS32(_PREHASH_RelatedRights, id_it->second);
00856         }
00857 
00858         mNumRightsChanged = ids.size();
00859         gAgent.sendReliableMessage();
00860 }
00861 
00862 
00863 
00864 // static
00865 void LLPanelFriends::handleRemove(S32 option, void* user_data)
00866 {
00867         LLDynamicArray<LLUUID>* ids = static_cast<LLDynamicArray<LLUUID>*>(user_data);
00868         for(LLDynamicArray<LLUUID>::iterator itr = ids->begin(); itr != ids->end(); ++itr)
00869         {
00870                 LLUUID id = (*itr);
00871                 const LLRelationship* ip = LLAvatarTracker::instance().getBuddyInfo(id);
00872                 if(ip)
00873                 {                       
00874                         switch(option)
00875                         {
00876                         case 0: // YES
00877                                 if( ip->isRightGrantedTo(LLRelationship::GRANT_MODIFY_OBJECTS))
00878                                 {
00879                                         LLAvatarTracker::instance().empower(id, FALSE);
00880                                         LLAvatarTracker::instance().notifyObservers();
00881                                 }
00882                                 LLAvatarTracker::instance().terminateBuddy(id);
00883                                 LLAvatarTracker::instance().notifyObservers();
00884                                 gInventory.addChangedMask(LLInventoryObserver::LABEL | LLInventoryObserver::CALLING_CARD, LLUUID::null);
00885                                 gInventory.notifyObservers();
00886                                 break;
00887 
00888                         case 1: // NO
00889                         default:
00890                                 llinfos << "No removal performed." << llendl;
00891                                 break;
00892                         }
00893                 }
00894                 
00895         }
00896         delete ids;
00897 }

Generated on Fri May 16 08:33:27 2008 for SecondLife by  doxygen 1.5.5