OSDN Git Service

4a20ee255605c1617e857e56bc67316981145621
[radegast/radegast.git] / Radegast / GUI / Consoles / GroupDetails.cs
1 // 
2 // Radegast Metaverse Client
3 // Copyright (c) 2009-2014, Radegast Development Team
4 // All rights reserved.
5 // 
6 // Redistribution and use in source and binary forms, with or without
7 // modification, are permitted provided that the following conditions are met:
8 // 
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.
17 // 
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.
28 //
29 // $Id$
30 //
31 using System;
32 using System.Collections;
33 using System.Collections.Generic;
34 #if (COGBOT_LIBOMV || USE_STHREADS)
35 using ThreadPoolUtil;
36 using Thread = ThreadPoolUtil.Thread;
37 using ThreadPool = ThreadPoolUtil.ThreadPool;
38 using Monitor = ThreadPoolUtil.Monitor;
39 #endif
40 using System.Threading;
41 using System.Timers;
42 using System.Windows.Forms;
43 using OpenMetaverse;
44 using OpenMetaverse.Packets;
45
46 namespace Radegast
47 {
48     public partial class GroupDetails : UserControl
49     {
50         private RadegastInstance instance;
51         private GridClient client { get { return instance.Client; } }
52         private Group group;
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;
60
61         private UUID groupTitlesRequest, groupMembersRequest, groupRolesRequest, groupRolesMembersRequest;
62
63         public GroupDetails(RadegastInstance instance, Group group)
64         {
65             InitializeComponent();
66             Disposed += new EventHandler(GroupDetails_Disposed);
67
68             this.instance = instance;
69             this.group = group;
70
71             if (group.InsigniaID != UUID.Zero)
72             {
73                 SLImageHandler insignia = new SLImageHandler(instance, group.InsigniaID, string.Empty);
74                 insignia.Dock = DockStyle.Fill;
75                 pnlInsignia.Controls.Add(insignia);
76             }
77
78             nameUpdateTimer = new System.Threading.Timer(nameUpdateTimer_Elapsed, this,
79                 System.Threading.Timeout.Infinite, System.Threading.Timeout.Infinite);
80
81             txtGroupID.Text = group.ID.ToString();
82
83             lblGroupName.Text = group.Name;
84
85             isMember = instance.Groups.ContainsKey(group.ID);
86
87             if (!isMember)
88             {
89                 tcGroupDetails.TabPages.Remove(tpMembersRoles);
90                 tcGroupDetails.TabPages.Remove(tpNotices);
91             }
92
93             lvwNoticeArchive.SmallImageList = frmMain.ResourceImages;
94             lvwNoticeArchive.ListViewItemSorter = new GroupNoticeSorter();
95
96             // Callbacks
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();
110             RefreshGroupInfo();
111         }
112
113
114         void GroupDetails_Disposed(object sender, EventArgs e)
115         {
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)
128             {
129                 instance.Names.NameUpdated -= new EventHandler<UUIDNameReplyEventArgs>(Names_NameUpdated);
130             }
131             if (nameUpdateTimer != null)
132             {
133                 nameUpdateTimer.Dispose();
134                 nameUpdateTimer = null;
135             }
136         }
137
138         #region Network callbacks
139
140         void Groups_GroupMemberEjected(object sender, GroupOperationEventArgs e)
141         {
142             if (e.GroupID != group.ID) return;
143
144             if (e.Success)
145             {
146                 BeginInvoke(new MethodInvoker(() => { RefreshGroupInfo(); }));
147                 instance.TabConsole.DisplayNotificationInChat("Group member ejected.");
148             }
149             else
150             {
151                 instance.TabConsole.DisplayNotificationInChat("Failed to eject group member.");
152             }
153         }
154
155         void Groups_GroupRoleMembersReply(object sender, GroupRolesMembersReplyEventArgs e)
156         {
157             if (e.GroupID == group.ID && e.RequestID == groupRolesMembersRequest)
158             {
159                 roleMembers = e.RolesMembers;
160                 BeginInvoke(new MethodInvoker(() =>
161                     {
162                         btnInviteNewMember.Enabled = HasPower(GroupPowers.Invite);
163                         btnEjectMember.Enabled = HasPower(GroupPowers.Eject);
164                         lvwMemberDetails_SelectedIndexChanged(null, null);
165                     }
166                 ));
167             }
168         }
169
170         void Groups_GroupRoleDataReply(object sender, GroupRolesDataReplyEventArgs e)
171         {
172             if (e.GroupID == group.ID && e.RequestID == groupRolesRequest)
173             {
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()));
178             }
179         }
180
181         void Groups_GroupLeaveReply(object sender, GroupOperationEventArgs e)
182         {
183             if (e.GroupID == group.ID && e.Success)
184             {
185                 BeginInvoke(new MethodInvoker(() => RefreshGroupInfo()));
186             }
187         }
188
189         void Groups_GroupJoinedReply(object sender, GroupOperationEventArgs e)
190         {
191             if (e.GroupID == group.ID && e.Success)
192             {
193                 BeginInvoke(new MethodInvoker(() => RefreshGroupInfo()));
194             }
195         }
196
197         UUID destinationFolderID;
198
199         void Self_IM(object sender, InstantMessageEventArgs e)
200         {
201             if (e.IM.Dialog != InstantMessageDialog.GroupNoticeRequested) return;
202
203             if (InvokeRequired)
204             {
205                 BeginInvoke(new MethodInvoker(() => Self_IM(sender, e)));
206                 return;
207             }
208
209             InstantMessage msg = e.IM;
210             AssetType type;
211             UUID groupID;
212
213             if (msg.BinaryBucket.Length >= 18)
214             {
215                 groupID = new UUID(msg.BinaryBucket, 2);
216             }
217             else
218             {
219                 groupID = msg.FromAgentID;
220             }
221
222             if (groupID != group.ID) return;
223
224             if (msg.BinaryBucket.Length > 18 && msg.BinaryBucket[0] != 0)
225             {
226                 type = (AssetType)msg.BinaryBucket[1];
227                 destinationFolderID = client.Inventory.FindFolderForType(type);
228                 int icoIndx = InventoryConsole.GetItemImageIndex(type.ToString().ToLower());
229                 if (icoIndx >= 0)
230                 {
231                     icnItem.Image = frmMain.ResourceImages.Images[icoIndx];
232                     icnItem.Visible = true;
233                 }
234                 txtItemName.Text = Utils.BytesToString(msg.BinaryBucket, 18, msg.BinaryBucket.Length - 19);
235                 btnSave.Enabled = true;
236                 btnSave.Visible = icnItem.Visible = txtItemName.Visible = true;
237                 btnSave.Tag = msg;
238             }
239
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;
245         }
246
247         void Groups_GroupNoticesListReply(object sender, GroupNoticesListReplyEventArgs e)
248         {
249             if (e.GroupID != group.ID) return;
250
251             if (InvokeRequired)
252             {
253                 BeginInvoke(new MethodInvoker(() => Groups_GroupNoticesListReply(sender, e)));
254                 return;
255             }
256
257             lvwNoticeArchive.BeginUpdate();
258
259             foreach (GroupNoticesListEntry notice in e.Notices)
260             {
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)
266                 {
267                     noticeDate = Utils.UnixTimeToDateTime(notice.Timestamp).ToShortDateString();
268                 }
269                 item.SubItems.Add(noticeDate);
270
271                 if (notice.HasAttachment)
272                 {
273                     item.ImageIndex = InventoryConsole.GetItemImageIndex(notice.AssetType.ToString().ToLower());
274                 }
275
276                 item.Tag = notice;
277
278                 lvwNoticeArchive.Items.Add(item);
279             }
280             lvwNoticeArchive.EndUpdate();
281         }
282
283         void Groups_CurrentGroups(object sender, CurrentGroupsEventArgs e)
284         {
285             BeginInvoke(new MethodInvoker(RefreshControlsAvailability));
286         }
287
288         void Groups_GroupProfile(object sender, GroupProfileEventArgs e)
289         {
290             if (group.ID != e.Group.ID) return;
291
292             if (InvokeRequired)
293             {
294                 BeginInvoke(new MethodInvoker(() => Groups_GroupProfile(sender, e)));
295                 return;
296             }
297
298             group = e.Group;
299             if (group.InsigniaID != UUID.Zero && pnlInsignia.Controls.Count == 0)
300             {
301                 SLImageHandler insignia = new SLImageHandler(instance, group.InsigniaID, string.Empty);
302                 insignia.Dock = DockStyle.Fill;
303                 pnlInsignia.Controls.Add(insignia);
304             }
305
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;
311
312             if (group.MembershipFee > 0)
313             {
314                 cbxEnrollmentFee.Checked = true;
315                 nudEnrollmentFee.Value = group.MembershipFee;
316             }
317             else
318             {
319                 cbxEnrollmentFee.Checked = false;
320                 nudEnrollmentFee.Value = 0;
321             }
322
323             if (group.MaturePublish)
324             {
325                 cbxMaturity.SelectedIndex = 1;
326             }
327             else
328             {
329                 cbxMaturity.SelectedIndex = 0;
330             }
331
332             btnJoin.Enabled = btnJoin.Visible = false;
333
334             if (myGroups.ContainsKey(group.ID)) // I am in this group
335             {
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);
340             }
341             else if (group.OpenEnrollment) // I am not in this group, but I could join it
342             {
343                 btnJoin.Text = "Join $L" + group.MembershipFee;
344                 btnJoin.Enabled = btnJoin.Visible = true;
345             }
346
347             RefreshControlsAvailability();
348         }
349
350         void Names_NameUpdated(object sender, UUIDNameReplyEventArgs e)
351         {
352             ProcessNameUpdate(e.Names);
353         }
354
355         int lastTick = 0;
356
357         void ProcessNameUpdate(Dictionary<UUID, string> Names)
358         {
359             if (Names.ContainsKey(group.FounderID))
360             {
361                 if (InvokeRequired)
362                 {
363                     BeginInvoke(new MethodInvoker(() => { lblFounded.Text = "Founded by: " + Names[group.FounderID]; }));
364                 }
365                 else
366                 {
367                     lblFounded.Text = "Founded by: " + Names[group.FounderID];
368                 }
369             }
370
371             WorkPool.QueueUserWorkItem(sync =>
372             {
373                 try
374                 {
375                     bool hasUpdates = false;
376
377                     foreach (var name in Names)
378                     {
379                         var member = GroupMembers.Find((m) => m.Base.ID == name.Key);
380                         if (member == null) continue;
381
382                         hasUpdates = true;
383                         member.Name = name.Value;
384                     }
385
386                     if (hasUpdates)
387                     {
388                         int tick = Environment.TickCount;
389                         int elapsed = tick - lastTick;
390                         if (elapsed > 500)
391                         {
392                             lastTick = tick;
393                             nameUpdateTimer_Elapsed(this);
394                         }
395                         nameUpdateTimer.Change(500, System.Threading.Timeout.Infinite);
396                     }
397                 }
398                 catch (Exception ex)
399                 {
400                     Logger.DebugLog("Failed updating group member names: " + ex.ToString());
401                 }
402             });
403         }
404
405         void Groups_GroupTitlesReply(object sender, GroupTitlesReplyEventArgs e)
406         {
407             if (groupTitlesRequest != e.RequestID) return;
408
409             if (InvokeRequired)
410             {
411                 BeginInvoke(new MethodInvoker(() => Groups_GroupTitlesReply(sender, e)));
412                 return;
413             }
414
415             this.titles = e.Titles;
416
417             foreach (GroupTitle title in titles.Values)
418             {
419                 cbxActiveTitle.Items.Add(title);
420                 if (title.Selected)
421                 {
422                     cbxActiveTitle.SelectedItem = title;
423                 }
424             }
425
426             cbxActiveTitle.SelectedIndexChanged += cbxActiveTitle_SelectedIndexChanged;
427         }
428
429         List<EnhancedGroupMember> GroupMembers = new List<EnhancedGroupMember>();
430
431         void Groups_GroupMembersReply(object sender, GroupMembersReplyEventArgs e)
432         {
433             if (InvokeRequired)
434             {
435                 BeginInvoke(new MethodInvoker(() => Groups_GroupMembersReply(sender, e)));
436                 return;
437             }
438
439             lvwGeneralMembers.VirtualListSize = 0;
440             lvwMemberDetails.VirtualListSize = 0;
441
442             var members = new List<EnhancedGroupMember>(e.Members.Count);
443             foreach (var member in e.Members)
444             {
445                 members.Add(new EnhancedGroupMember(instance.Names.Get(member.Key), member.Value));
446             }
447
448             GroupMembers = members;
449             GroupMembers.Sort(memberSorter);
450             lvwGeneralMembers.VirtualListSize = GroupMembers.Count;
451             lvwMemberDetails.VirtualListSize = GroupMembers.Count;
452         }
453
454         void lvwMemberDetails_RetrieveVirtualItem(object sender, RetrieveVirtualItemEventArgs e)
455         {
456             EnhancedGroupMember member = null;
457             try
458             {
459                 member = GroupMembers[e.ItemIndex];
460             }
461             catch
462             {
463                 e.Item = new ListViewItem();
464                 return;
465             }
466
467             ListViewItem item = new ListViewItem(member.Name);
468             item.Tag = member;
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)
472             {
473                 item.SubItems.Add(new ListViewItem.ListViewSubItem(item, member.Base.OnlineStatus));
474             }
475
476             e.Item = item;
477         }
478
479         void lvwGeneralMembers_RetrieveVirtualItem(object sender, RetrieveVirtualItemEventArgs e)
480         {
481             EnhancedGroupMember member = null;
482             try
483             {
484                 member = GroupMembers[e.ItemIndex];
485             }
486             catch
487             {
488                 e.Item = new ListViewItem();
489                 return;
490             }
491             ListViewItem item = new ListViewItem(member.Name);
492
493             item.Tag = member;
494             item.Name = member.Base.ID.ToString();
495             item.SubItems.Add(new ListViewItem.ListViewSubItem(item, member.Base.Title));
496             if (member.LastOnline != DateTime.MinValue)
497             {
498                 item.SubItems.Add(new ListViewItem.ListViewSubItem(item, member.Base.OnlineStatus));
499             }
500
501             e.Item = item;
502         }
503         #endregion
504
505         #region Privatate methods
506
507         private void nameUpdateTimer_Elapsed(object sync)
508         {
509             if (InvokeRequired)
510             {
511                 BeginInvoke(new MethodInvoker(() => nameUpdateTimer_Elapsed(sync)));
512                 return;
513             }
514
515             GroupMembers.Sort(memberSorter);
516             lvwGeneralMembers.Invalidate();
517             lvwMemberDetails.Invalidate();
518         }
519
520         private void DisplayGroupRoles()
521         {
522             lvwRoles.Items.Clear();
523
524             lock (roles)
525             {
526                 foreach (GroupRole role in roles.Values)
527                 {
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());
533                     item.Tag = role;
534                     lvwRoles.Items.Add(item);
535                 }
536             }
537
538         }
539
540
541         private bool HasPower(GroupPowers power)
542         {
543             if (!instance.Groups.ContainsKey(group.ID))
544                 return false;
545
546             return (instance.Groups[group.ID].Powers & power) != 0;
547         }
548
549         private void RefreshControlsAvailability()
550         {
551             if (!HasPower(GroupPowers.ChangeOptions))
552             {
553                 nudEnrollmentFee.ReadOnly = true;
554                 cbxEnrollmentFee.Enabled = false;
555                 cbxOpenEnrollment.Enabled = false;
556             }
557
558             if (!HasPower(GroupPowers.ChangeIdentity))
559             {
560                 tbxCharter.ReadOnly = true;
561                 cbxShowInSearch.Enabled = false;
562                 cbxMaturity.Enabled = false;
563             }
564
565             if (!myGroups.ContainsKey(group.ID))
566             {
567                 cbxReceiveNotices.Enabled = false;
568                 cbxListInProfile.Enabled = false;
569             }
570         }
571
572         private void RefreshGroupNotices()
573         {
574             lvwNoticeArchive.Items.Clear();
575             client.Groups.RequestGroupNoticesList(group.ID);
576             btnNewNotice.Enabled = HasPower(GroupPowers.SendNotices);
577         }
578
579         private void RefreshGroupInfo()
580         {
581             lvwGeneralMembers.VirtualListSize = 0;
582             if (isMember) lvwMemberDetails.VirtualListSize = 0;
583
584             cbxActiveTitle.SelectedIndexChanged -= cbxActiveTitle_SelectedIndexChanged;
585             cbxReceiveNotices.CheckedChanged -= new EventHandler(cbxListInProfile_CheckedChanged);
586             cbxListInProfile.CheckedChanged -= new EventHandler(cbxListInProfile_CheckedChanged);
587
588             cbxActiveTitle.Items.Clear();
589
590             // Request group info
591             client.Groups.RequestGroupProfile(group.ID);
592             groupTitlesRequest = client.Groups.RequestGroupTitles(group.ID);
593             groupMembersRequest = client.Groups.RequestGroupMembers(group.ID);
594         }
595
596         private void RefreshRoles()
597         {
598             if (!isMember) return;
599
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);
607         }
608
609         private void RefreshMembersRoles()
610         {
611             if (!isMember) return;
612
613             btnApply.Enabled = false;
614             lvwAssignedRoles.Items.Clear();
615             groupRolesRequest = client.Groups.RequestGroupRoles(group.ID);
616         }
617         #endregion
618
619         #region Controls change handlers
620         void cbxListInProfile_CheckedChanged(object sender, EventArgs e)
621         {
622             if (myGroups.ContainsKey(group.ID))
623             {
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();
629             }
630         }
631
632         private void cbxActiveTitle_SelectedIndexChanged(object sender, EventArgs e)
633         {
634             GroupTitle title = (GroupTitle)cbxActiveTitle.SelectedItem;
635             client.Groups.ActivateTitle(title.GroupID, title.RoleID);
636         }
637
638         private void btnRefresh_Click(object sender, EventArgs e)
639         {
640             switch (tcGroupDetails.SelectedTab.Name)
641             {
642                 case "tpGeneral":
643                     RefreshGroupInfo();
644                     break;
645
646                 case "tpNotices":
647                     RefreshGroupNotices();
648                     break;
649
650                 case "tpMembersRoles":
651                     RefreshMembersRoles();
652                     break;
653             }
654         }
655         #endregion
656
657         void lvwGeneralMembers_ColumnClick(object sender, ColumnClickEventArgs e)
658         {
659             ListView lb = (ListView)sender;
660             switch (e.Column)
661             {
662                 case 0:
663                     memberSorter.SortBy = GroupMemberSorter.SortByColumn.Name;
664                     break;
665
666                 case 1:
667                     if (lb.Name == "lvwMemberDetails")
668                         memberSorter.SortBy = GroupMemberSorter.SortByColumn.Contribution;
669                     else
670                         memberSorter.SortBy = GroupMemberSorter.SortByColumn.Title;
671                     break;
672
673                 case 2:
674                     memberSorter.SortBy = GroupMemberSorter.SortByColumn.LastOnline;
675                     break;
676             }
677
678             if (memberSorter.CurrentOrder == GroupMemberSorter.SortOrder.Ascending)
679                 memberSorter.CurrentOrder = GroupMemberSorter.SortOrder.Descending;
680             else
681                 memberSorter.CurrentOrder = GroupMemberSorter.SortOrder.Ascending;
682
683             GroupMembers.Sort(memberSorter);
684             lb.Invalidate();
685         }
686
687         private void lvwNoticeArchive_ColumnClick(object sender, ColumnClickEventArgs e)
688         {
689
690             GroupNoticeSorter sorter = (GroupNoticeSorter)lvwNoticeArchive.ListViewItemSorter;
691
692             switch (e.Column)
693             {
694                 case 1:
695                     sorter.SortBy = GroupNoticeSorter.SortByColumn.Subject;
696                     break;
697
698                 case 2:
699                     sorter.SortBy = GroupNoticeSorter.SortByColumn.Sender;
700                     break;
701
702                 case 3:
703                     sorter.SortBy = GroupNoticeSorter.SortByColumn.Date;
704                     break;
705             }
706
707             if (sorter.CurrentOrder == GroupNoticeSorter.SortOrder.Ascending)
708                 sorter.CurrentOrder = GroupNoticeSorter.SortOrder.Descending;
709             else
710                 sorter.CurrentOrder = GroupNoticeSorter.SortOrder.Ascending;
711
712             lvwNoticeArchive.Sort();
713         }
714
715
716         private void btnClose_Click(object sender, EventArgs e)
717         {
718             this.FindForm().Close();
719         }
720
721         private void tcGroupDetails_SelectedIndexChanged(object sender, EventArgs e)
722         {
723             switch (tcGroupDetails.SelectedTab.Name)
724             {
725                 case "tpNotices":
726                     RefreshGroupNotices();
727                     break;
728
729                 case "tpMembersRoles":
730                     RefreshMembersRoles();
731                     break;
732             }
733         }
734
735         private void lvwNoticeArchive_SelectedIndexChanged(object sender, EventArgs e)
736         {
737             if (lvwNoticeArchive.SelectedItems.Count == 1)
738             {
739                 if (lvwNoticeArchive.SelectedItems[0].Tag is GroupNoticesListEntry)
740                 {
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;
749                     return;
750                 }
751             }
752             pnlArchivedNotice.Visible = false;
753         }
754
755         private void btnSave_Click(object sender, EventArgs e)
756         {
757             if (btnSave.Tag is InstantMessage)
758             {
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;
762                 btnClose.Focus();
763             }
764         }
765
766         private void btnJoin_Click(object sender, EventArgs e)
767         {
768             client.Groups.RequestJoinGroup(group.ID);
769         }
770
771         private void lvwGeneralMembers_MouseDoubleClick(object sender, MouseEventArgs e)
772         {
773             ListViewItem item = lvwGeneralMembers.GetItemAt(e.X, e.Y);
774             if (item != null)
775             {
776                 try
777                 {
778                     UUID agentID = new UUID(item.Name);
779                     instance.MainForm.ShowAgentProfile(item.Text, agentID);
780                 }
781                 catch (Exception) { }
782             }
783         }
784
785         private void lvwMemberDetails_MouseDoubleClick(object sender, MouseEventArgs e)
786         {
787             ListViewItem item = lvwMemberDetails.GetItemAt(e.X, e.Y);
788             if (item != null)
789             {
790                 try
791                 {
792                     UUID agentID = new UUID(item.Name);
793                     instance.MainForm.ShowAgentProfile(item.Text, agentID);
794                 }
795                 catch (Exception) { }
796             }
797         }
798
799         private void btnEjectMember_Click(object sender, EventArgs e)
800         {
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);
804         }
805
806         private void lvwMemberDetails_SelectedIndexChanged(object sender, EventArgs e)
807         {
808             if (lvwMemberDetails.SelectedIndices.Count != 1 || roles == null || roleMembers == null) return;
809             EnhancedGroupMember m = GroupMembers[lvwMemberDetails.SelectedIndices[0]];
810
811             btnApply.Enabled = false;
812
813             lvwAssignedRoles.BeginUpdate();
814             lvwAssignedRoles.ItemChecked -= lvwAssignedRoles_ItemChecked;
815             lvwAssignedRoles.Items.Clear();
816             lvwAssignedRoles.Tag = m;
817
818             ListViewItem defaultItem = new ListViewItem();
819             defaultItem.Name = "Everyone";
820             defaultItem.SubItems.Add(defaultItem.Name);
821             defaultItem.Checked = true;
822             lvwAssignedRoles.Items.Add(defaultItem);
823
824             GroupPowers abilities = GroupPowers.None;
825
826             lock (roles)
827             {
828                 foreach (var r in roles)
829                 {
830                     GroupRole role = r.Value;
831
832                     if (role.ID == UUID.Zero)
833                     {
834                         abilities |= role.Powers;
835                         continue;
836                     }
837
838                     ListViewItem item = new ListViewItem();
839                     item.Name = role.Name;
840                     item.SubItems.Add(new ListViewItem.ListViewSubItem(item, role.Name));
841                     item.Tag = role;
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);
846
847                     if (hasRole)
848                         abilities |= role.Powers;
849                 }
850             }
851
852             lvwAssignedRoles.ItemChecked += lvwAssignedRoles_ItemChecked;
853             lvwAssignedRoles.EndUpdate();
854
855             lvwAllowedAbilities.BeginUpdate();
856             lvwAllowedAbilities.Items.Clear();
857
858             foreach (GroupPowers p in Enum.GetValues(typeof(GroupPowers)))
859             {
860                 if (p != GroupPowers.None && (abilities & p) == p)
861                 {
862                     lvwAllowedAbilities.Items.Add(p.ToString());
863                 }
864             }
865
866
867             lvwAllowedAbilities.EndUpdate();
868
869         }
870
871         private void UpdateMemberRoles()
872         {
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>();
879
880             foreach (ListViewItem item in lvwAssignedRoles.Items)
881             {
882                 if (!(item.Tag is GroupRole))
883                     continue;
884
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;
888
889                 if (item.Checked != hasRole)
890                 {
891                     if (item.Checked)
892                         roleMembers.Add(new KeyValuePair<UUID, UUID>(role.ID, m.Base.ID));
893                     else
894                         roleMembers.Remove(foundRole);
895
896                     var rc = new GroupRoleChangesPacket.RoleChangeBlock();
897                     rc.MemberID = m.Base.ID;
898                     rc.RoleID = role.ID;
899                     rc.Change = item.Checked ? 0u : 1u;
900                     changes.Add(rc);
901                 }
902             }
903
904             if (changes.Count > 0)
905             {
906                 p.RoleChange = changes.ToArray();
907                 client.Network.CurrentSim.SendPacket(p);
908             }
909
910             btnApply.Enabled = false;
911             lvwMemberDetails_SelectedIndexChanged(lvwMemberDetails, EventArgs.Empty);
912         }
913
914
915         private void lvwAssignedRoles_ItemChecked(object sender, ItemCheckedEventArgs e)
916         {
917             if (e.Item.Tag == null) // click on the default role
918             {
919                 if (!e.Item.Checked)
920                     e.Item.Checked = true;
921
922                 return;
923             }
924             if (e.Item.Tag is GroupRole)
925             {
926                 EnhancedGroupMember m = (EnhancedGroupMember)lvwAssignedRoles.Tag;
927                 bool modified = false;
928
929                 foreach (ListViewItem item in lvwAssignedRoles.Items)
930                 {
931                     if (!(item.Tag is GroupRole))
932                         continue;
933
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;
937
938                     if (item.Checked != hasRole)
939                     {
940                         modified = true;
941                     }
942                 }
943
944                 btnApply.Enabled = modified;
945             }
946         }
947
948         private void tbxCharter_TextChanged(object sender, EventArgs e)
949         {
950             btnApply.Enabled = true;
951         }
952
953         private void btnApply_Click(object sender, EventArgs e)
954         {
955             switch (tcGroupDetails.SelectedTab.Name)
956             {
957                 case "tpMembersRoles":
958                     UpdateMemberRoles();
959                     break;
960             }
961         }
962
963         private void btnInviteNewMember_Click(object sender, EventArgs e)
964         {
965             (new GroupInvite(instance, group, roles)).Show();
966         }
967
968         private void lvwAllowedAbilities_SizeChanged(object sender, EventArgs e)
969         {
970             lvwAllowedAbilities.Columns[0].Width = lvwAllowedAbilities.Width - 30;
971         }
972
973         private void tcMembersRoles_SelectedIndexChanged(object sender, EventArgs e)
974         {
975             switch (tcMembersRoles.SelectedTab.Name)
976             {
977                 case "tpMembers":
978                     RefreshMembersRoles();
979                     break;
980
981                 case "tpRoles":
982                     RefreshRoles();
983                     break;
984
985             }
986
987         }
988
989         private void lvwRoles_SelectedIndexChanged(object sender, EventArgs e)
990         {
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();
995
996             if (lvwRoles.SelectedItems.Count != 1) return;
997
998             GroupRole role = (GroupRole)lvwRoles.SelectedItems[0].Tag;
999             txtRoleName.Text = role.Name;
1000             txtRoleTitle.Text = role.Title;
1001             txtRoleDescription.Text = role.Description;
1002
1003             if (HasPower(GroupPowers.RoleProperties))
1004             {
1005                 txtRoleDescription.Enabled = txtRoleName.Enabled = txtRoleTitle.Enabled = btnSaveRole.Enabled = true;
1006             }
1007
1008             if (HasPower(GroupPowers.ChangeActions))
1009             {
1010                 lvwRoleAbilitis.Enabled = btnSaveRole.Enabled = true;
1011             }
1012
1013             btnSaveRole.Tag = role;
1014
1015             lvwAssignedMembers.BeginUpdate();
1016             if (role.ID == UUID.Zero)
1017             {
1018                 foreach (var member in GroupMembers)
1019                     lvwAssignedMembers.Items.Add(member.Name);
1020             }
1021             else if (roleMembers != null)
1022             {
1023                 var mmb = roleMembers.FindAll((KeyValuePair<UUID, UUID> kvp) => { return kvp.Key == role.ID; });
1024                 foreach (var m in mmb)
1025                 {
1026                     lvwAssignedMembers.Items.Add(instance.Names.Get(m.Value));
1027                 }
1028             }
1029             lvwAssignedMembers.EndUpdate();
1030
1031             lvwRoleAbilitis.Tag = role;
1032
1033             foreach (GroupPowers p in Enum.GetValues(typeof(GroupPowers)))
1034             {
1035                 if (p != GroupPowers.None)
1036                 {
1037                     ListViewItem item = new ListViewItem();
1038                     item.Tag = p;
1039                     item.SubItems.Add(p.ToString());
1040                     item.Checked = (p & role.Powers) != 0;
1041                     lvwRoleAbilitis.Items.Add(item);
1042                 }
1043             }
1044         }
1045
1046         private void btnCreateNewRole_Click(object sender, EventArgs e)
1047         {
1048             lvwRoles.SelectedItems.Clear();
1049             txtRoleDescription.Enabled = txtRoleName.Enabled = txtRoleTitle.Enabled = btnSaveRole.Enabled = true;
1050             btnSaveRole.Tag = null;
1051             txtRoleName.Focus();
1052         }
1053
1054         private void btnSaveRole_Click(object sender, EventArgs e)
1055         {
1056             if (btnSaveRole.Tag == null) // new role
1057             {
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);
1064                 RefreshRoles();
1065             }
1066             else if (btnSaveRole.Tag is GroupRole) // update role
1067             {
1068                 GroupRole role = (GroupRole)btnSaveRole.Tag;
1069
1070                 if (HasPower(GroupPowers.ChangeActions))
1071                 {
1072                     role.Powers = GroupPowers.None;
1073
1074                     foreach (ListViewItem item in lvwRoleAbilitis.Items)
1075                     {
1076                         if (item.Checked)
1077                             role.Powers |= (GroupPowers)item.Tag;
1078                     }
1079                 }
1080
1081                 if (HasPower(GroupPowers.RoleProperties))
1082                 {
1083                     role.Name = txtRoleName.Text;
1084                     role.Title = txtRoleTitle.Text;
1085                     role.Description = txtRoleDescription.Text;
1086                 }
1087
1088                 client.Groups.UpdateRole(role);
1089                 System.Threading.Thread.Sleep(100);
1090                 RefreshRoles();
1091             }
1092         }
1093
1094         private void btnDeleteRole_Click(object sender, EventArgs e)
1095         {
1096             if (lvwRoles.SelectedItems.Count == 1)
1097             {
1098                 client.Groups.DeleteRole(group.ID, ((GroupRole)lvwRoles.SelectedItems[0].Tag).ID);
1099                 System.Threading.Thread.Sleep(100);
1100                 RefreshRoles();
1101             }
1102         }
1103
1104         #region New notice
1105         private void btnNewNotice_Click(object sender, EventArgs e)
1106         {
1107             if (HasPower(GroupPowers.SendNotices))
1108             {
1109                 pnlArchivedNotice.Visible = false;
1110                 pnlNewNotice.Visible = true;
1111                 txtNewNoticeTitle.Focus();
1112             }
1113             else
1114             {
1115                 instance.TabConsole.DisplayNotificationInChat("Don't have permission to send notices in this group", ChatBufferTextStyle.Error);
1116             }
1117         }
1118
1119         private void btnPasteInv_Click(object sender, EventArgs e)
1120         {
1121             if (instance.InventoryClipboard != null && instance.InventoryClipboard.Item is InventoryItem)
1122             {
1123                 InventoryItem inv = instance.InventoryClipboard.Item as InventoryItem;
1124                 txtNewNoteAtt.Text = inv.Name;
1125                 int icoIndx = InventoryConsole.GetItemImageIndex(inv.AssetType.ToString().ToLower());
1126                 if (icoIndx >= 0)
1127                 {
1128                     icnNewNoticeAtt.Image = frmMain.ResourceImages.Images[icoIndx];
1129                     icnNewNoticeAtt.Visible = true;
1130                 }
1131                 txtNewNoteAtt.Tag = inv;
1132                 btnRemoveAttachment.Enabled = true;
1133             }
1134         }
1135
1136         private void btnRemoveAttachment_Click(object sender, EventArgs e)
1137         {
1138             txtNewNoteAtt.Tag = null;
1139             txtNewNoteAtt.Text = string.Empty;
1140             btnRemoveAttachment.Enabled = false;
1141             icnNewNoticeAtt.Visible = false;
1142         }
1143
1144         private void btnSend_Click(object sender, EventArgs e)
1145         {
1146             GroupNotice ntc = new GroupNotice();
1147             ntc.Subject = txtNewNoticeTitle.Text;
1148             ntc.Message = txtNewNoticeBody.Text;
1149             if (txtNewNoteAtt.Tag != null && txtNewNoteAtt.Tag is InventoryItem)
1150             {
1151                 InventoryItem inv = txtNewNoteAtt.Tag as InventoryItem;
1152                 ntc.OwnerID = inv.OwnerID;
1153                 ntc.AttachmentID = inv.UUID;
1154             }
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);
1161         }
1162         #endregion
1163
1164         private void memberListContextMenuSave_Click(object sender, EventArgs e)
1165         {
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)
1171             {
1172                 try
1173                 {
1174                     switch (saveMembers.FilterIndex)
1175                     {
1176                         case 1:
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)
1181                             {
1182                                 sw.WriteLine("{0},{1}", item.Base.ID, item.Name);
1183                             }
1184                             sw.Close();
1185                             break;
1186                         case 2:
1187                             OpenMetaverse.StructuredData.OSDArray members = new OpenMetaverse.StructuredData.OSDArray(GroupMembers.Count);
1188                             foreach (var item in GroupMembers)
1189                             {
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);
1194                             }
1195                             System.IO.File.WriteAllText(saveMembers.FileName, OpenMetaverse.StructuredData.OSDParser.SerializeJsonString(members));
1196                             break;
1197                     }
1198
1199                     instance.TabConsole.DisplayNotificationInChat(string.Format("Saved {0} members to {1}", GroupMembers.Count, saveMembers.FileName));
1200                 }
1201                 catch (Exception ex)
1202                 {
1203                     instance.TabConsole.DisplayNotificationInChat("Failed to save member list: " + ex.Message, ChatBufferTextStyle.Error);
1204                 }
1205             }
1206         }
1207
1208         private void copyRoleIDToolStripMenuItem_Click(object sender, EventArgs e)
1209         {
1210             if (lvwRoles.SelectedItems.Count != 1) return;
1211             if (lvwRoles.SelectedItems[0].Tag is GroupRole)
1212             {
1213                 Clipboard.SetText(((GroupRole)lvwRoles.SelectedItems[0].Tag).ID.ToString());
1214             }
1215         }
1216
1217         private void lvwMemberDetails_SearchForVirtualItem(object sender, SearchForVirtualItemEventArgs e)
1218         {
1219             if (e.IsTextSearch)
1220             {
1221                 for (int i = 0; i < GroupMembers.Count; i++)
1222                 {
1223                     if (GroupMembers[i].Name.StartsWith(e.Text, StringComparison.CurrentCultureIgnoreCase))
1224                     {
1225                         e.Index = i;
1226                         break;
1227                     }
1228                 }
1229             }
1230         }
1231
1232     }
1233
1234     public class EnhancedGroupMember
1235     {
1236         public GroupMember Base;
1237         public DateTime LastOnline;
1238         public string Name;
1239
1240         public EnhancedGroupMember(string name, GroupMember baseMember)
1241         {
1242             Base = baseMember;
1243             Name = name;
1244
1245             if (baseMember.OnlineStatus == "Online")
1246             {
1247                 LastOnline = DateTime.Now;
1248             }
1249             else if (string.IsNullOrEmpty(baseMember.OnlineStatus) || baseMember.OnlineStatus == "unknown")
1250             {
1251                 LastOnline = DateTime.MinValue;
1252             }
1253             else
1254             {
1255                 try
1256                 {
1257                     LastOnline = Convert.ToDateTime(baseMember.OnlineStatus, Utils.EnUsCulture);
1258                 }
1259                 catch (FormatException)
1260                 {
1261                     LastOnline = DateTime.MaxValue;
1262                 }
1263             }
1264         }
1265     }
1266
1267     #region Sorter classes
1268     public class GroupMemberSorter : IComparer<EnhancedGroupMember>
1269     {
1270         public enum SortByColumn
1271         {
1272             Name,
1273             Title,
1274             LastOnline,
1275             Contribution
1276         }
1277
1278         public enum SortOrder
1279         {
1280             Ascending,
1281             Descending
1282         }
1283
1284         public SortOrder CurrentOrder = SortOrder.Ascending;
1285         public SortByColumn SortBy = SortByColumn.Name;
1286
1287         public int Compare(EnhancedGroupMember member1, EnhancedGroupMember member2)
1288         {
1289             switch (SortBy)
1290             {
1291                 case SortByColumn.Name:
1292                     if (CurrentOrder == SortOrder.Ascending)
1293                         return string.Compare(member1.Name, member2.Name);
1294                     else
1295                         return string.Compare(member2.Name, member1.Name);
1296
1297                 case SortByColumn.Title:
1298                     if (CurrentOrder == SortOrder.Ascending)
1299                         return string.Compare(member1.Base.Title, member2.Base.Title);
1300                     else
1301                         return string.Compare(member2.Base.Title, member1.Base.Title);
1302
1303                 case SortByColumn.LastOnline:
1304                     if (CurrentOrder == SortOrder.Ascending)
1305                         return DateTime.Compare(member1.LastOnline, member2.LastOnline);
1306                     else
1307                         return DateTime.Compare(member2.LastOnline, member1.LastOnline);
1308
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;
1314                     else
1315                         return 0;
1316             }
1317
1318             return 0;
1319         }
1320     }
1321
1322
1323     public class GroupNoticeSorter : IComparer
1324     {
1325         public enum SortByColumn
1326         {
1327             Subject,
1328             Sender,
1329             Date
1330         }
1331
1332         public enum SortOrder
1333         {
1334             Ascending,
1335             Descending
1336         }
1337
1338         public SortOrder CurrentOrder = SortOrder.Descending;
1339         public SortByColumn SortBy = SortByColumn.Date;
1340
1341         private int IntCompare(uint x, uint y)
1342         {
1343             if (x < y)
1344             {
1345                 return -1;
1346             }
1347             else if (x > y)
1348             {
1349                 return 1;
1350             }
1351             else
1352             {
1353                 return 0;
1354             }
1355         }
1356
1357         public int Compare(object x, object y)
1358         {
1359             ListViewItem item1 = (ListViewItem)x;
1360             ListViewItem item2 = (ListViewItem)y;
1361             GroupNoticesListEntry member1 = (GroupNoticesListEntry)item1.Tag;
1362             GroupNoticesListEntry member2 = (GroupNoticesListEntry)item2.Tag;
1363
1364             switch (SortBy)
1365             {
1366                 case SortByColumn.Subject:
1367                     if (CurrentOrder == SortOrder.Ascending)
1368                         return string.Compare(member1.Subject, member2.Subject);
1369                     else
1370                         return string.Compare(member2.Subject, member1.Subject);
1371
1372                 case SortByColumn.Sender:
1373                     if (CurrentOrder == SortOrder.Ascending)
1374                         return string.Compare(member1.FromName, member2.FromName);
1375                     else
1376                         return string.Compare(member2.FromName, member1.FromName);
1377
1378                 case SortByColumn.Date:
1379                     if (CurrentOrder == SortOrder.Ascending)
1380                         return IntCompare(member1.Timestamp, member2.Timestamp);
1381                     else
1382                         return IntCompare(member2.Timestamp, member1.Timestamp);
1383             }
1384
1385             return 0;
1386         }
1387     }
1388     #endregion
1389 }