~ken-vandine/ubuntu/precise/folks/precise

« back to all changes in this revision

Viewing changes to folks/individual.vala

  • Committer: Bazaar Package Importer
  • Author(s): Robert Ancell
  • Date: 2010-11-26 14:12:44 UTC
  • mfrom: (1.2.4 upstream) (4.1.5 experimental)
  • Revision ID: james.westby@ubuntu.com-20101126141244-0r97g01y2npcalc8
Tags: 0.3.2-1ubuntu1
* Merge with Debian experimental, remaining Ubuntu changes:
* debian/control:
  - Build-depend on dh-autoreconf
  - Bump build-depends on valac-0.12, libvala-0.12-dev
  - Add Vcs-Bzr link
* debian/rules:
  - Build with autoreconf
* debian/patches/00git_no_gettext.patch:
  - Don't use IT_PROG_INTLTOOL and AM_GNU_GETTEXT
* debian/patches/01_tests_ldflags.patch:
  - Link telepathy tests to GIO

Show diffs side-by-side

added added

removed removed

Lines of Context:
20
20
 
21
21
using Gee;
22
22
using GLib;
23
 
using Folks;
24
23
 
25
24
/**
26
25
 * Trust level for an {@link Individual} for use in the UI.
64
63
 * might have, such as their different IM addresses or vCard entries.
65
64
 */
66
65
public class Folks.Individual : Object,
67
 
    Alias,
 
66
    Aliasable,
68
67
    Avatar,
69
68
    Favourite,
70
 
    Groups,
 
69
    Groupable,
 
70
    IMable,
71
71
    Presence
72
72
{
73
73
  private bool _is_favourite;
85
85
   * in this Individual. There shouldn't be any entries with a number < 1.
86
86
   * This is used for working out when to disconnect from store signals. */
87
87
  private HashMap<PersonaStore, uint> stores;
 
88
  /* The number of Personas in this Individual which have
 
89
   * Persona.is_user == true. Iff this is > 0, Individual.is_user == true. */
 
90
  private uint persona_user_count = 0;
 
91
  private HashTable<string, GenericArray<string>> _im_addresses;
88
92
 
89
93
  /**
90
94
   * The trust level of the Individual.
115
119
  public string presence_message { get; private set; }
116
120
 
117
121
  /**
 
122
   * Whether the Individual is the user.
 
123
   *
 
124
   * Iff the Individual represents the user – the person who owns the
 
125
   * account in the backend for each {@link Persona} in the Individual –
 
126
   * this is `true`.
 
127
   *
 
128
   * It is //not// guaranteed that every {@link Persona} in the Individual has
 
129
   * its {@link Persona.is_user} set to the same value as the Individual. For
 
130
   * example, the user could own two Telepathy accounts, and have added the
 
131
   * other account as a contact in each account. The accounts will expose a
 
132
   * {@link Persona} for the user (which will have {@link Persona.is_user} set
 
133
   * to `true`) //and// a {@link Persona} for the contact for the other account
 
134
   * (which will have {@link Persona.is_user} set to `false`).
 
135
   *
 
136
   * It is guaranteed that iff this property is set to `true` on an Individual,
 
137
   * there will be at least one {@link Persona} in the Individual with its
 
138
   * {@link Persona.is_user} set to `true`.
 
139
   *
 
140
   * It is guaranteed that there will only ever be one Individual with this
 
141
   * property set to `true`.
 
142
   *
 
143
   * @since 0.3.0
 
144
   */
 
145
  public bool is_user { get; private set; }
 
146
 
 
147
  /**
118
148
   * A unique identifier for the Individual.
119
149
   *
120
150
   * This uniquely identifies the Individual, and persists across
133
163
   *
134
164
   * @param replacement_individual the individual which has replaced this one
135
165
   * due to linking, or `null` if this individual was removed for another reason
 
166
   * @since 0.1.13
136
167
   */
137
168
  public signal void removed (Individual? replacement_individual);
138
169
 
156
187
          bool alias_changed = false;
157
188
          this._persona_list.foreach ((p) =>
158
189
            {
159
 
              if (p is Alias && ((Persona) p).store.is_writeable == true)
 
190
              if (p is Aliasable && ((Persona) p).store.is_writeable == true)
160
191
                {
161
192
                  debug ("    written to writeable persona '%s'",
162
193
                      ((Persona) p).uid);
163
 
                  ((Alias) p).alias = value;
 
194
                  ((Aliasable) p).alias = value;
164
195
                  alias_changed = true;
165
196
                }
166
197
            });
171
202
            {
172
203
              this._persona_list.foreach ((p) =>
173
204
                {
174
 
                  if (p is Alias)
 
205
                  if (p is Aliasable)
175
206
                    {
176
207
                      debug ("    written to non-writeable persona '%s'",
177
208
                          ((Persona) p).uid);
178
 
                      ((Alias) p).alias = value;
 
209
                      ((Aliasable) p).alias = value;
179
210
                    }
180
211
                });
181
212
            }
227
258
          this._groups = value;
228
259
          this._persona_list.foreach ((p) =>
229
260
            {
230
 
              if (p is Groups && ((Persona) p).store.is_writeable == true)
231
 
                ((Groups) p).groups = value;
 
261
              if (p is Groupable && ((Persona) p).store.is_writeable == true)
 
262
                ((Groupable) p).groups = value;
232
263
            });
233
264
        }
