2 // Radegast Metaverse Client
3 // Copyright (c) 2009-2014, Radegast Development Team
4 // All rights reserved.
6 // Redistribution and use in source and binary forms, with or without
7 // modification, are permitted provided that the following conditions are met:
9 // * Redistributions of source code must retain the above copyright notice,
10 // this list of conditions and the following disclaimer.
11 // * Redistributions in binary form must reproduce the above copyright
12 // notice, this list of conditions and the following disclaimer in the
13 // documentation and/or other materials provided with the distribution.
14 // * Neither the name of the application "Radegast", nor the names of its
15 // contributors may be used to endorse or promote products derived from
16 // this software without specific prior written permission.
18 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
19 // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
21 // DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
22 // FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23 // DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
24 // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
25 // CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
26 // OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32 using System.Collections;
33 using System.Collections.Generic;
34 #if (COGBOT_LIBOMV || USE_STHREADS)
36 using Thread = ThreadPoolUtil.Thread;
37 using ThreadPool = ThreadPoolUtil.ThreadPool;
38 using Monitor = ThreadPoolUtil.Monitor;
40 using System.Threading;
42 using System.Windows.Forms;
44 using OpenMetaverse.Packets;
48 public partial class GroupDetails : UserControl
50 private RadegastInstance instance;
51 private GridClient client { get { return instance.Client; } }
53 private Dictionary<UUID, GroupTitle> titles;
54 private Dictionary<UUID, Group> myGroups { get { return instance.Groups; } }
55 private List<KeyValuePair<UUID, UUID>> roleMembers;
56 private Dictionary<UUID, GroupRole> roles;
57 private bool isMember;
58 private GroupMemberSorter memberSorter = new GroupMemberSorter();
59 private System.Threading.Timer nameUpdateTimer;
61 private UUID groupTitlesRequest, groupMembersRequest, groupRolesRequest, groupRolesMembersRequest;
63 public GroupDetails(RadegastInstance instance, Group group)
65 InitializeComponent();
66 Disposed += new EventHandler(GroupDetails_Disposed);
68 this.instance = instance;
71 if (group.InsigniaID != UUID.Zero)
73 SLImageHandler insignia = new SLImageHandler(instance, group.InsigniaID, string.Empty);
74 insignia.Dock = DockStyle.Fill;
75 pnlInsignia.Controls.Add(insignia);
78 nameUpdateTimer = new System.Threading.Timer(nameUpdateTimer_Elapsed, this,
79 System.Threading.Timeout.Infinite, System.Threading.Timeout.Infinite);
81 txtGroupID.Text = group.ID.ToString();
83 lblGroupName.Text = group.Name;
85 isMember = instance.Groups.ContainsKey(group.ID);
89 tcGroupDetails.TabPages.Remove(tpMembersRoles);
90 tcGroupDetails.TabPages.Remove(tpNotices);
93 lvwNoticeArchive.SmallImageList = frmMain.ResourceImages;
94 lvwNoticeArchive.ListViewItemSorter = new GroupNoticeSorter();
97 client.Groups.GroupTitlesReply += new EventHandler<GroupTitlesReplyEventArgs>(Groups_GroupTitlesReply);
98 client.Groups.GroupMembersReply += new EventHandler<GroupMembersReplyEventArgs>(Groups_GroupMembersReply);
99 client.Groups.GroupProfile += new EventHandler<GroupProfileEventArgs>(Groups_GroupProfile);
100 client.Groups.CurrentGroups += new EventHandler<CurrentGroupsEventArgs>(Groups_CurrentGroups);
101 client.Groups.GroupNoticesListReply += new EventHandler<GroupNoticesListReplyEventArgs>(Groups_GroupNoticesListReply);
102 client.Groups.GroupJoinedReply += new EventHandler<GroupOperationEventArgs>(Groups_GroupJoinedReply);
103 client.Groups.GroupLeaveReply += new EventHandler<GroupOperationEventArgs>(Groups_GroupLeaveReply);
104 client.Groups.GroupRoleDataReply += new EventHandler<GroupRolesDataReplyEventArgs>(Groups_GroupRoleDataReply);
105 client.Groups.GroupMemberEjected += new EventHandler<GroupOperationEventArgs>(Groups_GroupMemberEjected);
106 client.Groups.GroupRoleMembersReply += new EventHandler<GroupRolesMembersReplyEventArgs>(Groups_GroupRoleMembersReply);
107 client.Self.IM += new EventHandler<InstantMessageEventArgs>(Self_IM);
108 instance.Names.NameUpdated += new EventHandler<UUIDNameReplyEventArgs>(Names_NameUpdated);
109 RefreshControlsAvailability();
114 void GroupDetails_Disposed(object sender, EventArgs e)
116 client.Groups.GroupTitlesReply -= new EventHandler<GroupTitlesReplyEventArgs>(Groups_GroupTitlesReply);
117 client.Groups.GroupMembersReply -= new EventHandler<GroupMembersReplyEventArgs>(Groups_GroupMembersReply);
118 client.Groups.GroupProfile -= new EventHandler<GroupProfileEventArgs>(Groups_GroupProfile);
119 client.Groups.CurrentGroups -= new EventHandler<CurrentGroupsEventArgs>(Groups_CurrentGroups);
120 client.Groups.GroupNoticesListReply -= new EventHandler<GroupNoticesListReplyEventArgs>(Groups_GroupNoticesListReply);
121 client.Groups.GroupJoinedReply -= new EventHandler<GroupOperationEventArgs>(Groups_GroupJoinedReply);
122 client.Groups.GroupLeaveReply -= new EventHandler<GroupOperationEventArgs>(Groups_GroupLeaveReply);
123 client.Groups.GroupRoleDataReply -= new EventHandler<GroupRolesDataReplyEventArgs>(Groups_GroupRoleDataReply);
124 client.Groups.GroupRoleMembersReply -= new EventHandler<GroupRolesMembersReplyEventArgs>(Groups_GroupRoleMembersReply);
125 client.Groups.GroupMemberEjected -= new EventHandler<GroupOperationEventArgs>(Groups_GroupMemberEjected);
126 client.Self.IM -= new EventHandler<InstantMessageEventArgs>(Self_IM);
127 if (instance != null && instance.Names != null)
129 instance.Names.NameUpdated -= new EventHandler<UUIDNameReplyEventArgs>(Names_NameUpdated);
131 if (nameUpdateTimer != null)
133 nameUpdateTimer.Dispose();
134 nameUpdateTimer = null;
138 #region Network callbacks
140 void Groups_GroupMemberEjected(object sender, GroupOperationEventArgs e)
142 if (e.GroupID != group.ID) return;
146 BeginInvoke(new MethodInvoker(() => { RefreshGroupInfo(); }));
147 instance.TabConsole.DisplayNotificationInChat("Group member ejected.");
151 instance.TabConsole.DisplayNotificationInChat("Failed to eject group member.");
155 void Groups_GroupRoleMembersReply(object sender, GroupRolesMembersReplyEventArgs e)
157 if (e.GroupID == group.ID && e.RequestID == groupRolesMembersRequest)
159 roleMembers = e.RolesMembers;
160 BeginInvoke(new MethodInvoker(() =>
162 btnInviteNewMember.Enabled = HasPower(GroupPowers.Invite);
163 btnEjectMember.Enabled = HasPower(GroupPowers.Eject);
164 lvwMemberDetails_SelectedIndexChanged(null, null);
170 void Groups_GroupRoleDataReply(object sender, GroupRolesDataReplyEventArgs e)
172 if (e.GroupID == group.ID && e.RequestID == groupRolesRequest)
174 groupRolesMembersRequest = client.Groups.RequestGroupRolesMembers(group.ID);
175 if (roles == null) roles = e.Roles;
176 else lock (roles) roles = e.Roles;
177 BeginInvoke(new MethodInvoker(() => DisplayGroupRoles()));
181 void Groups_GroupLeaveReply(object sender, GroupOperationEventArgs e)
183 if (e.GroupID == group.ID && e.Success)
185 BeginInvoke(new MethodInvoker(() => RefreshGroupInfo()));
189 void Groups_GroupJoinedReply(object sender, GroupOperationEventArgs e)
191 if (e.GroupID == group.ID && e.Success)
193 BeginInvoke(new MethodInvoker(() => RefreshGroupInfo()));
197 UUID destinationFolderID;
199 void Self_IM(object sender, InstantMessageEventArgs e)
201 if (e.IM.Dialog != InstantMessageDialog.GroupNoticeRequested) return;
205 BeginInvoke(new MethodInvoker(() => Self_IM(sender, e)));
209 InstantMessage msg = e.IM;
213 if (msg.BinaryBucket.Length >= 18)
215 groupID = new UUID(msg.BinaryBucket, 2);
219 groupID = msg.FromAgentID;
222 if (groupID != group.ID) return;
224 if (msg.BinaryBucket.Length > 18 && msg.BinaryBucket[0] != 0)
226 type = (AssetType)msg.BinaryBucket[1];
227 destinationFolderID = client.Inventory.FindFolderForType(type);
228 int icoIndx = InventoryConsole.GetItemImageIndex(type.ToString().ToLower());
231 icnItem.Image = frmMain.ResourceImages.Images[icoIndx];
232 icnItem.Visible = true;
234 txtItemName.Text = Utils.BytesToString(msg.BinaryBucket, 18, msg.BinaryBucket.Length - 19);
235 btnSave.Enabled = true;
236 btnSave.Visible = icnItem.Visible = txtItemName.Visible = true;
240 string text = msg.Message.Replace("\n", System.Environment.NewLine);
241 int pos = msg.Message.IndexOf('|');
242 string title = msg.Message.Substring(0, pos);
243 text = text.Remove(0, pos + 1);
244 txtNotice.Text = text;
247 void Groups_GroupNoticesListReply(object sender, GroupNoticesListReplyEventArgs e)
249 if (e.GroupID != group.ID) return;
253 BeginInvoke(new MethodInvoker(() => Groups_GroupNoticesListReply(sender, e)));
257 lvwNoticeArchive.BeginUpdate();
259 foreach (GroupNoticesListEntry notice in e.Notices)
261 ListViewItem item = new ListViewItem();
262 item.SubItems.Add(notice.Subject);
263 item.SubItems.Add(notice.FromName);
264 string noticeDate = string.Empty;
265 if (notice.Timestamp != 0)
267 noticeDate = Utils.UnixTimeToDateTime(notice.Timestamp).ToShortDateString();
269 item.SubItems.Add(noticeDate);
271 if (notice.HasAttachment)
273 item.ImageIndex = InventoryConsole.GetItemImageIndex(notice.AssetType.ToString().ToLower());
278 lvwNoticeArchive.Items.Add(item);
280 lvwNoticeArchive.EndUpdate();
283 void Groups_CurrentGroups(object sender, CurrentGroupsEventArgs e)
285 BeginInvoke(new MethodInvoker(RefreshControlsAvailability));
288 void Groups_GroupProfile(object sender, GroupProfileEventArgs e)
290 if (group.ID != e.Group.ID) return;
294 BeginInvoke(new MethodInvoker(() => Groups_GroupProfile(sender, e)));
299 if (group.InsigniaID != UUID.Zero && pnlInsignia.Controls.Count == 0)
301 SLImageHandler insignia = new SLImageHandler(instance, group.InsigniaID, string.Empty);
302 insignia.Dock = DockStyle.Fill;
303 pnlInsignia.Controls.Add(insignia);
306 lblGroupName.Text = e.Group.Name;
307 tbxCharter.Text = group.Charter.Replace("\n", Environment.NewLine);
308 lblFounded.Text = "Founded by: " + instance.Names.Get(group.FounderID);
309 cbxShowInSearch.Checked = group.ShowInList;
310 cbxOpenEnrollment.Checked = group.OpenEnrollment;
312 if (group.MembershipFee > 0)
314 cbxEnrollmentFee.Checked = true;
315 nudEnrollmentFee.Value = group.MembershipFee;
319 cbxEnrollmentFee.Checked = false;
320 nudEnrollmentFee.Value = 0;
323 if (group.MaturePublish)
325 cbxMaturity.SelectedIndex = 1;
329 cbxMaturity.SelectedIndex = 0;
332 btnJoin.Enabled = btnJoin.Visible = false;
334 if (myGroups.ContainsKey(group.ID)) // I am in this group
336 cbxReceiveNotices.Checked = myGroups[group.ID].AcceptNotices;
337 cbxListInProfile.Checked = myGroups[group.ID].ListInProfile;
338 cbxReceiveNotices.CheckedChanged += new EventHandler(cbxListInProfile_CheckedChanged);
339 cbxListInProfile.CheckedChanged += new EventHandler(cbxListInProfile_CheckedChanged);
341 else if (group.OpenEnrollment) // I am not in this group, but I could join it
343 btnJoin.Text = "Join $L" + group.MembershipFee;
344 btnJoin.Enabled = btnJoin.Visible = true;
347 RefreshControlsAvailability();
350 void Names_NameUpdated(object sender, UUIDNameReplyEventArgs e)
352 ProcessNameUpdate(e.Names);
357 void ProcessNameUpdate(Dictionary<UUID, string> Names)
359 if (Names.ContainsKey(group.FounderID))
363 BeginInvoke(new MethodInvoker(() => { lblFounded.Text = "Founded by: " + Names[group.FounderID]; }));
367 lblFounded.Text = "Founded by: " + Names[group.FounderID];
371 WorkPool.QueueUserWorkItem(sync =>
375 bool hasUpdates = false;
377 foreach (var name in Names)
379 var member = GroupMembers.Find((m) => m.Base.ID == name.Key);
380 if (member == null) continue;
383 member.Name = name.Value;
388 int tick = Environment.TickCount;
389 int elapsed = tick - lastTick;
393 nameUpdateTimer_Elapsed(this);
395 nameUpdateTimer.Change(500, System.Threading.Timeout.Infinite);
400 Logger.DebugLog("Failed updating group member names: " + ex.ToString());
405 void Groups_GroupTitlesReply(object sender, GroupTitlesReplyEventArgs e)
407 if (groupTitlesRequest != e.RequestID) return;
411 BeginInvoke(new MethodInvoker(() => Groups_GroupTitlesReply(sender, e)));
415 this.titles = e.Titles;
417 foreach (GroupTitle title in titles.Values)
419 cbxActiveTitle.Items.Add(title);
422 cbxActiveTitle.SelectedItem = title;
426 cbxActiveTitle.SelectedIndexChanged += cbxActiveTitle_SelectedIndexChanged;
429 List<EnhancedGroupMember> GroupMembers = new List<EnhancedGroupMember>();
431 void Groups_GroupMembersReply(object sender, GroupMembersReplyEventArgs e)
435 BeginInvoke(new MethodInvoker(() => Groups_GroupMembersReply(sender, e)));
439 lvwGeneralMembers.VirtualListSize = 0;
440 lvwMemberDetails.VirtualListSize = 0;
442 var members = new List<EnhancedGroupMember>(e.Members.Count);
443 foreach (var member in e.Members)
445 members.Add(new EnhancedGroupMember(instance.Names.Get(member.Key), member.Value));
448 GroupMembers = members;
449 GroupMembers.Sort(memberSorter);
450 lvwGeneralMembers.VirtualListSize = GroupMembers.Count;
451 lvwMemberDetails.VirtualListSize = GroupMembers.Count;
454 void lvwMemberDetails_RetrieveVirtualItem(object sender, RetrieveVirtualItemEventArgs e)
456 EnhancedGroupMember member = null;
459 member = GroupMembers[e.ItemIndex];
463 e.Item = new ListViewItem();
467 ListViewItem item = new ListViewItem(member.Name);
469 item.Name = member.Base.ID.ToString();
470 item.SubItems.Add(new ListViewItem.ListViewSubItem(item, member.Base.Contribution.ToString()));
471 if (member.LastOnline != DateTime.MinValue)
473 item.SubItems.Add(new ListViewItem.ListViewSubItem(item, member.Base.OnlineStatus));
479 void lvwGeneralMembers_RetrieveVirtualItem(object sender, RetrieveVirtualItemEventArgs e)
481 EnhancedGroupMember member = null;
484 member = GroupMembers[e.ItemIndex];
488 e.Item = new ListViewItem();
491 ListViewItem item = new ListViewItem(member.Name);
494 item.Name = member.Base.ID.ToString();
495 item.SubItems.Add(new ListViewItem.ListViewSubItem(item, member.Base.Title));
496 if (member.LastOnline != DateTime.MinValue)
498 item.SubItems.Add(new ListViewItem.ListViewSubItem(item, member.Base.OnlineStatus));
505 #region Privatate methods
507 private void nameUpdateTimer_Elapsed(object sync)
511 BeginInvoke(new MethodInvoker(() => nameUpdateTimer_Elapsed(sync)));
515 GroupMembers.Sort(memberSorter);
516 lvwGeneralMembers.Invalidate();
517 lvwMemberDetails.Invalidate();
520 private void DisplayGroupRoles()
522 lvwRoles.Items.Clear();
526 foreach (GroupRole role in roles.Values)
528 ListViewItem item = new ListViewItem();
529 item.Name = role.ID.ToString();
530 item.Text = role.Name;
531 item.SubItems.Add(role.Title);
532 item.SubItems.Add(role.ID.ToString());
534 lvwRoles.Items.Add(item);
541 private bool HasPower(GroupPowers power)
543 if (!instance.Groups.ContainsKey(group.ID))
546 return (instance.Groups[group.ID].Powers & power) != 0;
549 private void RefreshControlsAvailability()
551 if (!HasPower(GroupPowers.ChangeOptions))
553 nudEnrollmentFee.ReadOnly = true;
554 cbxEnrollmentFee.Enabled = false;
555 cbxOpenEnrollment.Enabled = false;
558 if (!HasPower(GroupPowers.ChangeIdentity))
560 tbxCharter.ReadOnly = true;
561 cbxShowInSearch.Enabled = false;
562 cbxMaturity.Enabled = false;
565 if (!myGroups.ContainsKey(group.ID))
567 cbxReceiveNotices.Enabled = false;
568 cbxListInProfile.Enabled = false;
572 private void RefreshGroupNotices()
574 lvwNoticeArchive.Items.Clear();
575 client.Groups.RequestGroupNoticesList(group.ID);
576 btnNewNotice.Enabled = HasPower(GroupPowers.SendNotices);
579 private void RefreshGroupInfo()
581 lvwGeneralMembers.VirtualListSize = 0;
582 if (isMember) lvwMemberDetails.VirtualListSize = 0;
584 cbxActiveTitle.SelectedIndexChanged -= cbxActiveTitle_SelectedIndexChanged;
585 cbxReceiveNotices.CheckedChanged -= new EventHandler(cbxListInProfile_CheckedChanged);
586 cbxListInProfile.CheckedChanged -= new EventHandler(cbxListInProfile_CheckedChanged);
588 cbxActiveTitle.Items.Clear();
590 // Request group info
591 client.Groups.RequestGroupProfile(group.ID);
592 groupTitlesRequest = client.Groups.RequestGroupTitles(group.ID);
593 groupMembersRequest = client.Groups.RequestGroupMembers(group.ID);
596 private void RefreshRoles()
598 if (!isMember) return;
600 lvwRoles.SelectedItems.Clear();
601 lvwRoles.Items.Clear();
602 btnApply.Enabled = false;
603 btnCreateNewRole.Enabled = HasPower(GroupPowers.CreateRole);
604 btnDeleteRole.Enabled = HasPower(GroupPowers.DeleteRole);
605 txtRoleDescription.Enabled = txtRoleName.Enabled = txtRoleTitle.Enabled = lvwRoleAbilitis.Enabled = btnSaveRole.Enabled = false;
606 groupRolesRequest = client.Groups.RequestGroupRoles(group.ID);
609 private void RefreshMembersRoles()
611 if (!isMember) return;
613 btnApply.Enabled = false;
614 lvwAssignedRoles.Items.Clear();
615 groupRolesRequest = client.Groups.RequestGroupRoles(group.ID);
619 #region Controls change handlers
620 void cbxListInProfile_CheckedChanged(object sender, EventArgs e)
622 if (myGroups.ContainsKey(group.ID))
624 Group g = myGroups[group.ID];
625 // g.AcceptNotices = cbxReceiveNotices.Checked;
626 // g.ListInProfile = cbxListInProfile.Checked;
627 client.Groups.SetGroupAcceptNotices(g.ID, cbxReceiveNotices.Checked, cbxListInProfile.Checked);
628 client.Groups.RequestCurrentGroups();
632 private void cbxActiveTitle_SelectedIndexChanged(object sender, EventArgs e)
634 GroupTitle title = (GroupTitle)cbxActiveTitle.SelectedItem;
635 client.Groups.ActivateTitle(title.GroupID, title.RoleID);
638 private void btnRefresh_Click(object sender, EventArgs e)
640 switch (tcGroupDetails.SelectedTab.Name)
647 RefreshGroupNotices();
650 case "tpMembersRoles":
651 RefreshMembersRoles();
657 void lvwGeneralMembers_ColumnClick(object sender, ColumnClickEventArgs e)
659 ListView lb = (ListView)sender;
663 memberSorter.SortBy = GroupMemberSorter.SortByColumn.Name;
667 if (lb.Name == "lvwMemberDetails")
668 memberSorter.SortBy = GroupMemberSorter.SortByColumn.Contribution;
670 memberSorter.SortBy = GroupMemberSorter.SortByColumn.Title;
674 memberSorter.SortBy = GroupMemberSorter.SortByColumn.LastOnline;
678 if (memberSorter.CurrentOrder == GroupMemberSorter.SortOrder.Ascending)
679 memberSorter.CurrentOrder = GroupMemberSorter.SortOrder.Descending;
681 memberSorter.CurrentOrder = GroupMemberSorter.SortOrder.Ascending;
683 GroupMembers.Sort(memberSorter);
687 private void lvwNoticeArchive_ColumnClick(object sender, ColumnClickEventArgs e)
690 GroupNoticeSorter sorter = (GroupNoticeSorter)lvwNoticeArchive.ListViewItemSorter;
695 sorter.SortBy = GroupNoticeSorter.SortByColumn.Subject;
699 sorter.SortBy = GroupNoticeSorter.SortByColumn.Sender;
703 sorter.SortBy = GroupNoticeSorter.SortByColumn.Date;
707 if (sorter.CurrentOrder == GroupNoticeSorter.SortOrder.Ascending)
708 sorter.CurrentOrder = GroupNoticeSorter.SortOrder.Descending;
710 sorter.CurrentOrder = GroupNoticeSorter.SortOrder.Ascending;
712 lvwNoticeArchive.Sort();
716 private void btnClose_Click(object sender, EventArgs e)
718 this.FindForm().Close();
721 private void tcGroupDetails_SelectedIndexChanged(object sender, EventArgs e)
723 switch (tcGroupDetails.SelectedTab.Name)
726 RefreshGroupNotices();
729 case "tpMembersRoles":
730 RefreshMembersRoles();
735 private void lvwNoticeArchive_SelectedIndexChanged(object sender, EventArgs e)
737 if (lvwNoticeArchive.SelectedItems.Count == 1)
739 if (lvwNoticeArchive.SelectedItems[0].Tag is GroupNoticesListEntry)
741 GroupNoticesListEntry notice = (GroupNoticesListEntry)lvwNoticeArchive.SelectedItems[0].Tag;
742 lblSentBy.Text = "Sent by " + notice.FromName;
743 lblTitle.Text = notice.Subject;
744 txtNotice.Text = string.Empty;
745 btnSave.Enabled = btnSave.Visible = icnItem.Visible = txtItemName.Visible = false;
746 client.Groups.RequestGroupNotice(notice.NoticeID);
747 pnlNewNotice.Visible = false;
748 pnlArchivedNotice.Visible = true;
752 pnlArchivedNotice.Visible = false;
755 private void btnSave_Click(object sender, EventArgs e)
757 if (btnSave.Tag is InstantMessage)
759 InstantMessage msg = (InstantMessage)btnSave.Tag;
760 client.Self.InstantMessage(client.Self.Name, msg.FromAgentID, string.Empty, msg.IMSessionID, InstantMessageDialog.GroupNoticeInventoryAccepted, InstantMessageOnline.Offline, client.Self.SimPosition, client.Network.CurrentSim.RegionID, destinationFolderID.GetBytes());
761 btnSave.Enabled = false;
766 private void btnJoin_Click(object sender, EventArgs e)
768 client.Groups.RequestJoinGroup(group.ID);
771 private void lvwGeneralMembers_MouseDoubleClick(object sender, MouseEventArgs e)
773 ListViewItem item = lvwGeneralMembers.GetItemAt(e.X, e.Y);
778 UUID agentID = new UUID(item.Name);
779 instance.MainForm.ShowAgentProfile(item.Text, agentID);
781 catch (Exception) { }
785 private void lvwMemberDetails_MouseDoubleClick(object sender, MouseEventArgs e)
787 ListViewItem item = lvwMemberDetails.GetItemAt(e.X, e.Y);
792 UUID agentID = new UUID(item.Name);
793 instance.MainForm.ShowAgentProfile(item.Text, agentID);
795 catch (Exception) { }
799 private void btnEjectMember_Click(object sender, EventArgs e)
801 if (lvwMemberDetails.SelectedIndices.Count != 1 || roles == null || roleMembers == null) return;
802 EnhancedGroupMember m = GroupMembers[lvwMemberDetails.SelectedIndices[0]];
803 client.Groups.EjectUser(group.ID, m.Base.ID);
806 private void lvwMemberDetails_SelectedIndexChanged(object sender, EventArgs e)
808 if (lvwMemberDetails.SelectedIndices.Count != 1 || roles == null || roleMembers == null) return;
809 EnhancedGroupMember m = GroupMembers[lvwMemberDetails.SelectedIndices[0]];
811 btnApply.Enabled = false;
813 lvwAssignedRoles.BeginUpdate();
814 lvwAssignedRoles.ItemChecked -= lvwAssignedRoles_ItemChecked;
815 lvwAssignedRoles.Items.Clear();
816 lvwAssignedRoles.Tag = m;
818 ListViewItem defaultItem = new ListViewItem();
819 defaultItem.Name = "Everyone";
820 defaultItem.SubItems.Add(defaultItem.Name);
821 defaultItem.Checked = true;
822 lvwAssignedRoles.Items.Add(defaultItem);
824 GroupPowers abilities = GroupPowers.None;
828 foreach (var r in roles)
830 GroupRole role = r.Value;
832 if (role.ID == UUID.Zero)
834 abilities |= role.Powers;
838 ListViewItem item = new ListViewItem();
839 item.Name = role.Name;
840 item.SubItems.Add(new ListViewItem.ListViewSubItem(item, role.Name));
842 var foundRole = roleMembers.Find((KeyValuePair<UUID, UUID> kvp) => { return kvp.Value == m.Base.ID && kvp.Key == role.ID; });
843 bool hasRole = foundRole.Value == m.Base.ID;
844 item.Checked = hasRole;
845 lvwAssignedRoles.Items.Add(item);
848 abilities |= role.Powers;
852 lvwAssignedRoles.ItemChecked += lvwAssignedRoles_ItemChecked;
853 lvwAssignedRoles.EndUpdate();
855 lvwAllowedAbilities.BeginUpdate();
856 lvwAllowedAbilities.Items.Clear();
858 foreach (GroupPowers p in Enum.GetValues(typeof(GroupPowers)))
860 if (p != GroupPowers.None && (abilities & p) == p)
862 lvwAllowedAbilities.Items.Add(p.ToString());
867 lvwAllowedAbilities.EndUpdate();
871 private void UpdateMemberRoles()
873 EnhancedGroupMember m = (EnhancedGroupMember)lvwAssignedRoles.Tag;
874 GroupRoleChangesPacket p = new GroupRoleChangesPacket();
875 p.AgentData.AgentID = client.Self.AgentID;
876 p.AgentData.SessionID = client.Self.SessionID;
877 p.AgentData.GroupID = group.ID;
878 List<GroupRoleChangesPacket.RoleChangeBlock> changes = new List<GroupRoleChangesPacket.RoleChangeBlock>();
880 foreach (ListViewItem item in lvwAssignedRoles.Items)
882 if (!(item.Tag is GroupRole))
885 GroupRole role = (GroupRole)item.Tag;
886 var foundRole = roleMembers.Find((KeyValuePair<UUID, UUID> kvp) => { return kvp.Value == m.Base.ID && kvp.Key == role.ID; });
887 bool hasRole = foundRole.Value == m.Base.ID;
889 if (item.Checked != hasRole)
892 roleMembers.Add(new KeyValuePair<UUID, UUID>(role.ID, m.Base.ID));
894 roleMembers.Remove(foundRole);
896 var rc = new GroupRoleChangesPacket.RoleChangeBlock();
897 rc.MemberID = m.Base.ID;
899 rc.Change = item.Checked ? 0u : 1u;
904 if (changes.Count > 0)
906 p.RoleChange = changes.ToArray();
907 client.Network.CurrentSim.SendPacket(p);
910 btnApply.Enabled = false;
911 lvwMemberDetails_SelectedIndexChanged(lvwMemberDetails, EventArgs.Empty);
915 private void lvwAssignedRoles_ItemChecked(object sender, ItemCheckedEventArgs e)
917 if (e.Item.Tag == null) // click on the default role
920 e.Item.Checked = true;
924 if (e.Item.Tag is GroupRole)
926 EnhancedGroupMember m = (EnhancedGroupMember)lvwAssignedRoles.Tag;
927 bool modified = false;
929 foreach (ListViewItem item in lvwAssignedRoles.Items)
931 if (!(item.Tag is GroupRole))
934 GroupRole role = (GroupRole)item.Tag;
935 var foundRole = roleMembers.Find((KeyValuePair<UUID, UUID> kvp) => { return kvp.Value == m.Base.ID && kvp.Key == role.ID; });
936 bool hasRole = foundRole.Value == m.Base.ID;
938 if (item.Checked != hasRole)
944 btnApply.Enabled = modified;
948 private void tbxCharter_TextChanged(object sender, EventArgs e)
950 btnApply.Enabled = true;
953 private void btnApply_Click(object sender, EventArgs e)
955 switch (tcGroupDetails.SelectedTab.Name)
957 case "tpMembersRoles":
963 private void btnInviteNewMember_Click(object sender, EventArgs e)
965 (new GroupInvite(instance, group, roles)).Show();
968 private void lvwAllowedAbilities_SizeChanged(object sender, EventArgs e)
970 lvwAllowedAbilities.Columns[0].Width = lvwAllowedAbilities.Width - 30;
973 private void tcMembersRoles_SelectedIndexChanged(object sender, EventArgs e)
975 switch (tcMembersRoles.SelectedTab.Name)
978 RefreshMembersRoles();
989 private void lvwRoles_SelectedIndexChanged(object sender, EventArgs e)
991 txtRoleDescription.Text = txtRoleName.Text = txtRoleTitle.Text = string.Empty;
992 txtRoleDescription.Enabled = txtRoleName.Enabled = txtRoleTitle.Enabled = lvwRoleAbilitis.Enabled = btnSaveRole.Enabled = false;
993 lvwAssignedMembers.Items.Clear();
994 lvwRoleAbilitis.Items.Clear();
996 if (lvwRoles.SelectedItems.Count != 1) return;
998 GroupRole role = (GroupRole)lvwRoles.SelectedItems[0].Tag;
999 txtRoleName.Text = role.Name;
1000 txtRoleTitle.Text = role.Title;
1001 txtRoleDescription.Text = role.Description;
1003 if (HasPower(GroupPowers.RoleProperties))
1005 txtRoleDescription.Enabled = txtRoleName.Enabled = txtRoleTitle.Enabled = btnSaveRole.Enabled = true;
1008 if (HasPower(GroupPowers.ChangeActions))
1010 lvwRoleAbilitis.Enabled = btnSaveRole.Enabled = true;
1013 btnSaveRole.Tag = role;
1015 lvwAssignedMembers.BeginUpdate();
1016 if (role.ID == UUID.Zero)
1018 foreach (var member in GroupMembers)
1019 lvwAssignedMembers.Items.Add(member.Name);
1021 else if (roleMembers != null)
1023 var mmb = roleMembers.FindAll((KeyValuePair<UUID, UUID> kvp) => { return kvp.Key == role.ID; });
1024 foreach (var m in mmb)
1026 lvwAssignedMembers.Items.Add(instance.Names.Get(m.Value));
1029 lvwAssignedMembers.EndUpdate();
1031 lvwRoleAbilitis.Tag = role;
1033 foreach (GroupPowers p in Enum.GetValues(typeof(GroupPowers)))
1035 if (p != GroupPowers.None)
1037 ListViewItem item = new ListViewItem();
1039 item.SubItems.Add(p.ToString());
1040 item.Checked = (p & role.Powers) != 0;
1041 lvwRoleAbilitis.Items.Add(item);
1046 private void btnCreateNewRole_Click(object sender, EventArgs e)
1048 lvwRoles.SelectedItems.Clear();
1049 txtRoleDescription.Enabled = txtRoleName.Enabled = txtRoleTitle.Enabled = btnSaveRole.Enabled = true;
1050 btnSaveRole.Tag = null;
1051 txtRoleName.Focus();
1054 private void btnSaveRole_Click(object sender, EventArgs e)
1056 if (btnSaveRole.Tag == null) // new role
1058 GroupRole role = new GroupRole();
1059 role.Name = txtRoleName.Text;
1060 role.Title = txtRoleTitle.Text;
1061 role.Description = txtRoleDescription.Text;
1062 client.Groups.CreateRole(group.ID, role);
1063 System.Threading.Thread.Sleep(100);
1066 else if (btnSaveRole.Tag is GroupRole) // update role
1068 GroupRole role = (GroupRole)btnSaveRole.Tag;
1070 if (HasPower(GroupPowers.ChangeActions))
1072 role.Powers = GroupPowers.None;
1074 foreach (ListViewItem item in lvwRoleAbilitis.Items)
1077 role.Powers |= (GroupPowers)item.Tag;
1081 if (HasPower(GroupPowers.RoleProperties))
1083 role.Name = txtRoleName.Text;
1084 role.Title = txtRoleTitle.Text;
1085 role.Description = txtRoleDescription.Text;
1088 client.Groups.UpdateRole(role);
1089 System.Threading.Thread.Sleep(100);
1094 private void btnDeleteRole_Click(object sender, EventArgs e)
1096 if (lvwRoles.SelectedItems.Count == 1)
1098 client.Groups.DeleteRole(group.ID, ((GroupRole)lvwRoles.SelectedItems[0].Tag).ID);
1099 System.Threading.Thread.Sleep(100);
1105 private void btnNewNotice_Click(object sender, EventArgs e)
1107 if (HasPower(GroupPowers.SendNotices))
1109 pnlArchivedNotice.Visible = false;
1110 pnlNewNotice.Visible = true;
1111 txtNewNoticeTitle.Focus();
1115 instance.TabConsole.DisplayNotificationInChat("Don't have permission to send notices in this group", ChatBufferTextStyle.Error);
1119 private void btnPasteInv_Click(object sender, EventArgs e)
1121 if (instance.InventoryClipboard != null && instance.InventoryClipboard.Item is InventoryItem)
1123 InventoryItem inv = instance.InventoryClipboard.Item as InventoryItem;
1124 txtNewNoteAtt.Text = inv.Name;
1125 int icoIndx = InventoryConsole.GetItemImageIndex(inv.AssetType.ToString().ToLower());
1128 icnNewNoticeAtt.Image = frmMain.ResourceImages.Images[icoIndx];
1129 icnNewNoticeAtt.Visible = true;
1131 txtNewNoteAtt.Tag = inv;
1132 btnRemoveAttachment.Enabled = true;
1136 private void btnRemoveAttachment_Click(object sender, EventArgs e)
1138 txtNewNoteAtt.Tag = null;
1139 txtNewNoteAtt.Text = string.Empty;
1140 btnRemoveAttachment.Enabled = false;
1141 icnNewNoticeAtt.Visible = false;
1144 private void btnSend_Click(object sender, EventArgs e)
1146 GroupNotice ntc = new GroupNotice();
1147 ntc.Subject = txtNewNoticeTitle.Text;
1148 ntc.Message = txtNewNoticeBody.Text;
1149 if (txtNewNoteAtt.Tag != null && txtNewNoteAtt.Tag is InventoryItem)
1151 InventoryItem inv = txtNewNoteAtt.Tag as InventoryItem;
1152 ntc.OwnerID = inv.OwnerID;
1153 ntc.AttachmentID = inv.UUID;
1155 client.Groups.SendGroupNotice(group.ID, ntc);
1156 btnRemoveAttachment.PerformClick();
1157 txtNewNoticeTitle.Text = txtNewNoticeBody.Text = string.Empty;
1158 pnlNewNotice.Visible = false;
1159 btnRefresh.PerformClick();
1160 instance.TabConsole.DisplayNotificationInChat("Notice sent", ChatBufferTextStyle.Invisible);
1164 private void memberListContextMenuSave_Click(object sender, EventArgs e)
1166 SaveFileDialog saveMembers = new SaveFileDialog();
1167 saveMembers.Filter = "CSV|.csv|JSON|.json";
1168 saveMembers.Title = "Save visible group members";
1169 saveMembers.ShowDialog();
1170 if (saveMembers.FileName != string.Empty)
1174 switch (saveMembers.FilterIndex)
1177 System.IO.FileStream fs = (System.IO.FileStream)saveMembers.OpenFile();
1178 System.IO.StreamWriter sw = new System.IO.StreamWriter(fs, System.Text.Encoding.UTF8);
1179 sw.WriteLine("UUID,Name");
1180 foreach (var item in GroupMembers)
1182 sw.WriteLine("{0},{1}", item.Base.ID, item.Name);
1187 OpenMetaverse.StructuredData.OSDArray members = new OpenMetaverse.StructuredData.OSDArray(GroupMembers.Count);
1188 foreach (var item in GroupMembers)
1190 OpenMetaverse.StructuredData.OSDMap member = new OpenMetaverse.StructuredData.OSDMap(2);
1191 member["UUID"] = item.Base.ID;
1192 member["Name"] = item.Name;
1193 members.Add(member);
1195 System.IO.File.WriteAllText(saveMembers.FileName, OpenMetaverse.StructuredData.OSDParser.SerializeJsonString(members));
1199 instance.TabConsole.DisplayNotificationInChat(string.Format("Saved {0} members to {1}", GroupMembers.Count, saveMembers.FileName));
1201 catch (Exception ex)
1203 instance.TabConsole.DisplayNotificationInChat("Failed to save member list: " + ex.Message, ChatBufferTextStyle.Error);
1208 private void copyRoleIDToolStripMenuItem_Click(object sender, EventArgs e)
1210 if (lvwRoles.SelectedItems.Count != 1) return;
1211 if (lvwRoles.SelectedItems[0].Tag is GroupRole)
1213 Clipboard.SetText(((GroupRole)lvwRoles.SelectedItems[0].Tag).ID.ToString());
1217 private void lvwMemberDetails_SearchForVirtualItem(object sender, SearchForVirtualItemEventArgs e)
1221 for (int i = 0; i < GroupMembers.Count; i++)
1223 if (GroupMembers[i].Name.StartsWith(e.Text, StringComparison.CurrentCultureIgnoreCase))
1234 public class EnhancedGroupMember
1236 public GroupMember Base;
1237 public DateTime LastOnline;
1240 public EnhancedGroupMember(string name, GroupMember baseMember)
1245 if (baseMember.OnlineStatus == "Online")
1247 LastOnline = DateTime.Now;
1249 else if (string.IsNullOrEmpty(baseMember.OnlineStatus) || baseMember.OnlineStatus == "unknown")
1251 LastOnline = DateTime.MinValue;
1257 LastOnline = Convert.ToDateTime(baseMember.OnlineStatus, Utils.EnUsCulture);
1259 catch (FormatException)
1261 LastOnline = DateTime.MaxValue;
1267 #region Sorter classes
1268 public class GroupMemberSorter : IComparer<EnhancedGroupMember>
1270 public enum SortByColumn
1278 public enum SortOrder
1284 public SortOrder CurrentOrder = SortOrder.Ascending;
1285 public SortByColumn SortBy = SortByColumn.Name;
1287 public int Compare(EnhancedGroupMember member1, EnhancedGroupMember member2)
1291 case SortByColumn.Name:
1292 if (CurrentOrder == SortOrder.Ascending)
1293 return string.Compare(member1.Name, member2.Name);
1295 return string.Compare(member2.Name, member1.Name);
1297 case SortByColumn.Title:
1298 if (CurrentOrder == SortOrder.Ascending)
1299 return string.Compare(member1.Base.Title, member2.Base.Title);
1301 return string.Compare(member2.Base.Title, member1.Base.Title);
1303 case SortByColumn.LastOnline:
1304 if (CurrentOrder == SortOrder.Ascending)
1305 return DateTime.Compare(member1.LastOnline, member2.LastOnline);
1307 return DateTime.Compare(member2.LastOnline, member1.LastOnline);
1309 case SortByColumn.Contribution:
1310 if (member1.Base.Contribution < member2.Base.Contribution)
1311 return CurrentOrder == SortOrder.Ascending ? -1 : 1;
1312 else if (member1.Base.Contribution > member2.Base.Contribution)
1313 return CurrentOrder == SortOrder.Ascending ? 1 : -1;
1323 public class GroupNoticeSorter : IComparer
1325 public enum SortByColumn
1332 public enum SortOrder
1338 public SortOrder CurrentOrder = SortOrder.Descending;
1339 public SortByColumn SortBy = SortByColumn.Date;
1341 private int IntCompare(uint x, uint y)
1357 public int Compare(object x, object y)
1359 ListViewItem item1 = (ListViewItem)x;
1360 ListViewItem item2 = (ListViewItem)y;
1361 GroupNoticesListEntry member1 = (GroupNoticesListEntry)item1.Tag;
1362 GroupNoticesListEntry member2 = (GroupNoticesListEntry)item2.Tag;
1366 case SortByColumn.Subject:
1367 if (CurrentOrder == SortOrder.Ascending)
1368 return string.Compare(member1.Subject, member2.Subject);
1370 return string.Compare(member2.Subject, member1.Subject);
1372 case SortByColumn.Sender:
1373 if (CurrentOrder == SortOrder.Ascending)
1374 return string.Compare(member1.FromName, member2.FromName);
1376 return string.Compare(member2.FromName, member1.FromName);
1378 case SortByColumn.Date:
1379 if (CurrentOrder == SortOrder.Ascending)
1380 return IntCompare(member1.Timestamp, member2.Timestamp);
1382 return IntCompare(member2.Timestamp, member1.Timestamp);