[gnome-contacts/new-design: 6/6] Initial work on the new content-pane design
- From: Alexander Larsson <alexl src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gnome-contacts/new-design: 6/6] Initial work on the new content-pane design
- Date: Wed, 7 Dec 2011 21:01:08 +0000 (UTC)
commit 0c6a67d3096c74981f77f03ce10bce9aab1cf742
Author: Alexander Larsson <alexl redhat com>
Date: Wed Dec 7 21:59:27 2011 +0100
Initial work on the new content-pane design
src/contacts-contact-pane.vala | 1724 ++++++++++------------------------------
src/contacts-contact.vala | 4 +-
2 files changed, 425 insertions(+), 1303 deletions(-)
---
diff --git a/src/contacts-contact-pane.vala b/src/contacts-contact-pane.vala
index 0e18f2a..b8b2b9b 100644
--- a/src/contacts-contact-pane.vala
+++ b/src/contacts-contact-pane.vala
@@ -241,641 +241,8 @@ public class Contacts.ContactFrame : Frame {
}
}
-public class Contacts.PersonaButton : RadioButton {
- private Widget create_image (AvatarDetails? details, int size) {
- var image = new Image ();
- image.set_padding (2, 2);
-
- Gdk.Pixbuf pixbuf = null;
- if (details != null &&
- details.avatar != null) {
- try {
- var stream = details.avatar.load (size, null);
- pixbuf = new Gdk.Pixbuf.from_stream_at_scale (stream, size, size, true);
- }
- catch {
- }
- }
-
- if (pixbuf == null) {
- pixbuf = Contact.draw_fallback_avatar (size, null);
- }
-
- if (pixbuf != null) {
- image.set_from_pixbuf (Contact.frame_icon (pixbuf));
- }
-
- image.draw.connect ( (cr) => {
- if (this.get_active ()) {
- cr.save ();
- cr.set_source_rgba (0x74/255.0, 0xa0/255.0, 0xd0/255.0, 0.5);
- Utils.cairo_rounded_box (cr, 0, 0, size+4, size+4, 4+2);
- Utils.cairo_rounded_box (cr, 2, 2, size, size, 4);
- cr.set_fill_rule (Cairo.FillRule.EVEN_ODD);
- cr.fill ();
- cr.restore ();
- }
- return false;
- });
-
- return image;
- }
-
-
- public PersonaButton (RadioButton? group, AvatarDetails? avatar, int size) {
- if (group != null)
- join_group (group);
-
- get_style_context ().add_class ("contact-button");
- set_can_default (false);
- var image = create_image (avatar, size);
- add (image);
- set_mode (false);
- }
-}
-
-
-public class Contacts.ContactPane : Grid {
- // TODO: Remove later when bound in vala
- private static unowned string C_(string context, string msgid) {
- return GLib.dpgettext2 (Config.GETTEXT_PACKAGE, context, msgid);
- }
- private enum DisplayMode {
- INITIAL,
- EMPTY,
- DETAILS,
- NOTES,
- EDIT
- }
- private Store contacts_store;
- private Contact? selected_contact;
- private DisplayMode display_mode;
- private Grid card_grid;
- private Grid fields_grid;
- private Grid button_grid;
+public class Contacts.AvatarMenu : Menu {
private Gnome.DesktopThumbnailFactory thumbnail_factory;
- /* Stuff used only in edit mode */
- private ContactFrame edit_image_frame;
- private Grid edit_persona_grid;
- private Persona? editing_persona;
- private Persona? editing_persona_primary;
- private MenuItem delete_menu_item;
-
- private bool has_notes;
- private bool keep_has_notes_once;
- private Widget notes_dot;
- private Widget empty_widget;
- private EventBox pane;
- private ButtonBox normal_buttons;
- private ButtonBox editing_buttons;
- private DetailsLayout.SharedState layout_state;
- private DetailsLayout card_layout;
- private DetailsLayout fields_layout;
- private DetailsLayout button_layout;
-
- HashSet<EmailFieldDetails> editing_emails;
- HashSet<PhoneFieldDetails> editing_phones;
- HashSet<UrlFieldDetails> editing_urls;
- HashSet<PostalAddressFieldDetails> editing_postals;
-
- const int PROFILE_SIZE = 96;
- const int LABEL_HEIGHT = 20;
-
- private signal void save_data ();
-
- private async Persona? set_persona_property (Persona persona,
- string property_name,
- Value value) throws GLib.Error, PropertyError {
- selected_contact.is_unedited = false;
- if (persona is FakePersona) {
- var fake = persona as FakePersona;
- return yield fake.make_real_and_set (property_name, value);
- } else {
- persona.set_data ("contacts-unedited", true);
- yield Contact.set_persona_property (persona, property_name, value);
- return null;
- }
- }
-
- /* Tries to set the property on all persons that have it writeable, and
- * if none, creates a new persona and writes to it, returning the new
- * persona.
- */
- private async Persona? set_individual_property (Contact contact,
- string property_name,
- Value value) throws GLib.Error, PropertyError {
- selected_contact.is_unedited = false;
- bool did_set = false;
- // Need to make a copy here as it could change during the yields
- var personas_copy = contact.individual.personas.to_array ();
- foreach (var p in personas_copy) {
- if (property_name in p.writeable_properties) {
- did_set = true;
- yield Contact.set_persona_property (p, property_name, value);
- }
- }
-
- if (!did_set) {
- var fake = new FakePersona (contact);
- return yield fake.make_real_and_set (property_name, value);
- }
- return null;
- }
-
- private void update_property (string property_name,
- Value value) {
- var editing_backup = editing_persona;
- set_persona_property.begin (editing_persona, property_name, value, (obj, result) => {
- try {
- var p = set_persona_property.end (result);
- if (p != null &&
- display_mode == DisplayMode.EDIT &&
- editing_persona == editing_backup) {
- update_persona_buttons (selected_contact, p);
- editing_persona = p;
- editing_persona_primary = p;
- }
- } catch (PropertyError e1) {
- warning ("Unable to edit property '%s': %s", property_name, e1.message);
- } catch (Error e2) {
- warning ("Unable to create writeable persona: %s", e2.message);
- }
- });
- }
-
- private void update_string_property (string property_name,
- string string_value) {
- var value = Value (typeof (string));
- value.set_string (string_value);
- update_property (property_name, value);
- }
-
- private void update_detail_property (string property_name,
- Set<AbstractFieldDetails> detail_set) {
- var value = Value (detail_set.get_type ());
- value.set_object (detail_set);
- update_property (property_name, value);
- }
-
- private void update_edit_detail_type (Set<AbstractFieldDetails> detail_set,
- AbstractFieldDetails detail,
- TypeCombo combo,
- string property_name) {
- combo.update_details (detail);
- update_detail_property (property_name, detail_set);
- }
-
- private void add_detail_combo (DetailsLayout layout,
- TypeSet type_set,
- Set<AbstractFieldDetails> detail_set,
- AbstractFieldDetails detail,
- string property_name) {
- var combo = new TypeCombo (type_set);
- combo.set_halign (Align.FILL);
- combo.set_hexpand (false);
- combo.set_active (detail);
- layout.add_widget_label (combo);
-
- combo.changed.connect ( () => {
- update_edit_detail_type (detail_set, detail, combo, property_name);
- });
- }
-
- private void update_edit_detail_string_value (Set<AbstractFieldDetails<string>> detail_set,
- AbstractFieldDetails<string> detail,
- Entry entry,
- string property_name) {
- if (detail.value != entry.get_text ()) {
- detail.value = entry.get_text ();
-
- update_detail_property (property_name, detail_set);
- }
- }
-
- private Entry add_detail_entry (DetailsLayout layout,
- Set<AbstractFieldDetails> detail_set,
- AbstractFieldDetails<string> detail,
- string property_name,
- string? placeholder_text) {
- var entry = layout.add_entry (detail.value);
- if (placeholder_text != null)
- entry.set ("placeholder-text", placeholder_text);
-
- entry.focus_out_event.connect ( (ev) => {
- update_edit_detail_string_value (detail_set, detail, entry, property_name);
- return false;
- });
- return entry;
- }
-
- private void update_edit_detail_postal_value (Set<PostalAddressFieldDetails> detail_set,
- PostalAddressFieldDetails detail,
- Entry entry,
- string subproperty_name,
- string property_name) {
- string old_value;
- detail.value.get (subproperty_name, out old_value);
- if (old_value != entry.get_text ()) {
- var new_value = new PostalAddress (detail.value.po_box,
- detail.value.extension,
- detail.value.street,
- detail.value.locality,
- detail.value.region,
- detail.value.postal_code,
- detail.value.country,
- detail.value.address_format,
- detail.value.uid);
- new_value.set (subproperty_name, entry.get_text ());
- detail.value = new_value;
-
- update_detail_property (property_name, detail_set);
- }
- }
-
- private Entry add_detail_postal_entry (DetailsLayout layout,
- Set<PostalAddressFieldDetails> detail_set,
- PostalAddressFieldDetails detail,
- string subproperty_name,
- string property_name,
- string? placeholder_text) {
- string postal_part;
- detail.value.get (subproperty_name, out postal_part);
- var entry = layout.add_entry (postal_part);
- entry.get_style_context ().add_class ("contact-postal-entry");
- if (placeholder_text != null)
- entry.set ("placeholder-text", placeholder_text);
-
- entry.focus_out_event.connect ( (ev) => {
- update_edit_detail_postal_value (detail_set, detail, entry, subproperty_name, property_name);
- return false;
- });
-
- return entry;
- }
-
- private Button add_detail_remove (DetailsLayout layout,
- Set<AbstractFieldDetails> detail_set,
- AbstractFieldDetails detail,
- string property_name,
- bool at_top = true) {
- var remove_button = layout.add_remove (at_top);
- var row = layout.current_row;
-
- remove_button.clicked.connect ( () => {
- detail_set.remove (detail);
- update_detail_property (property_name, detail_set);
- row.destroy ();
- });
- return remove_button;
- }
-
- private Widget add_detail_editor (DetailsLayout layout,
- TypeSet type_set,
- Set<AbstractFieldDetails> detail_set,
- AbstractFieldDetails<string> detail,
- string property_name,
- string? placeholder_text) {
- detail_set.add (detail);
- add_detail_combo (layout, type_set, detail_set, detail, property_name);
- var main = add_detail_entry (layout, detail_set, detail, property_name, placeholder_text);
- add_detail_remove (layout, detail_set, detail, property_name);
-
- return main;
- }
-
- private Widget add_detail_editor_no_type (DetailsLayout layout,
- Set<AbstractFieldDetails> detail_set,
- AbstractFieldDetails<string> detail,
- string property_name,
- string? placeholder_text) {
- detail_set.add (detail);
- var main = add_detail_entry (layout, detail_set, detail, property_name, placeholder_text);
- add_detail_remove (layout, detail_set, detail, property_name, false);
-
- return main;
- }
-
- private Entry add_string_entry (DetailsLayout layout,
- string property_name,
- string value,
- string? placeholder_text) {
- var entry = layout.add_entry (value);
- entry.set_data ("original-text", value);
- if (placeholder_text != null)
- entry.set ("placeholder-text", placeholder_text);
-
- entry.focus_out_event.connect ( (ev) => {
- if (entry.get_data<string?> ("original-text") !=
- entry.get_text ()) {
- var s = entry.get_text ();
- entry.set_data ("original-text", s);
- update_string_property (property_name, s);
- }
- return false;
- });
- return entry;
- }
-
- private Button add_string_remove (DetailsLayout layout,
- string property_name,
- bool at_top = true) {
- var remove_button = layout.add_remove (at_top);
- var row = layout.current_row;
-
- remove_button.clicked.connect ( () => {
- update_string_property (property_name, "");
- row.destroy ();
- });
- return remove_button;
- }
-
- private Widget add_string_editor (DetailsLayout layout,
- string label,
- string property_name,
- string value,
- string? placeholder_text,
- bool add_remove = true) {
- layout.add_label (label);
- var main = add_string_entry (layout, property_name, value, placeholder_text);
- if (add_remove)
- add_string_remove (layout, property_name);
-
- return main;
- }
-
- private Widget add_nickname_editor (DetailsLayout layout,
- string nickname) {
- return add_string_editor (layout,
- _("Nickname"),
- "nickname",
- nickname,
- _("Enter nickname"));
- }
-
- private Widget add_alias_editor (DetailsLayout layout,
- string alias) {
- return add_string_editor (layout,
- _("Alias"),
- "alias",
- alias,
- _("Enter alias"),
- false);
- }
-
- private Widget add_email_editor (DetailsLayout layout,
- Set<AbstractFieldDetails> detail_set,
- EmailFieldDetails? email) {
- return add_detail_editor (layout,
- TypeSet.general,
- detail_set,
- email != null ? new EmailFieldDetails (email.value, email.parameters) : new EmailFieldDetails(""),
- "email-addresses",
- _("Enter email address"));
- }
-
- private Widget add_phone_editor (DetailsLayout layout,
- Set<AbstractFieldDetails> detail_set,
- PhoneFieldDetails? p) {
- return add_detail_editor (layout,
- TypeSet.phone,
- detail_set,
- p != null ? new PhoneFieldDetails (p.value, p.parameters) : new PhoneFieldDetails(""),
- "phone-numbers",
- _("Enter phone number"));
- }
-
- private Widget add_url_editor (DetailsLayout layout,
- Set<AbstractFieldDetails> detail_set,
- UrlFieldDetails? url) {
- layout.add_label (C_ ("url-link", "Link"));
- return add_detail_editor_no_type (layout,
- detail_set,
- url != null ? new UrlFieldDetails (url.value, url.parameters) : new UrlFieldDetails (""),
- "urls",
- _("Enter link"));
- }
-
- private Widget add_postal_editor (DetailsLayout layout,
- Set<PostalAddressFieldDetails> detail_set,
- PostalAddressFieldDetails detail) {
- string[] props = {"street", "extension", "locality", "region", "postal_code", "po_box", "country"};
- string[] nice = {_("Street"), _("Extension"), _("City"), _("State/Province"), _("Zip/Postal Code"), _("PO box"), _("Country")};
-
- detail_set.add (detail);
- add_detail_combo (layout, TypeSet.general, detail_set, detail, "postal-addresses");
-
- Widget main = null;
- layout.begin_detail_box ();
- for (int i = 0; i < props.length; i++) {
- var e = add_detail_postal_entry (layout,
- detail_set,
- detail,
- props[i],
- "postal-addresses",
- nice[i]);
- if (i == 0)
- main = e;
- }
- layout.end_detail_box ();
- var button = add_detail_remove (layout, detail_set, detail, "postal-addresses");
- button.set_valign (Align.START);
-
- return main;
- }
-
- private void update_edit_details (Persona persona, bool new_contact) {
- editing_persona = persona;
- fields_layout.reset ();
- button_layout.reset ();
-
- edit_image_frame.set_image (persona as AvatarDetails);
- edit_image_frame.set_text (Contact.format_persona_store_name (persona.store), LABEL_HEIGHT);
-
- editing_emails = new HashSet<EmailFieldDetails>();
- editing_phones = new HashSet<PhoneFieldDetails>();
- editing_urls = new HashSet<UrlFieldDetails>();
- editing_postals = new HashSet<PostalAddressFieldDetails>();
-
- var nick_layout = new DetailsLayout (layout_state);
- fields_grid.add (nick_layout.grid);
-
- var name_details = persona as NameDetails;
- if (name_details != null) {
- var nick = name_details.nickname;
- if (is_set (nick)) {
- add_nickname_editor (nick_layout, nick);
- }
- }
-
- var alias_layout = new DetailsLayout (layout_state);
- fields_grid.add (alias_layout.grid);
-
- var alias_details = persona as AliasDetails;
- if (alias_details != null) {
- var alias = alias_details.alias;
- if (is_set (alias)) {
- add_alias_editor (alias_layout, alias);
- }
- }
-
- var email_layout = new DetailsLayout (layout_state);
- fields_grid.add (email_layout.grid);
-
- var email_details = persona as EmailDetails;
- if (email_details != null) {
- var emails = Contact.sort_fields<EmailFieldDetails>(email_details.email_addresses);
- foreach (var email in emails) {
- add_email_editor (email_layout,
- editing_emails, email);
- }
- }
-
- if (new_contact)
- add_email_editor (email_layout,
- editing_emails, null);
-
- var im_layout = new DetailsLayout (layout_state);
- fields_grid.add (im_layout.grid);
-
- var im_details = persona as ImDetails;
- if (im_details != null) {
- var ims = im_details.im_addresses;
- var im_keys = ims.get_keys ();
- foreach (var protocol in im_keys) {
- foreach (var id in ims[protocol]) {
- var im_persona = selected_contact.find_im_persona (protocol, id.value);
- if (im_persona != null && im_persona != persona)
- continue;
- im_layout.add_label_detail (_("Chat"), protocol + "/" + id.value);
- }
- }
- }
-
- var phone_layout = new DetailsLayout (layout_state);
- fields_grid.add (phone_layout.grid);
-
- var phone_details = persona as PhoneDetails;
- if (phone_details != null) {
- var phone_numbers = Contact.sort_fields<PhoneFieldDetails>(phone_details.phone_numbers);
- foreach (var p in phone_numbers) {
- add_phone_editor (phone_layout,
- editing_phones, p);
- }
- }
-
- if (new_contact)
- add_phone_editor (phone_layout,
- editing_phones, null);
-
- var postal_layout = new DetailsLayout (layout_state);
- fields_grid.add (postal_layout.grid);
-
- var postal_details = persona as PostalAddressDetails;
- if (postal_details != null) {
- var postals = postal_details.postal_addresses;
- foreach (var _addr in postals) {
- add_postal_editor (postal_layout,
- editing_postals,
- new PostalAddressFieldDetails(_addr.value, _addr.parameters));
- }
- }
-
- var birthdate_layout = new DetailsLayout (layout_state);
- fields_grid.add (birthdate_layout.grid);
-
- var birthdate_details = persona as BirthdayDetails;
- if (birthdate_details != null) {
- /*DateTime? bday = birthdate_details.birthday;*/
- /* TODO: Implement GUI for this, needs a date picker widget (#657972)*/
- }
-
- var url_layout = new DetailsLayout (layout_state);
- fields_grid.add (url_layout.grid);
-
- var urls_details = persona as UrlDetails;
- if (urls_details != null) {
- var urls = urls_details.urls;
- foreach (var url_details in urls) {
- add_url_editor (url_layout,
- editing_urls,
- url_details);
- }
- }
-
- if (Contact.persona_has_writable_property (persona, "email-addresses") ||
- Contact.persona_has_writable_property (persona, "phone-numbers") ||
- Contact.persona_has_writable_property (persona, "postal-addresses") ||
- Contact.persona_has_writable_property (persona, "urls")) {
- button_layout.add_label ("");
- var menu_button = new MenuButton (_("Add detail"));
- menu_button.set_hexpand (false);
- menu_button.set_margin_top (12);
-
- var menu = new Menu ();
- if (Contact.persona_has_writable_property (persona, "email-addresses")) {
- Utils.add_menu_item (menu, _("Email")).activate.connect ( () => {
- var widget = add_email_editor (email_layout,
- editing_emails, null);
- widget.grab_focus ();
- email_layout.grid.show_all ();
- });
- }
- if (Contact.persona_has_writable_property (persona, "phone-numbers")) {
- Utils.add_menu_item (menu, _("Phone number")).activate.connect ( () => {
- var widget = add_phone_editor (phone_layout,
- editing_phones, null);
- widget.grab_focus ();
- phone_layout.grid.show_all ();
- });
- }
- if (Contact.persona_has_writable_property (persona, "postal-addresses")) {
- Utils.add_menu_item (menu, _("Postal Address")).activate.connect ( () => {
- var widget = add_postal_editor (postal_layout,
- editing_postals,
- new PostalAddressFieldDetails(new PostalAddress (null, null, null, null, null, null, null, null, null),
- null));
- widget.grab_focus ();
- postal_layout.grid.show_all ();
- });
- }
- if (Contact.persona_has_writable_property (persona, "urls")) {
- Utils.add_menu_item (menu, C_ ("url-link", "Link")).activate.connect ( () => {
- var widget = add_url_editor (url_layout,
- editing_urls,
- null);
- widget.grab_focus ();
- url_layout.grid.show_all ();
- });
- }
- MenuItem nick_menu_item = null;
- if (name_details != null &&
- Contact.persona_has_writable_property (persona, "nickname")) {
- nick_menu_item = Utils.add_menu_item (menu, _("Nickname"));
- nick_menu_item.activate.connect ( () => {
- var widget = add_nickname_editor (nick_layout, "");
- widget.grab_focus ();
- nick_layout.grid.show_all ();
- });
- }
-
- menu_button.popup.connect ( () => {
- if (nick_menu_item != null) {
- if (is_set (name_details.nickname))
- nick_menu_item.hide ();
- else
- nick_menu_item.show ();
- }
- });
-
- menu_button.set_menu (menu);
-
- button_layout.attach_detail (menu_button);
- }
-
- card_grid.show_all ();
- fields_grid.show_all ();
- button_grid.show_all ();
- }
private MenuItem? menu_item_for_pixbuf (Gdk.Pixbuf? pixbuf, Icon icon) {
if (pixbuf == null)
@@ -915,12 +282,10 @@ public class Contacts.ContactPane : Grid {
return null;
}
+ public signal void icon_set (Icon icon);
+
private void set_avatar_from_icon (Icon icon) {
- Value v = Value (icon.get_type ());
- v.set_object (icon);
- set_individual_property.begin (selected_contact,
- "avatar", v, () => {
- });
+ icon_set (icon);
}
private void pick_avatar_cb (MenuItem menu) {
@@ -994,10 +359,10 @@ public class Contacts.ContactPane : Grid {
chooser.present ();
}
- private Menu avatar_menu (Contact contact) {
- var menu = new Menu ();
+ public AvatarMenu (Contact contact) {
+ thumbnail_factory = new Gnome.DesktopThumbnailFactory (Gnome.ThumbnailSize.NORMAL);
- menu.get_style_context ().add_class ("contact-frame-menu");
+ this.get_style_context ().add_class ("contact-frame-menu");
int x = 0;
int y = 0;
@@ -1006,7 +371,7 @@ public class Contacts.ContactPane : Grid {
foreach (var p in contact.individual.personas) {
var menuitem = menu_item_for_persona (p);
if (menuitem != null) {
- menu.attach (menuitem,
+ this.attach (menuitem,
x, x + 1, y, y + 1);
menuitem.show ();
menuitem.activate.connect (pick_avatar_cb);
@@ -1031,7 +396,7 @@ public class Contacts.ContactPane : Grid {
while ((face = dir.read_name ()) != null) {
var filename = Path.build_filename (path, face);
var menuitem = menu_item_for_filename (filename);
- menu.attach (menuitem,
+ this.attach (menuitem,
x, x + 1, y, y + 1);
menuitem.show ();
menuitem.activate.connect (pick_avatar_cb);
@@ -1044,764 +409,521 @@ public class Contacts.ContactPane : Grid {
}
};
- Utils.add_menu_item (menu,_("Browse for more pictures...")).activate.connect (select_avatar_file_cb);
-
- return menu;
+ Utils.add_menu_item (this,_("Browse for more pictures...")).activate.connect (select_avatar_file_cb);
}
+}
- private void display_card (Contact contact) {
- var menu = avatar_menu (contact);
+public class Contacts.ContactRow : Grid {
+ public Alignment left;
+ public Grid content;
+ public Alignment right;
+ int start;
- var image_frame = new ContactFrame (PROFILE_SIZE, menu);
- image_frame.set_image (contact.individual, contact);
- // Put the frame in a grid so its not expanded by the size-group
- var ig = new Grid ();
- ig.add (image_frame);
- card_layout.add_widget_label (ig);
+ public ContactRow (ContactPane pane) {
+ this.set_orientation (Orientation.HORIZONTAL);
+ this.set_column_spacing (8);
- card_layout.current_row.set_vexpand (false);
- var g = new Grid();
- card_layout.current_row.add (g);
+ this.set_hexpand (true);
+ this.set_vexpand (false);
- var l = new Label (null);
- l.set_markup ("<span font='24px'>" + contact.display_name + "</span>");
- l.set_hexpand (true);
- l.set_halign (Align.START);
- l.set_valign (Align.START);
- l.set_margin_top (4);
- l.set_ellipsize (Pango.EllipsizeMode.END);
- l.xalign = 0.0f;
- g.attach (l, 0, 0, 1, 1);
-
- var secondary = contact.get_secondary_string ();
- if (secondary != null) {
- l = new Label (null);
- l.set_markup ("<span font='12px' rise='1000'>"+secondary+"</span>");
- l.set_halign (Align.START);
- l.set_valign (Align.START);
- l.set_ellipsize (Pango.EllipsizeMode.END);
- l.xalign = 0.0f;
- g.attach (l, 0, 1, 1, 1);
- }
+ left = new Alignment (1,0,0,0);
+ left.set_hexpand (true);
+ pane.border_size_group.add_widget (left);
- var merged_presence = contact.create_merged_presence_widget ();
- merged_presence.set_halign (Align.START);
- merged_presence.set_valign (Align.END);
- merged_presence.set_vexpand (true);
- merged_presence.set_margin_bottom (18);
- g.attach (merged_presence, 0, 3, 1, 1);
- }
+ content = new Grid ();
+ content.set_size_request (450, -1);
- private void save_notes (Gee.HashMultiMap<Persona?,TextView> widgets) {
- // Update notes on all personas if one of the textviews for that persona changed
- // Also note that the individual might not have a persona on the main store, so
- // it would need to add one and link the individual into it
-
- foreach (var persona in widgets.get_keys ()) {
- bool modified = false;
- bool empty = true;
-
- var notes = new HashSet<NoteFieldDetails> ();
- foreach (var view in widgets.get (persona)) {
- if (view.get_buffer ().get_modified ())
- modified = true;
- string? uid = view.get_data<string?> ("uid");
- TextIter start, end;
- view.get_buffer ().get_start_iter (out start);
- view.get_buffer ().get_end_iter (out end);
- var text = view.get_buffer ().get_text (start, end, true);
- if (is_set (text)) {
- var note = new NoteFieldDetails (text, null, uid);
- notes.add (note);
- empty = false;
- }
- }
+ right = new Alignment (0,0,0,0);
+ right.set_hexpand (true);
+ pane.border_size_group.add_widget (right);
- if (modified) {
- var value = Value(notes.get_type ());
- value.set_object (notes);
- set_persona_property.begin (persona, "notes", value, (obj, result) => {
- try {
- set_persona_property.end (result);
- } catch (PropertyError e1) {
- warning ("Unable to save note: %s", e1.message);
- } catch (Error e2) {
- warning ("Unable to save note: %s", e2.message);
- }
- });
- // We fake has_notes content for this display_contact() run, to avoid
- // the wait for the async property setter
- keep_has_notes_once = true;
- has_notes = !empty;
- }
- }
+ this.attach (left, 0, 0, 1, 1);
+ this.attach (content, 1, 0, 1, 1);
+ this.attach (right, 2, 0, 1, 1);
+ this.show_all ();
}
- private TextView add_note () {
- var text = new TextView ();
- text.set_hexpand (true);
- text.set_vexpand (true);
- var scrolled = new ScrolledWindow (null, null);
- scrolled.set_shadow_type (ShadowType.OUT);
- scrolled.add_with_viewport (text);
- fields_grid.add (scrolled);
- return text;
+ public void pack_start (Widget w, Align align = Align.START) {
+ content.attach (w, 0, start++, 1, 1);
+ w.set_hexpand (true);
+ w.set_halign (align);
}
- private void update_note (TextView text, NoteFieldDetails note) {
- text.get_buffer ().set_text (note.value);
- text.get_buffer ().set_modified (false);
- text.set_data<string?> ("uid", note.uid);
+ public void pack_end (Widget w) {
+ content.attach (w, 1, 0, 1, 1);
+ w.set_hexpand (false);
+ w.set_halign (Align.END);
}
- private void display_notes () {
- set_display_mode (DisplayMode.NOTES);
- display_card (selected_contact);
-
- var widgets = new HashMultiMap<Persona?, TextView>();
- var main_text = add_note ();
-
- // We store the main note on the primay persona if any, otherwise
- // on the first persona with a writable notes, falling back to
- // a FakePersona that creates a primary persona as needed
- Persona? notes_persona = selected_contact.find_primary_persona ();
- if (notes_persona == null) {
- foreach (var persona in selected_contact.individual.personas) {
- if (Contact.persona_has_writable_property (persona, "notes")) {
- notes_persona = persona;
- break;
- }
- }
- if (notes_persona == null)
- notes_persona = new FakePersona (selected_contact);
- }
+ public void label (string s) {
+ var l = new Label (s);
+ l.get_style_context ().add_class ("dim-label");
+ pack_start (l);
+ }
- widgets.set (notes_persona, main_text);
-
- bool notes_persona_note_seen = false;
-
- foreach (var persona in selected_contact.individual.personas) {
- var notes = persona as NoteDetails;
- if (notes == null)
- continue;
- foreach (var note in notes.notes) {
- if (persona == notes_persona && !notes_persona_note_seen) {
- notes_persona_note_seen = true;
- update_note (main_text, note);
- } else if (Contact.persona_has_writable_property (persona, "notes")) {
- var text = add_note ();
- update_note (text, note);
- widgets.set (persona, text);
- } else {
- var label = new Label (note.value);
- label.set_halign (Align.START);
- fields_grid.add (label);
- }
- }
+ public void text (string s, bool wrap = false) {
+ var l = new Label (s);
+ if (wrap) {
+ l.set_line_wrap (true);
+ l.set_line_wrap_mode (Pango.WrapMode.WORD_CHAR);
+ } else {
+ l.set_ellipsize (Pango.EllipsizeMode.END);
}
+ pack_start (l);
+ }
- card_grid.show_all ();
- fields_grid.show_all ();
-
- ulong id = 0;
- id = this.save_data.connect ( () => {
- save_notes (widgets);
- this.disconnect (id);
- });
+ public void detail (string s) {
+ var l = new Label (s);
+ l.get_style_context ().add_class ("dim-label");
+ pack_end (l);
}
+}
- private Persona update_persona_buttons (Contact contact,
- Persona? _persona) {
- Persona? persona = _persona;
+public class Contacts.PersonaSheet : Grid {
+ ContactPane pane;
+ Persona persona;
+ ContactRow header;
+ ContactRow footer;
- foreach (var w in edit_persona_grid.get_children ()) {
- w.destroy ();
- }
+ abstract class Field : Grid {
+ public class string label_name;
- var persona_list = new ArrayList<Persona>();
- int i = 0;
- persona_list.add_all (contact.individual.personas);
- while (i < persona_list.size) {
- if (persona_list[i].store.type_id == "key-file")
- persona_list.remove_at (i);
- else
- i++;
- }
- var fake_persona = FakePersona.maybe_create_for (contact);
- if (fake_persona != null)
- persona_list.add (fake_persona);
- persona_list.sort (Contact.compare_persona_by_store);
-
- foreach (var p in persona_list) {
- if (p.store.is_primary_store) {
- editing_persona_primary = p;
- }
- }
+ public PersonaSheet sheet { get; construct; }
+ public int row_nr { get; construct; }
+ public bool added;
+ ContactRow label_row;
- if (persona == null)
- persona = persona_list[0];
+ public abstract void populate ();
- PersonaButton button = null;
- if (persona_list.size > 1) {
- foreach (var p in persona_list) {
+ construct {
+ this.set_orientation (Orientation.VERTICAL);
- button = new PersonaButton (button, p as AvatarDetails, 48);
- edit_persona_grid.add (button);
+ label_row = new ContactRow (sheet.pane);
+ this.add (label_row);
+ label_row.label (label_name);
+ }
- if (p == persona)
- button.set_active (true);
+ public void add_to_sheet () {
+ sheet.attach (this, 0, row_nr, 1, 1);
+ added = true;
+ }
- button.toggled.connect ( (a_button) => {
- if (a_button.get_active ())
- update_edit_details (p, p is FakePersona);
- });
+ public bool is_empty () {
+ return get_children ().length () == 1;
+ }
+
+ public void clear () {
+ foreach (var row in get_children ()) {
+ if (row != label_row)
+ row.destroy ();
}
}
- edit_persona_grid.show_all ();
- return persona;
+ public ContactRow new_row () {
+ var row = new ContactRow (sheet.pane);
+ this.add (row);
+ return row;
+ }
}
- private void display_edit (Contact contact, Persona? _persona, bool new_contact = false) {
- Persona? persona = _persona;
- set_display_mode (DisplayMode.EDIT);
-
- edit_image_frame = new ContactFrame (PROFILE_SIZE);
- // Put the frame in a grid so its not expanded by the size-group
- var ig = new Grid ();
- ig.add (edit_image_frame);
- card_layout.add_widget_label (ig);
-
- card_layout.current_row.set_vexpand (false);
- var g = new Grid();
- card_layout.current_row.add (g);
-
- var e = new Entry ();
- e.get_style_context ().add_class ("contact-entry");
- e.set ("placeholder-text", _("Enter name"));
- e.set_data ("original-text", contact.display_name);
- e.set_text (contact.display_name);
- e.set_hexpand (true);
- e.set_halign (Align.FILL);
- e.set_valign (Align.START);
- g.attach (e, 0, 0, 1, 1);
- if (new_contact)
- e.grab_focus ();
-
- if (new_contact) {
- var l = new Label ("");
- l.set_markup ("<span font='12px'>" + _("Contact Name") + "</span>");
- l.xalign = 0.0f;
- g.attach (l, 0, 1, 1, 1);
+ class LinkField : Field {
+ class construct {
+ label_name = _("Links");
}
+ public override void populate () {
+ var details = sheet.persona as UrlDetails;
+ if (details == null)
+ return;
- edit_persona_grid = new Grid ();
- edit_persona_grid.set_column_spacing (0);
- edit_persona_grid.set_halign (Align.START);
- edit_persona_grid.set_valign (Align.END);
- edit_persona_grid.set_vexpand (true);
-
- persona = update_persona_buttons (contact, persona);
- update_edit_details (persona, new_contact || persona is FakePersona);
-
- e.focus_out_event.connect ( (ev) => {
- name = e.get_text ();
- if (name != e.get_data<string?> ("original-text")) {
- e.set_data ("original-text", name);
- Value v = Value (typeof (string));
- v.set_string (name);
- set_individual_property.begin (selected_contact,
- "full-name", v,
- (obj, result) => {
- try {
- var p = set_individual_property.end (result);
- if (p != null &&
- selected_contact == contact &&
- display_mode == DisplayMode.EDIT) {
- if (editing_persona is FakePersona)
- editing_persona = p;
- editing_persona_primary = p;
- update_persona_buttons (selected_contact, editing_persona);
- }
- } catch (Error e) {
- warning ("Unable to create writeable persona: %s", e.message);
- }
- });
- }
- return false;
- });
-
- g.attach (edit_persona_grid, 0, 3, 1, 1);
- card_grid.show_all ();
- fields_grid.show_all ();
- button_grid.show_all ();
+ var urls = details.urls;
+ foreach (var url_details in urls) {
+ var row = new_row ();
+ row.text (Contact.format_uri_link_text (url_details));
+ //row.detail ("Blog");
+ // Add link to url_details.value
+ var image = new Image.from_icon_name ("web-browser" /* -symbolic */, IconSize.MENU);
+ image.get_style_context ().add_class ("dim-label");
+ var button = new Button();
+ button.set_relief (ReliefStyle.NONE);
+ button.add (image);
+ row.right.add (button);
+ }
+ }
}
- private void display_contact (Contact contact) {
- set_display_mode (DisplayMode.DETAILS);
- set_has_notes (!contact.individual.notes.is_empty);
- display_card (contact);
-
- bool can_remove = false;
- bool can_remove_all = true;
- foreach (var p in contact.individual.personas) {
- if (p.store.can_remove_personas == MaybeBool.TRUE &&
- !(p is Tpf.Persona)) {
- can_remove = true;
- } else {
- can_remove_all = false;
+ class EmailField : Field {
+ class construct {
+ label_name = _("Email");
+ }
+ public override void populate () {
+ var details = sheet.persona as EmailDetails;
+ if (details == null)
+ return;
+ var emails = Contact.sort_fields<EmailFieldDetails>(details.email_addresses);
+ foreach (var email in emails) {
+ var row = new_row ();
+ row.text (email.value);
+ row.detail (TypeSet.general.format_type (email));
}
}
- can_remove_all = can_remove && can_remove_all;
-
- delete_menu_item.set_sensitive (can_remove_all);
-
- string [] secondary_sources;
- contact.get_secondary_string (out secondary_sources);
-
- var nickname = contact.individual.nickname;
- if (is_set (nickname) &&
- !("nickname" in secondary_sources))
- fields_layout.add_label_detail (_("Nickname"), nickname);
-
- var emails = Contact.sort_fields<EmailFieldDetails>(contact.individual.email_addresses);
- foreach (var email in emails) {
- var type = TypeSet.general.format_type (email);
- fields_layout.add_label_detail (type, email.value);
- var button = fields_layout.add_button ("mail-unread-symbolic");
- var email_addr = email.value;
- button.clicked.connect ( () => {
- Utils.compose_mail (email_addr);
- });
+ }
+
+ class PhoneField : Field {
+ class construct {
+ label_name = _("Phone");
}
+ public override void populate () {
+ var details = sheet.persona as PhoneDetails;
+ if (details == null)
+ return;
+ var phone_numbers = Contact.sort_fields<PhoneFieldDetails>(details.phone_numbers);
+ foreach (var phone in phone_numbers) {
+ var row = new_row ();
+ row.text (phone.value);
+ row.detail (TypeSet.phone.format_type (phone));
+ }
+ }
+ }
- var ims = contact.individual.im_addresses;
- var im_keys = ims.get_keys ();
- foreach (var protocol in im_keys) {
- foreach (var id in ims[protocol]) {
- fields_layout.add_label_detail (_("Chat"), contact.format_im_name (protocol, id.value));
- Button? button = null;
- var presence = contact.create_presence_widget (protocol, id.value);
- if (presence != null) {
- button = fields_layout.add_button (null);
- button.add (presence);
+ class ChatField : Field {
+ class construct {
+ label_name = _("Chat");
+ }
+ public override void populate () {
+ var details = sheet.persona as ImDetails;
+ if (details == null)
+ return;
+ var ims = details.im_addresses;
+ var im_keys = ims.get_keys ();
+ foreach (var protocol in im_keys) {
+ foreach (var id in ims[protocol]) {
+ var im_persona = sheet.persona as Tpf.Persona;
+ if (im_persona == null)
+ continue;
+ var row = new_row ();
+ row.text (Contact.format_im_name (im_persona, protocol, id.value));
}
+ }
+ }
+ }
- if (button != null) {
- button.clicked.connect ( () => {
- Utils.start_chat (contact, protocol, id.value);
- });
- }
+ class BirthdayField : Field {
+ class construct {
+ label_name = _("Birthday");
+ }
+ public override void populate () {
+ var details = sheet.persona as BirthdayDetails;
+ if (details == null)
+ return;
- var callable_account = contact.is_callable (protocol, id.value);
- if (callable_account != null) {
- Button? button_call = fields_layout.add_button (null);
- var phone_image = new Image ();
- phone_image.set_no_show_all (true);
- phone_image.set_from_icon_name ("audio-input-microphone-symbolic",
- IconSize.MENU);
- phone_image.show ();
- button_call.add (phone_image);
- button_call.clicked.connect ( () => {
- Utils.start_call_with_account (id.value, callable_account);
- });
- }
+ DateTime? bday = details.birthday;
+ if (bday != null) {
+ var row = new_row ();
+ row.text (bday.to_local ().format ("%x"));
+
+ var image = new Image.from_icon_name ("preferences-system-date-and-time-symbolic", IconSize.MENU);
+ image.get_style_context ().add_class ("dim-label");
+ var button = new Button();
+ button.set_relief (ReliefStyle.NONE);
+ button.add (image);
+ row.right.add (button);
}
}
+ }
- var phone_numbers = Contact.sort_fields<PhoneFieldDetails>(contact.individual.phone_numbers);
- foreach (var p in phone_numbers) {
- var phone = p as PhoneFieldDetails;
- var type = TypeSet.phone.format_type (phone);
- fields_layout.add_label_detail (type, phone.value);
- if (this.contacts_store.can_call) {
- Button? button = fields_layout.add_button (null);
- var phone_image = new Image ();
- phone_image.set_no_show_all (true);
- phone_image.set_from_icon_name ("phone-symbolic", IconSize.MENU);
- phone_image.show ();
- button.add (phone_image);
- button.clicked.connect ( () => {
- Utils.start_call (phone.value, this.contacts_store.calling_accounts);
- });
- }
+ class NicknameField : Field {
+ class construct {
+ label_name = _("Nickname");
}
+ public override void populate () {
+ var details = sheet.persona as NameDetails;
+ if (details == null)
+ return;
- var postals = contact.individual.postal_addresses;
- if (!postals.is_empty) {
- foreach (var addr in postals) {
- var type = TypeSet.general.format_type (addr);
- string[] strs = Contact.format_address (addr.value);
- fields_layout.add_label (type);
- if (strs.length > 0) {
- foreach (var s in strs)
- fields_layout.add_detail (s);
- }
- var button = fields_layout.add_button ("edit-copy-symbolic");
- button.clicked.connect ( () => {
- string addr_s = "";
- foreach (var s in Contact.format_address (addr.value)) {
- addr_s += s + "\n";
- }
- Clipboard.get_for_display (button.get_screen().get_display(), Gdk.SELECTION_CLIPBOARD).set_text (addr_s, -1);
- var notification = new Notify.Notification (_("Address copied to clipboard"), null, "edit-copy");
- notification.set_timeout (3000);
- notification.set_urgency (Notify.Urgency.CRITICAL);
- try {
- notification.show ();
- Timeout.add (3000, () => {
- try {
- notification.close ();
- }
- catch (Error e) {
- }
- return false;
- });
- }
- catch (Error e) {
- }
- });
+ if (is_set (details.nickname)) {
+ var row = new_row ();
+ row.text (details.nickname);
}
}
+ }
- DateTime? bday = contact.individual.birthday;
- if (bday != null) {
- fields_layout.add_label (_("Birthday"));
- fields_layout.add_detail (bday.to_local ().format ("%x"));
+ class NoteField : Field {
+ class construct {
+ label_name = _("Note");
}
+ public override void populate () {
+ var details = sheet.persona as NoteDetails;
+ if (details == null)
+ return;
- var roles_details = contact.individual.roles;
- foreach (var role_detail in roles_details) {
- var role = role_detail.value;
- if (is_set (role.organisation_name) &&
- !("organisation-name" in secondary_sources)) {
- fields_layout.add_label (_("Company"));
- fields_layout.add_detail (role.organisation_name);
- }
- var org_units = role_detail.get_parameter_values ("org_unit");
- if (org_units != null) {
- foreach (var org_unit in org_units) {
- if (is_set (org_unit)) {
- fields_layout.add_label (_("Department"));
- fields_layout.add_detail (org_unit);
- }
- }
+ foreach (var note in details.notes) {
+ var row = new_row ();
+ row.text (note.value, true);
}
- if (is_set (role.role) &&
- !("role" in secondary_sources)) {
- fields_layout.add_label (_("Profession"));
- fields_layout.add_detail (role.role);
- }
- if (is_set (role.title) &&
- !("title" in secondary_sources)) {
- fields_layout.add_label (_("Title"));
- fields_layout.add_detail (role.title);
- }
- var managers = role_detail.get_parameter_values ("manager");
- if (managers != null) {
- foreach (var manager in managers) {
- if (is_set (manager)) {
- fields_layout.add_label (_("Manager"));
- fields_layout.add_detail (manager);
- }
- }
- }
- var assistants = role_detail.get_parameter_values ("assistant");
- if (assistants != null) {
- foreach (var assistant in assistants) {
- if (is_set (assistant)) {
- fields_layout.add_label (_("Assistant"));
- fields_layout.add_detail (assistant);
- }
+ }
+ }
+
+ class AddressField : Field {
+ class construct {
+ label_name = _("Addresses");
+ }
+ public override void populate () {
+ var details = sheet.persona as PostalAddressDetails;
+ if (details == null)
+ return;
+
+ foreach (var addr in details.postal_addresses) {
+ var row = new_row ();
+ row.detail (TypeSet.general.format_type (addr));
+ string[] strs = Contact.format_address (addr.value);
+ foreach (var s in strs) {
+ row.text (s, true);
}
}
}
+ }
- var urls = contact.individual.urls;
- if (!urls.is_empty) {
- fields_layout.add_label (_("Links"));
- foreach (var url_details in urls) {
- fields_layout.add_link (url_details.value, contact.format_uri_link_text (url_details));
+ static Type[] field_types = {
+ typeof(LinkField),
+ typeof(EmailField),
+ typeof(PhoneField),
+ typeof(ChatField),
+ typeof(BirthdayField),
+ typeof(NicknameField),
+ typeof(AddressField),
+ typeof(NoteField)
+ /* More:
+ company/department/profession/title/manager/assistant
+ */
+ };
+
+ Field fields[8]; // This is really the size of field_types enum
+
+ public PersonaSheet(ContactPane pane, Persona persona) {
+ assert (fields.length == field_types.length);
+
+ this.pane = pane;
+ this.persona = persona;
+
+ this.set_orientation (Orientation.VERTICAL);
+ this.set_row_spacing (16);
+
+ int row_nr = 0;
+
+ bool editable =
+ Contact.persona_has_writable_property (persona, "email-addresses") &&
+ Contact.persona_has_writable_property (persona, "phone-numbers") &&
+ Contact.persona_has_writable_property (persona, "postal-addresses");
+
+ if (!persona.store.is_primary_store) {
+ header = new ContactRow (pane);
+ this.attach (header, 0, row_nr++, 1, 1);
+
+ var label = new Label ("");
+ label.set_markup (
+ "<span font='24px'>%s</span>".printf (Contact.format_persona_store_name (persona.store)));
+ header.pack_start (label);
+
+ if (!editable) {
+ var image = new Image.from_icon_name ("changes-prevent-symbolic", IconSize.MENU);
+
+ image.get_style_context ().add_class ("dim-label");
+ header.left.add (image);
+ header.left.set (1.0f, 0.5f, 0, 1.0f);
}
}
- card_grid.show_all ();
- fields_grid.show_all ();
- button_grid.show_all ();
- }
+ for (int i = 0; i < field_types.length; i++) {
+ var field = (Field) Object.new(field_types[i], sheet: this, row_nr: row_nr++);
- private void set_has_notes (bool has_notes) {
- if (!keep_has_notes_once)
- this.has_notes = has_notes;
- keep_has_notes_once = false;
- notes_dot.queue_draw ();
- }
+ field.populate ();
+ if (!field.is_empty ())
+ field.add_to_sheet ();
+ }
- private void selected_contact_changed () {
- if (display_mode == DisplayMode.DETAILS) {
- display_contact (selected_contact);
+ if (editable) {
+ footer = new ContactRow (pane);
+ this.attach (footer, 0, row_nr++, 1, 1);
+ var b = new Button.with_label ("Add detail...");
+ footer.pack_start (b);
}
+
}
+}
- private void set_display_mode (DisplayMode mode) {
- card_layout.reset ();
- fields_layout.reset ();
- button_layout.reset ();
- edit_image_frame = null;
- edit_persona_grid = null;
- editing_persona = null;
- editing_persona_primary = null;
+public class Contacts.ContactPane : ScrolledWindow {
+ public SizeGroup border_size_group;
- if (display_mode == mode)
- return;
+ private Store contacts_store;
+ private Grid top_grid;
+ private Grid card_grid;
+ private Grid personas_grid;
- display_mode = mode;
- if (mode == DisplayMode.EMPTY) {
- empty_widget.show ();
- pane.hide ();
- normal_buttons.hide ();
- editing_buttons.hide ();
- } else if (mode == DisplayMode.DETAILS) {
- pane.show ();
- empty_widget.hide ();
- normal_buttons.show ();
- editing_buttons.hide ();
- normal_buttons.set_sensitive (mode != DisplayMode.EMPTY);
+ private Contact? contact;
+
+ const int PROFILE_SIZE = 128;
+
+ private async Persona? set_persona_property (Persona persona,
+ string property_name,
+ Value value) throws GLib.Error, PropertyError {
+ contact.is_unedited = false;
+ if (persona is FakePersona) {
+ var fake = persona as FakePersona;
+ return yield fake.make_real_and_set (property_name, value);
} else {
- pane.show ();
- empty_widget.hide ();
- normal_buttons.hide ();
- editing_buttons.show ();
+ persona.set_data ("contacts-unedited", true);
+ yield Contact.set_persona_property (persona, property_name, value);
+ return null;
}
}
- public void new_contact (ListPane list_pane) {
- var details = new HashTable<string, Value?> (str_hash, str_equal);
- var v = Value (typeof (string));
- v.set_string (_("Contact Name"));
- details.set ("full-name", v);
- contacts_store.aggregator.primary_store.add_persona_from_details.begin (details, (obj, res) => {
- var store = obj as PersonaStore;
- Persona? persona = null;
- Dialog dialog = null;
-
- try {
- persona = store.add_persona_from_details.end (res);
- } catch (Error e) {
- dialog = new MessageDialog (this.get_toplevel () as Window,
- DialogFlags.DESTROY_WITH_PARENT |
- DialogFlags.MODAL,
- MessageType.ERROR,
- ButtonsType.OK,
- _("Unable to create new contacts: %s\n"), e.message);
- }
+ /* Tries to set the property on all persons that have it writeable, and
+ * if none, creates a new persona and writes to it, returning the new
+ * persona.
+ */
+ private async Persona? set_individual_property (Contact contact,
+ string property_name,
+ Value value) throws GLib.Error, PropertyError {
+ contact.is_unedited = false;
+ bool did_set = false;
+ // Need to make a copy here as it could change during the yields
+ var personas_copy = contact.individual.personas.to_array ();
+ foreach (var p in personas_copy) {
+ if (property_name in p.writeable_properties) {
+ did_set = true;
+ yield Contact.set_persona_property (p, property_name, value);
+ }
+ }
- var contact = contacts_store.find_contact_with_persona (persona);
- if (contact == null) {
- dialog = new MessageDialog (this.get_toplevel () as Window,
- DialogFlags.DESTROY_WITH_PARENT |
- DialogFlags.MODAL,
- MessageType.ERROR,
- ButtonsType.OK,
- "%s",
- _("Unable to find newly created contact\n"));
- }
+ if (!did_set) {
+ var fake = new FakePersona (contact);
+ return yield fake.make_real_and_set (property_name, value);
+ }
+ return null;
+ }
- if (dialog != null) {
- dialog.show ();
- dialog.response.connect ( () => {
- dialog.destroy ();
- });
+ public void update_card () {
+ foreach (var w in card_grid.get_children ()) {
+ w.destroy ();
+ }
- return;
- }
+ if (contact == null)
+ return;
- show_contact (contact);
- contact.is_new = true;
- contact.is_unedited = true;
- display_edit (contact, persona, true);
- list_pane.select_contact (contact, true);
-
- ulong id = 0;
- id = this.save_data.connect ( () => {
- if (contact.is_unedited) {
- editing_persona.store.remove_persona.begin (editing_persona, () => {
- });
- }
- this.disconnect (id);
- });
+ var menu = new AvatarMenu (contact);
+ menu.icon_set.connect ( (icon) => {
+ Value v = Value (icon.get_type ());
+ v.set_object (icon);
+ set_individual_property.begin (contact,
+ "avatar", v, () => {
+ });
});
- }
+ var image_frame = new ContactFrame (PROFILE_SIZE, menu);
+ image_frame.set_image (contact.individual, contact);
- public void show_contact (Contact? new_contact, bool edit=false) {
- if (new_contact != null)
- new_contact.is_new = false;
- this.save_data (); // Ensure all edit data saved
+ card_grid.attach (image_frame, 0, 0, 1, 3);
+ card_grid.set_row_spacing (16);
- if (selected_contact != null)
- selected_contact.changed.disconnect (selected_contact_changed);
+ var l = new Label (null);
+ l.set_markup ("<span font='24px'>" + contact.display_name + "</span>");
+ l.set_hexpand (true);
+ l.set_halign (Align.START);
+ l.set_valign (Align.START);
+ l.set_margin_top (4);
+ l.set_ellipsize (Pango.EllipsizeMode.END);
+ l.xalign = 0.0f;
+ card_grid.attach (l, 1, 0, 1, 1);
- selected_contact = new_contact;
- set_display_mode (DisplayMode.EMPTY);
- set_has_notes (false);
+ var merged_presence = contact.create_merged_presence_widget ();
+ merged_presence.set_halign (Align.START);
+ merged_presence.set_valign (Align.START);
+ merged_presence.set_vexpand (true);
+ merged_presence.set_margin_bottom (18);
+ card_grid.attach (merged_presence, 1, 1, 1, 1);
- delete_menu_item.set_sensitive (false);
+ var box = new Box (Orientation.HORIZONTAL, 0);
- if (selected_contact != null) {
- display_contact (selected_contact);
- selected_contact.changed.connect (selected_contact_changed);
- }
- }
+ box.get_style_context ().add_class ("linked");
+ var image = new Image.from_icon_name ("mail-unread-symbolic", IconSize.MENU);
+ var b = new Button ();
+ b.add (image);
+ b.set_hexpand (true);
+ box.pack_start (b, true, true, 0);
- public ContactPane (Store contacts_store) {
- thumbnail_factory = new Gnome.DesktopThumbnailFactory (Gnome.ThumbnailSize.NORMAL);
- this.contacts_store = contacts_store;
+ image = new Image.from_icon_name ("user-available-symbolic", IconSize.MENU);
+ b = new Button ();
+ b.add (image);
+ box.pack_start (b, true, true, 0);
- this.set_orientation (Orientation.VERTICAL);
+ image = new Image.from_icon_name ("call-start-symbolic", IconSize.MENU);
+ b = new Button ();
+ b.add (image);
+ box.pack_start (b, true, true, 0);
- pane = new EventBox ();
- pane.set_no_show_all (true);
- pane.get_style_context ().add_class ("contact-pane");
- this.add (pane);
-
- var image = new Image.from_icon_name ("avatar-default-symbolic", IconSize.MENU);
- image.set_sensitive (false);
- image.set_pixel_size (80);
- image.set_no_show_all (true);
- image.set_hexpand (true);
- image.set_vexpand (true);
- this.add (image);
- empty_widget = image;
-
- var grid = new Grid ();
- grid.set_margin_left (10);
- grid.set_margin_top (10);
- grid.set_margin_bottom (10);
- pane.add (grid);
-
- var scrolled = new ScrolledWindow (null, null);
- scrolled.set_hexpand (true);
- scrolled.set_vexpand (true);
- scrolled.set_policy (PolicyType.NEVER, PolicyType.AUTOMATIC);
- grid.attach (scrolled, 0, 1, 1, 1);
-
- var top_grid = new Grid ();
- top_grid.set_focus_vadjustment (scrolled.get_vadjustment ());
- top_grid.set_orientation (Orientation.VERTICAL);
- top_grid.set_margin_right (10);
- scrolled.add_with_viewport (top_grid);
- scrolled.get_child().get_style_context ().add_class ("contact-pane");
-
- layout_state = new DetailsLayout.SharedState ();
- card_layout = new DetailsLayout (layout_state);
- fields_layout = new DetailsLayout (layout_state);
- button_layout = new DetailsLayout (layout_state);
-
- card_grid = card_layout.grid;
- top_grid.add (card_grid);
-
- fields_grid = fields_layout.grid;
- top_grid.add (fields_grid);
-
- button_grid = button_layout.grid;
- top_grid.add (button_grid);
-
- var bbox = new ButtonBox (Orientation.HORIZONTAL);
- bbox.set_margin_right (10);
- normal_buttons = bbox;
- bbox.set_spacing (5);
- bbox.set_margin_top (8);
- bbox.set_layout (ButtonBoxStyle.START);
- grid.attach (bbox, 0, 2, 1, 1);
-
- var notes_button = new Button ();
- var notes_grid = new Grid ();
- var label = new Label(_("Notes"));
- label.set_hexpand (true);
- // We create an empty widget the same size as the dot in order
- // to make the label center correctly
- var a = new DrawingArea();
- a.set_size_request (6, -1);
- a.set_has_window (false);
- notes_grid.add (a);
- notes_grid.add (label);
- notes_dot = new DrawingArea();
- notes_dot.set_has_window (false);
- notes_dot.set_size_request (6, -1);
- notes_dot.draw.connect ( (widget, cr) => {
- if (has_notes) {
- cr.arc (3, 3 + 2, 3, 0, 2 * Math.PI);
- Gdk.RGBA color;
- color = widget.get_style_context ().get_color (0);
- Gdk.cairo_set_source_rgba (cr, color);
- cr.fill ();
- }
- return true;
- });
- notes_grid.add (notes_dot);
- notes_button.add (notes_grid);
+ card_grid.attach (box, 1, 2, 1, 1);
- notes_button.clicked.connect ( (button) => {
- display_notes ();
- });
+ card_grid.show_all ();
+ }
- bbox.pack_start (notes_button, false, false, 0);
+ public void update_personas () {
+ foreach (var w in personas_grid.get_children ()) {
+ w.destroy ();
+ }
- var button = new Button.with_label(_("Edit"));
- bbox.pack_start (button, false, false, 0);
+ if (contact == null)
+ return;
- button.clicked.connect ( (button) => {
- display_edit (selected_contact, null);
- });
+ var personas = contact.get_personas_for_display ();
- MenuButton menu_button = new MenuButton (_("More"));
- bbox.pack_start (menu_button, false, false, 0);
+ foreach (var p in personas) {
+ var sheet = new PersonaSheet(this, p);
+ personas_grid.add (sheet);
+ }
- bbox.show_all ();
- bbox.set_no_show_all (true);
+ personas_grid.show_all ();
+ }
- bbox = new ButtonBox (Orientation.HORIZONTAL);
- bbox.set_margin_right (10);
- editing_buttons = bbox;
- bbox.set_spacing (5);
- bbox.set_margin_top (8);
- bbox.set_layout (ButtonBoxStyle.END);
- grid.attach (bbox, 0, 3, 1, 1);
+ public void show_contact (Contact? new_contact, bool edit=false) {
+ contact = new_contact;
- button = new Button.with_label(_("Back to Contact"));
- bbox.pack_start (button, false, false, 0);
+ update_card ();
+ update_personas ();
+ }
- button.clicked.connect ( (button) => {
- this.save_data (); // Ensure all edit data saved
- display_contact (selected_contact);
- });
+ public void new_contact (ListPane list_pane) {
+ }
- var menu = new Menu ();
- Utils.add_menu_item (menu,_("Add/Remove Linked Contacts...")).activate.connect (link_contact);
- //Utils.add_menu_item (menu,_("Send..."));
- delete_menu_item = Utils.add_menu_item (menu,_("Delete"));
- delete_menu_item.activate.connect (delete_contact);
+ public ContactPane (Store contacts_store) {
+ this.contacts_store = contacts_store;
+ border_size_group = new SizeGroup (SizeGroupMode.HORIZONTAL);
- menu_button.set_menu (menu);
+ this.set_hexpand (true);
+ this.set_vexpand (true);
+ this.set_policy (PolicyType.NEVER, PolicyType.AUTOMATIC);
- bbox.show_all ();
- bbox.set_no_show_all (true);
+ top_grid = new Grid ();
+ top_grid.set_orientation (Orientation.VERTICAL);
+ top_grid.set_margin_left (10);
+ top_grid.set_margin_top (10);
+ top_grid.set_margin_bottom (10);
+ top_grid.set_row_spacing (20);
+ this.add_with_viewport (top_grid);
- grid.show_all ();
+ this.get_child().get_style_context ().add_class ("contact-pane");
- set_display_mode (DisplayMode.EMPTY);
- set_has_notes (false);
- }
+ var top_row = new ContactRow (this);
+ top_row.left.set_size_request (32, -1);
+ top_grid.add (top_row);
+ card_grid = new Grid ();
+ top_row.pack_start (card_grid, Align.FILL);
- void link_contact () {
- var dialog = new LinkDialog (selected_contact);
- dialog.show_all ();
- }
+ personas_grid = new Grid ();
+ personas_grid.set_orientation (Orientation.VERTICAL);
+ personas_grid.set_row_spacing (40);
+ top_grid.add (personas_grid);
- void delete_contact () {
- contacts_store.aggregator.remove_individual (selected_contact.individual);
+ top_grid.show_all ();
}
-
}
diff --git a/src/contacts-contact.vala b/src/contacts-contact.vala
index e5ee0e8..0d8b5ee 100644
--- a/src/contacts-contact.vala
+++ b/src/contacts-contact.vala
@@ -670,9 +670,9 @@ public class Contacts.Contact : GLib.Object {
return service;
}
- public string format_im_name (string protocol, string id) {
+ public static string format_im_name (Tpf.Persona? persona,
+ string protocol, string id) {
string? service = null;
- var persona = find_im_persona (protocol, id);
if (persona != null) {
var account = (persona.store as Tpf.PersonaStore).account;
service = account.service;
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]