234
265
    }
235
266
 
236
267
  /**
 
268
   * {@inheritDoc}
 
269
   */
 
270
  public HashTable<string, GenericArray<string>> im_addresses
 
271
    {
 
272
      get { return this._im_addresses; }
 
273
      private set {}
 
274
    }
 
275
 
 
276
  /**
237
277
   * The set of {@link Persona}s encapsulated by this Individual.
238
278
   *
239
279
   * Changing the set of personas may cause updates to the aggregated properties
289
329
   *
290
330
   * @param group a freeform group identifier
291
331
   * @param is_member whether the Individual should be a member of the group
 
332
   * @since 0.1.11
292
333
   */
293
334
  public async void change_group (string group, bool is_member)
294
335
    {
295
336
      this._persona_list.foreach ((p) =>
296
337
        {
297
 
          if (p is Groups)
298
 
            ((Groups) p).change_group.begin (group, is_member);
 
338
          if (p is Groupable)
 
339
            ((Groupable) p).change_group.begin (group, is_member);
299
340
        });
300
341
 
301
342
      /* don't notify, since it hasn't happened in the persona backing stores
307
348
      this.update_presence ();
308
349
    }
309
350
 
 
351
  private void notify_im_addresses_cb (Object obj, ParamSpec ps)
 
352
    {
 
353
      this.update_im_addresses ();
 
354
    }
 
355
 
310
356
  private void notify_is_favourite_cb (Object obj, ParamSpec ps)
311
357
    {
312
358
      this.update_is_favourite ();
319
365
   * `personas`. Otherwise, it will have to have personas added using the
320
366
   * {@link Folks.Individual.personas} property after construction.
321
367
   *
 
368
   * @param personas a list of {@link Persona}s to initialise the
 
369
   * {@link Individual} with, or `null`
322
370
   * @return a new Individual
323
371
   */
324
372
  public Individual (GLib.List<Persona>? personas)
325
373
    {
 
374
      this._im_addresses =
 
375
          new HashTable<string, GenericArray<string>> (str_hash, str_equal);
326
376
      this._persona_set = new HashSet<Persona> (null, null);
327
377
      this.stores = new HashMap<PersonaStore, uint> (null, null);
328
378
      this.personas = personas;
361
411
      GLib.List<Persona>? removed,
362
412
      string? message,
363
413
      Persona? actor,
364
 
      Groups.ChangeReason reason)
 
414
      Groupable.ChangeReason reason)
365
415
    {
366
416
      GLib.List<Persona> removed_personas = null;
367
417
      removed.foreach ((data) =>
395
445
      this.update_avatar ();
396
446
      this.update_alias ();
397
447
      this.update_trust_level ();
 
448
      this.update_im_addresses ();
398
449
    }
399
450
 
400
451
  private void update_groups ()
412
463
       * groups channel list) */
