corrade-vassal – Blame information for rev 1

Subversion Repositories:
Rev:
Rev Author Line No. Line
1 vero 1 /*
2 * Copyright (c) 2006-2014, openmetaverse.org
3 * All rights reserved.
4 *
5 * - Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 *
8 * - Redistributions of source code must retain the above copyright notice, this
9 * list of conditions and the following disclaimer.
10 * - Neither the name of the openmetaverse.org nor the names
11 * of its contributors may be used to endorse or promote products derived from
12 * this software without specific prior written permission.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
15 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
18 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
19 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
20 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
21 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
22 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
23 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
24 * POSSIBILITY OF SUCH DAMAGE.
25 */
26  
27 using OpenMetaverse;
28 using System;
29 using System.Collections;
30 using System.Collections.Generic;
31 using System.Drawing;
32 using System.Windows.Forms;
33  
34 namespace OpenMetaverse.GUI
35 {
36  
37 /// <summary>
38 /// ListView GUI component for viewing a client's nearby avatars list
39 /// </summary>
40 public class AvatarList : ListView
41 {
42 private GridClient _Client;
43 private ListColumnSorter _ColumnSorter = new ListColumnSorter();
44 private TrackedAvatar _SelectedAvatar;
45  
46 private DoubleDictionary<uint, UUID, TrackedAvatar> _TrackedAvatars = new DoubleDictionary<uint, UUID, TrackedAvatar>();
47 private Dictionary<UUID, TrackedAvatar> _UntrackedAvatars = new Dictionary<UUID, TrackedAvatar>();
48  
49 public delegate void AvatarCallback(TrackedAvatar trackedAvatar);
50  
51 /// <summary>
52 /// Triggered when the user double clicks on an avatar in the list
53 /// </summary>
54 public event AvatarCallback OnAvatarDoubleClick;
55  
56 /// <summary>
57 /// Triggered when a new avatar is added to the list
58 /// </summary>
59 public event AvatarCallback OnAvatarAdded;
60  
61 /// <summary>
62 /// Triggered when an avatar is removed from the list
63 /// </summary>
64 public event AvatarCallback OnAvatarRemoved;
65  
66 /// <summary>
67 /// Gets or sets the GridClient associated with this control
68 /// </summary>
69 public GridClient Client
70 {
71 get { return _Client; }
72 set { if (value != null) InitializeClient(value); }
73 }
74  
75 /// <summary>
76 /// Returns the current selected avatar in the tracked avatars list
77 /// </summary>
78 public TrackedAvatar SelectedAvatar
79 {
80 get { return _SelectedAvatar; }
81 }
82  
83 /// <summary>
84 /// TreeView control for an unspecified client's nearby avatar list
85 /// </summary>
86 public AvatarList()
87 {
88 ColumnHeader header1 = this.Columns.Add("Name");
89 header1.Width = this.Width - 20;
90  
91 ColumnHeader header2 = this.Columns.Add(" ");
92 header2.Width = 40;
93  
94 this.MultiSelect = false;
95 this.SelectedIndexChanged += new EventHandler(AvatarList_SelectedIndexChanged);
96  
97 _ColumnSorter.SortColumn = 1;
98 this.Sorting = SortOrder.Ascending;
99 this.ListViewItemSorter = _ColumnSorter;
100  
101 EventHandler clickHandler = new EventHandler(defaultMenuItem_Click);
102 this.ContextMenu = new ContextMenu();
103 this.ContextMenu.MenuItems.Add("Offer Teleport", clickHandler);
104 this.ContextMenu.MenuItems.Add("Teleport To", clickHandler);
105 this.ContextMenu.MenuItems.Add("Walk To", clickHandler);
106  
107 this.DoubleBuffered = true;
108 this.ListViewItemSorter = _ColumnSorter;
109 this.View = View.Details;
110 this.ColumnClick += new ColumnClickEventHandler(AvatarList_ColumnClick);
111 this.DoubleClick += new EventHandler(AvatarList_DoubleClick);
112 }
113  
114 void AvatarList_SelectedIndexChanged(object sender, EventArgs e)
115 {
116 lock (_TrackedAvatars)
117 {
118 lock (_UntrackedAvatars)
119 {
120 if (this.SelectedItems.Count > 0)
121 {
122 UUID selectedID = new UUID(this.SelectedItems[0].Name);
123 TrackedAvatar selectedAV;
124 if (!_TrackedAvatars.TryGetValue(selectedID, out selectedAV) && !_UntrackedAvatars.TryGetValue(selectedID, out selectedAV))
125 selectedAV = null;
126  
127 _SelectedAvatar = selectedAV;
128 }
129 }
130 }
131 }
132  
133 /// <summary>
134 /// Thread-safe method for clearing the TreeView control
135 /// </summary>
136 public void ClearItems()
137 {
138 if (this.InvokeRequired) this.BeginInvoke((MethodInvoker)delegate { ClearItems(); });
139 else
140 {
141 if (this.Handle != IntPtr.Zero)
142 this.Items.Clear();
143 }
144 }
145  
146 public TrackedAvatar GetAvatar(UUID avatarID)
147 {
148 TrackedAvatar av;
149 _TrackedAvatars.TryGetValue(avatarID, out av);
150 return av;
151 }
152  
153 private void InitializeClient(GridClient client)
154 {
155 _Client = client;
156 _Client.Avatars.AvatarAppearance += Avatars_OnAvatarAppearance;
157 _Client.Avatars.UUIDNameReply += new EventHandler<UUIDNameReplyEventArgs>(Avatars_UUIDNameReply);
158 _Client.Grid.CoarseLocationUpdate += Grid_CoarseLocationUpdate;
159 _Client.Network.SimChanged += Network_OnCurrentSimChanged;
160 _Client.Objects.AvatarUpdate += Objects_OnNewAvatar;
161 _Client.Objects.TerseObjectUpdate += Objects_OnObjectUpdated;
162  
163 }
164  
165 void Avatars_UUIDNameReply(object sender, UUIDNameReplyEventArgs e)
166 {
167 lock (_UntrackedAvatars)
168 {
169 foreach (KeyValuePair<UUID, string> name in e.Names)
170 {
171 TrackedAvatar trackedAvatar;
172 if (_UntrackedAvatars.TryGetValue(name.Key, out trackedAvatar))
173 {
174 trackedAvatar.Name = name.Value;
175  
176 if (OnAvatarAdded != null && trackedAvatar.ListViewItem.Text == "(Loading...)")
177 {
178 try { OnAvatarAdded(trackedAvatar); }
179 catch (Exception ex) { Logger.Log(ex.Message, Helpers.LogLevel.Error, Client, ex); }
180 }
181  
182 this.BeginInvoke((MethodInvoker)delegate
183 {
184 trackedAvatar.ListViewItem.Text = name.Value;
185 });
186 }
187 }
188 }
189 }
190  
191 void Grid_CoarseLocationUpdate(object sender, CoarseLocationUpdateEventArgs e)
192 {
193 UpdateCoarseInfo(e.Simulator, e.NewEntries, e.RemovedEntries);
194 }
195  
196 private void AddAvatar(UUID avatarID, Avatar avatar, Vector3 coarsePosition)
197 {
198 if (!this.IsHandleCreated) return;
199  
200 if (this.InvokeRequired) this.BeginInvoke((MethodInvoker)delegate { AddAvatar(avatar.ID, avatar, coarsePosition); });
201 else
202 {
203 TrackedAvatar trackedAvatar = new TrackedAvatar();
204 trackedAvatar.CoarseLocation = coarsePosition;
205 trackedAvatar.ID = avatarID;
206 trackedAvatar.ListViewItem = this.Items.Add(avatarID.ToString(), trackedAvatar.Name, null);
207 trackedAvatar.ListViewItem.Name = avatarID.ToString();
208  
209 string strDist = avatarID == _Client.Self.AgentID ? "--" : (int)Vector3.Distance(_Client.Self.SimPosition, coarsePosition) + "m";
210 trackedAvatar.ListViewItem.SubItems.Add(strDist);
211  
212 if (avatar != null)
213 {
214 trackedAvatar.Name = avatar.Name;
215 trackedAvatar.ListViewItem.Text = avatar.Name;
216  
217 lock (_TrackedAvatars)
218 {
219 if (_TrackedAvatars.ContainsKey(avatarID))
220 _TrackedAvatars.Remove(avatarID);
221  
222 _TrackedAvatars.Add(avatar.LocalID, avatarID, trackedAvatar);
223 }
224  
225 if (OnAvatarAdded != null)
226 {
227 try { OnAvatarAdded(trackedAvatar); }
228 catch (Exception ex) { Logger.Log(ex.Message, Helpers.LogLevel.Error, Client, ex); }
229 }
230 }
231 else
232 {
233 lock (_UntrackedAvatars)
234 {
235 _UntrackedAvatars.Add(avatarID, trackedAvatar);
236  
237 trackedAvatar.ListViewItem.ForeColor = Color.FromKnownColor(KnownColor.GrayText);
238  
239 if (avatarID == _Client.Self.AgentID)
240 {
241 trackedAvatar.Name = _Client.Self.Name;
242 trackedAvatar.ListViewItem.Text = _Client.Self.Name;
243 }
244  
245 else if (_Client.Network.Connected)
246 Client.Avatars.RequestAvatarName(avatarID);
247 }
248 }
249  
250 }
251 }
252  
253 private void RemoveAvatar(UUID id)
254 {
255 if (!this.IsHandleCreated) return;
256  
257 if (this.InvokeRequired) this.BeginInvoke((MethodInvoker)delegate { RemoveAvatar(id); });
258 else
259 {
260 TrackedAvatar trackedAvatar;
261  
262 lock (_TrackedAvatars)
263 {
264 if (_TrackedAvatars.TryGetValue(id, out trackedAvatar))
265 {
266 this.Items.Remove(trackedAvatar.ListViewItem);
267 _TrackedAvatars.Remove(id);
268 }
269 }
270  
271 lock (_UntrackedAvatars)
272 {
273 if (_UntrackedAvatars.TryGetValue(id, out trackedAvatar))
274 {
275 this.Items.Remove(trackedAvatar.ListViewItem);
276 _UntrackedAvatars.Remove(trackedAvatar.ID);
277 }
278 }
279  
280 if (OnAvatarRemoved != null)
281 {
282 try { OnAvatarRemoved(trackedAvatar); }
283 catch (Exception ex) { Logger.Log(ex.Message, Helpers.LogLevel.Error, Client, ex); }
284 }
285 }
286 }
287  
288 private void UpdateAvatar(Avatar avatar)
289 {
290 if (!this.IsHandleCreated) return;
291  
292 if (this.InvokeRequired) this.BeginInvoke((MethodInvoker)delegate { UpdateAvatar(avatar); });
293 else
294 {
295 TrackedAvatar trackedAvatar;
296 bool found;
297  
298 lock (_UntrackedAvatars)
299 found = _UntrackedAvatars.TryGetValue(avatar.ID, out trackedAvatar);
300  
301 if (found)
302 {
303 trackedAvatar.Name = avatar.Name;
304 trackedAvatar.ListViewItem.Text = avatar.Name;
305 trackedAvatar.ListViewItem.ForeColor = Color.FromKnownColor(KnownColor.ControlText);
306  
307 lock (_TrackedAvatars) _TrackedAvatars.Add(avatar.LocalID, avatar.ID, trackedAvatar);
308 _UntrackedAvatars.Remove(avatar.ID);
309 }
310  
311 lock (_TrackedAvatars)
312 found = _TrackedAvatars.TryGetValue(avatar.ID, out trackedAvatar);
313  
314 if (found)
315 {
316 trackedAvatar.Avatar = avatar;
317 trackedAvatar.Name = avatar.Name;
318 trackedAvatar.ID = avatar.ID;
319  
320 string strDist = avatar.ID == _Client.Self.AgentID ? "--" : (int)Vector3.Distance(_Client.Self.SimPosition, avatar.Position) + "m";
321 trackedAvatar.ListViewItem.SubItems[1].Text = strDist;
322 }
323 else
324 {
325 AddAvatar(avatar.ID, avatar, Vector3.Zero);
326 }
327  
328 this.Sort();
329 }
330 }
331  
332 private void UpdateCoarseInfo(Simulator sim, List<UUID> newEntries, List<UUID> removedEntries)
333 {
334 if (this.InvokeRequired) this.BeginInvoke((MethodInvoker)delegate { UpdateCoarseInfo(sim, newEntries, removedEntries); });
335 else
336 {
337 if (sim == null) return;
338  
339 if (removedEntries != null)
340 {
341 for (int i = 0; i < removedEntries.Count; i++)
342 RemoveAvatar(removedEntries[i]);
343 }
344  
345 if (newEntries != null)
346 {
347 for (int i = 0; i < newEntries.Count; i++)
348 {
349 int index = this.Items.IndexOfKey(newEntries[i].ToString());
350 if (index == -1)
351 {
352 Vector3 coarsePos;
353 if (!sim.AvatarPositions.TryGetValue(newEntries[i], out coarsePos))
354 continue;
355  
356 AddAvatar(newEntries[i], null, coarsePos);
357 }
358 }
359 }
360 }
361 }
362  
363 private void defaultMenuItem_Click(object sender, EventArgs e)
364 {
365 MenuItem menuItem = (MenuItem)sender;
366  
367 switch (menuItem.Text)
368 {
369 case "Offer Teleport":
370 {
371 Client.Self.SendTeleportLure(_SelectedAvatar.ID);
372 break;
373 }
374 case "Teleport To":
375 {
376 Vector3 pos;
377 if (Client.Network.CurrentSim.AvatarPositions.TryGetValue(_SelectedAvatar.ID, out pos))
378 Client.Self.Teleport(Client.Network.CurrentSim.Name, pos);
379  
380 break;
381 }
382 case "Walk To":
383 {
384 Vector3 pos;
385 if (Client.Network.CurrentSim.AvatarPositions.TryGetValue(_SelectedAvatar.ID, out pos))
386 Client.Self.AutoPilotLocal((int)pos.X, (int)pos.Y, pos.Z);
387  
388 break;
389 }
390 }
391 }
392  
393 void AvatarList_ColumnClick(object sender, ColumnClickEventArgs e)
394 {
395 _ColumnSorter.SortColumn = e.Column;
396 if ((_ColumnSorter.Ascending = (this.Sorting == SortOrder.Ascending))) this.Sorting = SortOrder.Descending;
397 else this.Sorting = SortOrder.Ascending;
398 this.ListViewItemSorter = _ColumnSorter;
399 }
400  
401 void AvatarList_DoubleClick(object sender, EventArgs e)
402 {
403 if (OnAvatarDoubleClick != null)
404 {
405 ListView list = (ListView)sender;
406 if (list.SelectedItems.Count > 0)
407 {
408 TrackedAvatar trackedAvatar;
409 if (!_TrackedAvatars.TryGetValue(new UUID(list.SelectedItems[0].Name), out trackedAvatar)
410 && !_UntrackedAvatars.TryGetValue(new UUID(list.SelectedItems[0].Name), out trackedAvatar))
411 return;
412  
413 try { OnAvatarDoubleClick(trackedAvatar); }
414 catch (Exception ex) { Logger.Log(ex.Message, Helpers.LogLevel.Error, Client, ex); }
415 }
416 }
417 }
418  
419 void Avatars_OnAvatarAppearance(object sender, AvatarAppearanceEventArgs e)
420 {
421 if (e.VisualParams.Count > 31)
422 {
423 TrackedAvatar trackedAvatar;
424 bool foundAvatar;
425  
426 lock (_TrackedAvatars)
427 foundAvatar = _TrackedAvatars.TryGetValue(e.AvatarID, out trackedAvatar);
428  
429 if (foundAvatar)
430 {
431 this.BeginInvoke((MethodInvoker)delegate
432 {
433 byte param = e.VisualParams[31];
434 if (param > 0)
435 trackedAvatar.ListViewItem.ForeColor = Color.Blue;
436 else
437 trackedAvatar.ListViewItem.ForeColor = Color.Magenta;
438 });
439 }
440 }
441 }
442  
443  
444  
445 void Network_OnCurrentSimChanged(object sender, SimChangedEventArgs e)
446 {
447 lock (_TrackedAvatars)
448 _TrackedAvatars.Clear();
449  
450 lock (_UntrackedAvatars)
451 _UntrackedAvatars.Clear();
452  
453 ClearItems();
454 }
455  
456 void Objects_OnNewAvatar(object sender, AvatarUpdateEventArgs e)
457 {
458 UpdateAvatar(e.Avatar);
459 }
460  
461 void Objects_OnObjectUpdated(object sender, TerseObjectUpdateEventArgs e)
462 {
463 bool found;
464 lock (_TrackedAvatars)
465 found = _TrackedAvatars.ContainsKey(e.Update.LocalID);
466  
467 if (found)
468 {
469 Avatar av;
470 if (e.Simulator.ObjectsAvatars.TryGetValue(e.Update.LocalID, out av))
471 UpdateAvatar(av);
472 }
473 }
474  
475 }
476  
477 /// <summary>
478 /// Contains any available information for an avatar in the simulator.
479 /// A null value for .Avatar indicates coarse data for an avatar outside of visible range.
480 /// </summary>
481 public class TrackedAvatar
482 {
483 /// <summary>Assigned if the avatar is within visible range</summary>
484 public Avatar Avatar = null;
485  
486 /// <summary>Last known coarse location of avatar</summary>
487 public Vector3 CoarseLocation;
488  
489 /// <summary>Avatar ID</summary>
490 public UUID ID;
491  
492 /// <summary>ListViewItem associated with this avatar</summary>
493 public ListViewItem ListViewItem;
494  
495 /// <summary>Populated by RequestAvatarName if avatar is not visible</summary>
496 public string Name = "(Loading...)";
497 }
498  
499 }