413
464
      this._persona_list.foreach ((p) =>
414
465
        {
415
 
          if (p is Groups)
 
466
          if (p is Groupable)
416
467
            {
417
 
              unowned Groups persona = (Groups) p;
 
468
              unowned Groupable persona = (Groupable) p;
418
469
 
419
470
              persona.groups.foreach ((k, v) =>
420
471
                {
525
576
       * stored. */
526
577
      foreach (Persona p in this._persona_list)
527
578
        {
528
 
          if (p is Alias && p.store.is_writeable == true)
 
579
          if (p is Aliasable && p.store.is_writeable == true)
529
580
            {
530
 
              unowned Alias a = (Alias) p;
 
581
              unowned Aliasable a = (Aliasable) p;
531
582
 
532
583
              if (a.alias != null && a.alias.strip () != "")
533
584
                {
547
598
        {
548
599
          foreach (Persona p in this._persona_list)
549
600
            {
550
 
              if (p is Alias)
 
601
              if (p is Aliasable)
551
602
                {
552
 
                  unowned Alias a = (Alias) p;
 
603
                  unowned Aliasable a = (Aliasable) p;
553
604
 
554
605
                  if (a.alias == null || a.alias.strip () == "")
555
606
                    continue;
621
672
 
622
673
      foreach (Persona p in this._persona_list)
623
674
        {
624
 
          if (p.store.trust_level == PersonaStoreTrust.NONE)
 
675
          if (p.is_user == false &&
 
676
              p.store.trust_level == PersonaStoreTrust.NONE)
625
677
            trust_level = TrustLevel.NONE;
626
678
        }
627
679
 
630
682
        this.trust_level = trust_level;
631
683
    }
632
684
 
633
 
  /*
634
 
   * GLib/C convenience functions (for built-in casting, etc.)
635
 
   */
636
 
 
637
 
  /**
638
 
   * Get the Individual's alias.
639
 
   *
640
 
   * The alias is a user-chosen name for the Individual; how the user wants that
641
 
   * Individual to be represented in UIs.
642
 
   *
643
 
   * @return the Individual's alias
644
 
   */
645
 
  public unowned string get_alias ()
646
 
    {
647
 
      return this.alias;
648
 
    }
649
 
 
650
 
  /**
651
 
   * Get a mapping of group ID to whether the Individual is a member.
652
 
   *
653
 
   * Freeform group IDs are mapped to a boolean which is `true` if the
654
 
   * Individual is a member of the group, and `false` otherwise.
655
 
   *
656
 
   * @return a mapping of group ID to membership status
657
 
   */
658
 
  public HashTable<string, bool> get_groups ()
659
 
    {
660
 
      Groups g = this;
661
 
      return g.groups;
662
 
    }
663
 
 
664
 
  /**
665
 
   * Get the Individual's current presence message.
666
 
   *
667
 
   * The presence message returned is from the same {@link Persona} which
668
 
   * provided the presence type returned by
669
 
   * {@link Individual.get_presence_type}.
670
 
   *
671
 
   * If none of the {@link Persona}s in the Individual have a presence message
672
 
   * set, an empty string is returned.
673
 
   *
674
 
   * @return the Individual's presence message
675
 
   */
676
 
  public unowned string get_presence_message ()
677
 
    {
678
 
      return this.presence_message;
679
 
    }
680
 
 
681
 
  /**
682
 
   * Get the Individual's current presence type.
683
 
   *
684
 
   * The presence type returned is from the same {@link Persona} which provided
685
 
   * the presence message returned by {@link Individual.get_presence_message}.
686
 
   *
687
 
   * If none of the {@link Persona}s in the Individual have a presence type set,
688
 
   * {@link PresenceType.UNSET} is returned.
689
 
   *
690
 
   * @return the Individual's presence type
691
 
   */
692
 
  public Folks.PresenceType get_presence_type ()
693
 
    {
694
 
      return this.presence_type;
695
 
    }
696
 
 
697
 
  /**
698
 
   * Whether the Individual is online.
699
 
   *
700
 
   * This will be `true` if any of the Individual's {@link Persona}s have a
701
 
   * presence type higher than {@link PresenceType.OFFLINE}, as determined by
702
 
   * {@link Presence.typecmp}.
703
 
   *
704
 
   * @return `true` if the Individual is online, `false` otherwise
705
 
   */
706
 
  public bool is_online ()
707
 
    {
708
 
      Presence p = this;
709
 
      return p.is_online ();
 
685
  private void update_im_addresses ()
 
686
    {
 
687
      /* populate the IM addresses as the union of our Personas' addresses */
 
688
      foreach (var persona in this.personas)
 
689
        {
 
690
          if (persona is IMable)
 
691
            {
 
692
              var imable = (IMable) persona;
 
693
              imable.im_addresses.foreach ((k, v) =>
 
694
                {
 
695
                  var cur_protocol = (string) k;
 
696
                  var cur_addresses = (GenericArray<string>) v;
 
697
                  var old_im_array = this._im_addresses.lookup (cur_protocol);
 
698
                  var im_array = new GenericArray<string> ();
 
699
 
 
700
                  /* use a set to eliminate duplicates */
 
701
                  var address_set = new HashSet<string> (str_hash, str_equal);
 
702
                  if (old_im_array != null)
 
703
                    {
 
704
                      old_im_array.foreach ((old_address) =>
 
705
                        {
 
706
                          address_set.add ((string) old_address);
 
707
                        });
 
708
                    }
 
709
                  cur_addresses.foreach ((cur_address) =>
 
710
                    {
 
711
                      address_set.add ((string) cur_address);
 
712
                    });
 
713
                  foreach (string addr in address_set)
 
714
                    im_array.add (addr);
 
715
 
 
716
                  this._im_addresses.insert (cur_protocol, im_array);
 
717
                });
 
718
            }
 
719
        }
 
720
      this.notify_property ("im-addresses");
710
721
    }
711
722
 
712
723
  private void connect_to_persona (Persona persona)
715
726
      persona.notify["avatar"].connect (this.notify_avatar_cb);
716
727
      persona.notify["presence-message"].connect (this.notify_presence_cb);
717
728
      persona.notify["presence-type"].connect (this.notify_presence_cb);
 
729
      persona.notify["im-addresses"].connect (this.notify_im_addresses_cb);
718
730
      persona.notify["is-favourite"].connect (this.notify_is_favourite_cb);
719
731
 
720
 
      if (persona is Groups)
 
732
      if (persona is Groupable)
721
733
        {
722
 
          ((Groups) persona).group_changed.connect (
 
734
          ((Groupable) persona).group_changed.connect (
723
735
              this.persona_group_changed_cb);
724
736
        }
725
737
    }
731
743
      persona.notify["presence-message"].disconnect (
732
744
          this.notify_presence_cb);
733
745
      persona.notify["presence-type"].disconnect (this.notify_presence_cb);
 
746
      persona.notify["im-addresses"].disconnect (
 
747
          this.notify_im_addresses_cb);
734
748
      persona.notify["is-favourite"].disconnect (
735
749
          this.notify_is_favourite_cb);
736
750
 
737
 
      if (persona is Groups)
 
751
      if (persona is Groupable)
738
752
        {
739
 
          ((Groups) persona).group_changed.disconnect (
 
753
          ((Groupable) persona).group_changed.disconnect (
740
754
              this.persona_group_changed_cb);
741
755
        }
742
756
    }
753
767
        {
754
768
          if (!this._persona_set.contains (p))
755
769
            {
 
770
              /* Keep track of how many Personas are users */
 
771
              if (p.is_user)
 
772
                this.persona_user_count++;
 
773
 
756
774
              added.prepend (p);
757
775
 
758
776
              this._persona_set.add (p);
783
801
        {
784
802
          if (!persona_set.contains (p))
785
803
            {
 
804
              /* Keep track of how many Personas are users */
 
805
              if (p.is_user)
 
806
                this.persona_user_count--;
 
807
 
786
808
              removed.prepend (p);
787
809
 
788
810
              /* Decrement the Persona count for this PersonaStore */
813
835
 
814
836
      this.personas_changed (added, removed);
815
837
 
 
838
      /* Update this.is_user */
 
839
      bool new_is_user = (this.persona_user_count > 0) ? true : false;
 
840
      if (new_is_user != this.is_user)
 
841
        this.is_user = new_is_user;
 
842
 
816
843
      /* If all the Personas have been removed, remove the Individual */
817
844
      if (this._persona_set.size < 1)
818
845
        {
819
846
          this.removed (replacement_individual);
820
 
            return;
 
847
          return;
821
848
        }
822
849
 
823
850
      /* TODO: Base this upon our ID in permanent storage, once we have that. */