diff --git a/src/command/command.c b/src/command/command.c index bfa1385a..b6935daa 100644 --- a/src/command/command.c +++ b/src/command/command.c @@ -278,9 +278,11 @@ static struct cmd_t command_defs[] = CMD_SYN( "/roster", "/roster online", - "/roster show [offline|resource|presence|status|empty|count|priority|contacts|rooms]", - "/roster hide [offline|resource|presence|status|empty|count|priority|contacts|rooms]", + "/roster show [offline|resource|presence|status|empty|priority|contacts|rooms]", + "/roster hide [offline|resource|presence|status|empty|priority|contacts|rooms]", "/roster by group|presence|none", + "/roster count unread|items|off" + "/roster count zero on|off" "/roster order name|presence", "/roster unread before|after|off", "/roster room char |none", @@ -331,6 +333,11 @@ static struct cmd_t command_defs[] = { "by group", "Group contacts in the roster panel by roster group." }, { "by presence", "Group contacts in the roster panel by presence." }, { "by none", "No grouping in the roster panel." }, + { "count unread", "Show total unread message count with roster headers." }, + { "count items", "Show item count with roster headers." }, + { "count off", "Do not show any count with roster headers." }, + { "count zero on", "Show roster count when 0." }, + { "count zero off", "Hide roster count when 0." }, { "order name", "Order roster items by name only." }, { "order presence", "Order roster items by presence, and then by name." }, { "unread before", "Show unread message count before contact in roster." }, @@ -1930,6 +1937,7 @@ static Autocomplete wins_ac; static Autocomplete roster_ac; static Autocomplete roster_show_ac; static Autocomplete roster_by_ac; +static Autocomplete roster_count_ac; static Autocomplete roster_order_ac; static Autocomplete roster_header_ac; static Autocomplete roster_contact_ac; @@ -2200,6 +2208,7 @@ cmd_init(void) autocomplete_add(roster_ac, "show"); autocomplete_add(roster_ac, "hide"); autocomplete_add(roster_ac, "by"); + autocomplete_add(roster_ac, "count"); autocomplete_add(roster_ac, "order"); autocomplete_add(roster_ac, "unread"); autocomplete_add(roster_ac, "room"); @@ -2241,7 +2250,6 @@ cmd_init(void) autocomplete_add(roster_show_ac, "presence"); autocomplete_add(roster_show_ac, "status"); autocomplete_add(roster_show_ac, "empty"); - autocomplete_add(roster_show_ac, "count"); autocomplete_add(roster_show_ac, "priority"); autocomplete_add(roster_show_ac, "contacts"); autocomplete_add(roster_show_ac, "rooms"); @@ -2251,6 +2259,12 @@ cmd_init(void) autocomplete_add(roster_by_ac, "presence"); autocomplete_add(roster_by_ac, "none"); + roster_count_ac = autocomplete_new(); + autocomplete_add(roster_count_ac, "unread"); + autocomplete_add(roster_count_ac, "items"); + autocomplete_add(roster_count_ac, "off"); + autocomplete_add(roster_count_ac, "zero"); + roster_order_ac = autocomplete_new(); autocomplete_add(roster_order_ac, "name"); autocomplete_add(roster_order_ac, "presence"); @@ -2545,6 +2559,7 @@ cmd_uninit(void) autocomplete_free(roster_char_ac); autocomplete_free(roster_show_ac); autocomplete_free(roster_by_ac); + autocomplete_free(roster_count_ac); autocomplete_free(roster_order_ac); autocomplete_free(roster_room_ac); autocomplete_free(roster_unread_ac); @@ -2758,6 +2773,7 @@ cmd_reset_autocomplete(ProfWin *window) autocomplete_reset(roster_char_ac); autocomplete_reset(roster_show_ac); autocomplete_reset(roster_by_ac); + autocomplete_reset(roster_count_ac); autocomplete_reset(roster_order_ac); autocomplete_reset(roster_room_ac); autocomplete_reset(roster_unread_ac); @@ -3192,6 +3208,10 @@ _roster_autocomplete(ProfWin *window, const char *const input) if (result) { return result; } + result = autocomplete_param_with_func(input, "/roster count zero", prefs_autocomplete_boolean_choice); + if (result) { + return result; + } jabber_conn_status_t conn_status = jabber_get_connection_status(); if (conn_status == JABBER_CONNECTED) { @@ -3225,6 +3245,10 @@ _roster_autocomplete(ProfWin *window, const char *const input) if (result) { return result; } + result = autocomplete_param_with_ac(input, "/roster count", roster_count_ac, TRUE); + if (result) { + return result; + } result = autocomplete_param_with_ac(input, "/roster order", roster_order_ac, TRUE); if (result) { return result; diff --git a/src/command/commands.c b/src/command/commands.c index fb3024da..9447f648 100644 --- a/src/command/commands.c +++ b/src/command/commands.c @@ -2224,13 +2224,6 @@ cmd_roster(ProfWin *window, const char *const command, gchar **args) rosterwin_roster(); } return TRUE; - } else if (g_strcmp0(args[1], "count") == 0) { - cons_show("Roster count enabled"); - prefs_set_boolean(PREF_ROSTER_COUNT, TRUE); - if (conn_status == JABBER_CONNECTED) { - rosterwin_roster(); - } - return TRUE; } else if (g_strcmp0(args[1], "priority") == 0) { cons_show("Roster priority enabled"); prefs_set_boolean(PREF_ROSTER_PRIORITY, TRUE); @@ -2299,13 +2292,6 @@ cmd_roster(ProfWin *window, const char *const command, gchar **args) rosterwin_roster(); } return TRUE; - } else if (g_strcmp0(args[1], "count") == 0) { - cons_show("Roster count disabled"); - prefs_set_boolean(PREF_ROSTER_COUNT, FALSE); - if (conn_status == JABBER_CONNECTED) { - rosterwin_roster(); - } - return TRUE; } else if (g_strcmp0(args[1], "priority") == 0) { cons_show("Roster priority disabled"); prefs_set_boolean(PREF_ROSTER_PRIORITY, FALSE); @@ -2381,6 +2367,41 @@ cmd_roster(ProfWin *window, const char *const command, gchar **args) return TRUE; } + } else if (g_strcmp0(args[0], "count") == 0) { + if (g_strcmp0(args[1], "zero") == 0) { + gboolean result = _cmd_set_boolean_preference(args[2], command, "Roster header zero count", PREF_ROSTER_COUNT_ZERO); + if (result) { + if (conn_status == JABBER_CONNECTED) { + rosterwin_roster(); + } + } + return result; + } else if (g_strcmp0(args[1], "unread") == 0) { + cons_show("Roster header count set to unread"); + prefs_set_string(PREF_ROSTER_COUNT, "unread"); + if (conn_status == JABBER_CONNECTED) { + rosterwin_roster(); + } + return TRUE; + } else if (g_strcmp0(args[1], "items") == 0) { + cons_show("Roster header count set to items"); + prefs_set_string(PREF_ROSTER_COUNT, "items"); + if (conn_status == JABBER_CONNECTED) { + rosterwin_roster(); + } + return TRUE; + } else if (g_strcmp0(args[1], "off") == 0) { + cons_show("Disabling roster header count"); + prefs_set_string(PREF_ROSTER_COUNT, "off"); + if (conn_status == JABBER_CONNECTED) { + rosterwin_roster(); + } + return TRUE; + } else { + cons_bad_cmd_usage(command); + return TRUE; + } + } else if (g_strcmp0(args[0], "unread") == 0) { if (g_strcmp0(args[1], "before") == 0) { cons_show("Roster unread message count: before"); diff --git a/src/command/commands.h b/src/command/commands.h index 5972e224..14683115 100644 --- a/src/command/commands.h +++ b/src/command/commands.h @@ -42,7 +42,7 @@ typedef struct cmd_help_t { const gchar *tags[20]; const gchar *synopsis[50]; const gchar *desc; - const gchar *args[64][2]; + const gchar *args[128][2]; const gchar *examples[20]; } CommandHelp; diff --git a/src/config/preferences.c b/src/config/preferences.c index bb85c682..8a15cccd 100644 --- a/src/config/preferences.c +++ b/src/config/preferences.c @@ -1112,6 +1112,7 @@ _get_group(preference_t pref) case PREF_ROSTER_ORDER: case PREF_ROSTER_UNREAD: case PREF_ROSTER_COUNT: + case PREF_ROSTER_COUNT_ZERO: case PREF_ROSTER_PRIORITY: case PREF_ROSTER_WRAP: case PREF_ROSTER_RESOURCE_JOIN: @@ -1311,6 +1312,8 @@ _get_key(preference_t pref) return "roster.unread"; case PREF_ROSTER_COUNT: return "roster.count"; + case PREF_ROSTER_COUNT_ZERO: + return "roster.count.zero"; case PREF_ROSTER_PRIORITY: return "roster.priority"; case PREF_ROSTER_WRAP: @@ -1383,7 +1386,7 @@ _get_default_boolean(preference_t pref) case PREF_ROSTER: case PREF_ROSTER_OFFLINE: case PREF_ROSTER_EMPTY: - case PREF_ROSTER_COUNT: + case PREF_ROSTER_COUNT_ZERO: case PREF_ROSTER_PRIORITY: case PREF_ROSTER_RESOURCE_JOIN: case PREF_ROSTER_CONTACTS: @@ -1415,6 +1418,8 @@ _get_default_string(preference_t pref) return "all"; case PREF_ROSTER_BY: return "presence"; + case PREF_ROSTER_COUNT: + return "unread"; case PREF_ROSTER_ORDER: return "presence"; case PREF_ROSTER_UNREAD: diff --git a/src/config/preferences.h b/src/config/preferences.h index 61ccbb11..32a924ba 100644 --- a/src/config/preferences.h +++ b/src/config/preferences.h @@ -71,6 +71,7 @@ typedef enum { PREF_ROSTER_ORDER, PREF_ROSTER_UNREAD, PREF_ROSTER_COUNT, + PREF_ROSTER_COUNT_ZERO, PREF_ROSTER_PRIORITY, PREF_ROSTER_WRAP, PREF_ROSTER_RESOURCE_JOIN, diff --git a/src/config/theme.c b/src/config/theme.c index e04a5d4a..b886f9e2 100644 --- a/src/config/theme.c +++ b/src/config/theme.c @@ -388,7 +388,7 @@ _load_preferences(void) _set_boolean_preference("roster.status", PREF_ROSTER_STATUS); _set_boolean_preference("roster.empty", PREF_ROSTER_EMPTY); _set_boolean_preference("roster.wrap", PREF_ROSTER_WRAP); - _set_boolean_preference("roster.count", PREF_ROSTER_COUNT); + _set_boolean_preference("roster.count.zero", PREF_ROSTER_COUNT_ZERO); _set_boolean_preference("roster.priority", PREF_ROSTER_PRIORITY); _set_boolean_preference("roster.contacts", PREF_ROSTER_CONTACTS); _set_boolean_preference("roster.rooms", PREF_ROSTER_ROOMS); @@ -417,6 +417,8 @@ _load_preferences(void) _set_string_preference("roster.rooms.unread", PREF_ROSTER_ROOMS_UNREAD); _set_string_preference("roster.rooms.pos", PREF_ROSTER_ROOMS_POS); _set_string_preference("roster.private", PREF_ROSTER_PRIVATE); + _set_string_preference("roster.count", PREF_ROSTER_COUNT); + if (g_key_file_has_key(theme, "ui", "occupants.size", NULL)) { gint occupants_size = g_key_file_get_integer(theme, "ui", "occupants.size", NULL); diff --git a/src/ui/console.c b/src/ui/console.c index a5a9800d..f2c1f35b 100644 --- a/src/ui/console.c +++ b/src/ui/console.c @@ -1370,11 +1370,6 @@ cons_roster_setting(void) else cons_show("Roster empty (/roster) : hide"); - if (prefs_get_boolean(PREF_ROSTER_COUNT)) - cons_show("Roster count (/roster) : show"); - else - cons_show("Roster count (/roster) : hide"); - if (prefs_get_boolean(PREF_ROSTER_PRIORITY)) cons_show("Roster priority (/roster) : show"); else @@ -1385,6 +1380,19 @@ cons_roster_setting(void) else cons_show("Roster contacts (/roster) : hide"); + char *count = prefs_get_string(PREF_ROSTER_COUNT); + if (g_strcmp0(count, "off") == 0) { + cons_show("Roster count (/roster) : OFF"); + } else { + cons_show("Roster count (/roster) : %s", count); + } + prefs_free_string(count); + + if (prefs_get_boolean(PREF_ROSTER_COUNT_ZERO)) + cons_show("Roster count zero (/roster) : ON"); + else + cons_show("Roster count zero (/roster) : OFF"); + char *by = prefs_get_string(PREF_ROSTER_BY); cons_show("Roster by (/roster) : %s", by); prefs_free_string(by); diff --git a/src/ui/rosterwin.c b/src/ui/rosterwin.c index ed5e01f4..ee57e145 100644 --- a/src/ui/rosterwin.c +++ b/src/ui/rosterwin.c @@ -368,9 +368,35 @@ _rosterwin_contacts_by_presence(ProfLayoutSplit *layout, const char *const prese g_string_append_printf(title_str, "%c", ch); } g_string_append(title_str, title); - if (prefs_get_boolean(PREF_ROSTER_COUNT)) { - g_string_append_printf(title_str, " (%d)", g_slist_length(contacts)); + + char *countpref = prefs_get_string(PREF_ROSTER_COUNT); + if (g_strcmp0(countpref, "items") == 0) { + int itemcount = g_slist_length(contacts); + if (itemcount == 0 && prefs_get_boolean(PREF_ROSTER_COUNT_ZERO)) { + g_string_append_printf(title_str, " (%d)", itemcount); + } else if (itemcount > 0) { + g_string_append_printf(title_str, " (%d)", itemcount); + } + } else if (g_strcmp0(countpref, "unread") == 0) { + int unreadcount = 0; + GSList *curr = contacts; + while (curr) { + PContact contact = curr->data; + const char *barejid = p_contact_barejid(contact); + ProfChatWin *chatwin = wins_get_chat(barejid); + if (chatwin) { + unreadcount += chatwin->unread; + } + curr = g_slist_next(curr); + } + if (unreadcount == 0 && prefs_get_boolean(PREF_ROSTER_COUNT_ZERO)) { + g_string_append_printf(title_str, " (%d)", unreadcount); + } else if (unreadcount > 0) { + g_string_append_printf(title_str, " (%d)", unreadcount); + } } + prefs_free_string(countpref); + gboolean wrap = prefs_get_boolean(PREF_ROSTER_WRAP); win_sub_print(layout->subwin, title_str->str, FALSE, wrap, 1); g_string_free(title_str, TRUE); @@ -413,9 +439,35 @@ _rosterwin_contacts_by_group(ProfLayoutSplit *layout, char *group, gboolean newl g_string_append_printf(title, "%c", ch); } g_string_append(title, group); - if (prefs_get_boolean(PREF_ROSTER_COUNT)) { - g_string_append_printf(title, " (%d)", g_slist_length(contacts)); + + char *countpref = prefs_get_string(PREF_ROSTER_COUNT); + if (g_strcmp0(countpref, "items") == 0) { + int itemcount = g_slist_length(contacts); + if (itemcount == 0 && prefs_get_boolean(PREF_ROSTER_COUNT_ZERO)) { + g_string_append_printf(title, " (%d)", itemcount); + } else if (itemcount > 0) { + g_string_append_printf(title, " (%d)", itemcount); + } + } else if (g_strcmp0(countpref, "unread") == 0) { + int unreadcount = 0; + GSList *curr = contacts; + while (curr) { + PContact contact = curr->data; + const char *barejid = p_contact_barejid(contact); + ProfChatWin *chatwin = wins_get_chat(barejid); + if (chatwin) { + unreadcount += chatwin->unread; + } + curr = g_slist_next(curr); + } + if (unreadcount == 0 && prefs_get_boolean(PREF_ROSTER_COUNT_ZERO)) { + g_string_append_printf(title, " (%d)", unreadcount); + } else if (unreadcount > 0) { + g_string_append_printf(title, " (%d)", unreadcount); + } } + prefs_free_string(countpref); + gboolean wrap = prefs_get_boolean(PREF_ROSTER_WRAP); win_sub_print(layout->subwin, title->str, FALSE, wrap, 1); g_string_free(title, TRUE); @@ -457,9 +509,34 @@ _rosterwin_contacts_by_no_group(ProfLayoutSplit *layout, gboolean newline) } g_string_append(title, "no group"); - if (prefs_get_boolean(PREF_ROSTER_COUNT)) { - g_string_append_printf(title, " (%d)", g_slist_length(contacts)); + char *countpref = prefs_get_string(PREF_ROSTER_COUNT); + if (g_strcmp0(countpref, "items") == 0) { + int itemcount = g_slist_length(contacts); + if (itemcount == 0 && prefs_get_boolean(PREF_ROSTER_COUNT_ZERO)) { + g_string_append_printf(title, " (%d)", itemcount); + } else if (itemcount > 0) { + g_string_append_printf(title, " (%d)", itemcount); + } + } else if (g_strcmp0(countpref, "unread") == 0) { + int unreadcount = 0; + GSList *curr = contacts; + while (curr) { + PContact contact = curr->data; + const char *barejid = p_contact_barejid(contact); + ProfChatWin *chatwin = wins_get_chat(barejid); + if (chatwin) { + unreadcount += chatwin->unread; + } + curr = g_slist_next(curr); + } + if (unreadcount == 0 && prefs_get_boolean(PREF_ROSTER_COUNT_ZERO)) { + g_string_append_printf(title, " (%d)", unreadcount); + } else if (unreadcount > 0) { + g_string_append_printf(title, " (%d)", unreadcount); + } } + prefs_free_string(countpref); + gboolean wrap = prefs_get_boolean(PREF_ROSTER_WRAP); win_sub_print(layout->subwin, title->str, FALSE, wrap, 1); g_string_free(title, TRUE); @@ -630,9 +707,31 @@ _rosterwin_private_chats(ProfLayoutSplit *layout) g_string_append_printf(title_str, "%c", ch); } g_string_append(title_str, "Private chats"); - if (prefs_get_boolean(PREF_ROSTER_COUNT)) { - g_string_append_printf(title_str, " (%d)", g_list_length(privs)); + + char *countpref = prefs_get_string(PREF_ROSTER_COUNT); + if (g_strcmp0(countpref, "items") == 0) { + int itemcount = g_list_length(privs); + if (itemcount == 0 && prefs_get_boolean(PREF_ROSTER_COUNT_ZERO)) { + g_string_append_printf(title_str, " (%d)", itemcount); + } else if (itemcount > 0) { + g_string_append_printf(title_str, " (%d)", itemcount); + } + } else if (g_strcmp0(countpref, "unread") == 0) { + int unreadcount = 0; + GList *curr = privs; + while (curr) { + ProfPrivateWin *privwin = curr->data; + unreadcount += privwin->unread; + curr = g_list_next(curr); + } + if (unreadcount == 0 && prefs_get_boolean(PREF_ROSTER_COUNT_ZERO)) { + g_string_append_printf(title_str, " (%d)", unreadcount); + } else if (unreadcount > 0) { + g_string_append_printf(title_str, " (%d)", unreadcount); + } } + prefs_free_string(countpref); + gboolean wrap = prefs_get_boolean(PREF_ROSTER_WRAP); win_sub_print(layout->subwin, title_str->str, FALSE, wrap, 1); g_string_free(title_str, TRUE); @@ -696,6 +795,7 @@ _rosterwin_private_chats(ProfLayoutSplit *layout) void _rosterwin_rooms(ProfLayoutSplit *layout, gboolean newline) { + int unread = 0; GList *rooms = muc_rooms(); GList *rooms_sorted = NULL; GList *curr_room = rooms; @@ -709,6 +809,7 @@ _rosterwin_rooms(ProfLayoutSplit *layout, gboolean newline) rooms_sorted = g_list_insert_sorted(rooms_sorted, mucwin, (GCompareFunc)_compare_rooms_name); } prefs_free_string(order); + unread += mucwin->unread; } curr_room = g_list_next(curr_room); } @@ -726,9 +827,36 @@ _rosterwin_rooms(ProfLayoutSplit *layout, gboolean newline) g_string_append_printf(title_str, "%c", ch); } g_string_append(title_str, "Rooms"); - if (prefs_get_boolean(PREF_ROSTER_COUNT)) { - g_string_append_printf(title_str, " (%d)", g_list_length(rooms_sorted)); + + char *countpref = prefs_get_string(PREF_ROSTER_COUNT); + if (g_strcmp0(countpref, "items") == 0) { + int count = g_list_length(rooms_sorted); + if (count == 0 && prefs_get_boolean(PREF_ROSTER_COUNT_ZERO)) { + g_string_append_printf(title_str, " (%d)", count); + } else if (count > 0) { + g_string_append_printf(title_str, " (%d)", count); + } + } else if (g_strcmp0(countpref, "unread") == 0) { + char *prefpriv = prefs_get_string(PREF_ROSTER_PRIVATE); + if (g_strcmp0(prefpriv, "room") == 0) { + GList *privwins = wins_get_private_chats(NULL); + GList *curr = privwins; + while (curr) { + ProfPrivateWin *privwin = curr->data; + unread += privwin->unread; + curr = g_list_next(curr); + } + g_list_free(privwins); + } + prefs_free_string(prefpriv); + if (unread == 0 && prefs_get_boolean(PREF_ROSTER_COUNT_ZERO)) { + g_string_append_printf(title_str, " (%d)", unread); + } else if (unread > 0) { + g_string_append_printf(title_str, " (%d)", unread); + } } + prefs_free_string(countpref); + gboolean wrap = prefs_get_boolean(PREF_ROSTER_WRAP); win_sub_print(layout->subwin, title_str->str, FALSE, wrap, 1); g_string_free(title_str, TRUE); @@ -818,9 +946,35 @@ rosterwin_roster(void) } g_string_append(title, "Roster"); - if (prefs_get_boolean(PREF_ROSTER_COUNT)) { - g_string_append_printf(title, " (%d)", g_slist_length(contacts)); + + char *countpref = prefs_get_string(PREF_ROSTER_COUNT); + if (g_strcmp0(countpref, "items") == 0) { + int itemcount = g_slist_length(contacts); + if (itemcount == 0 && prefs_get_boolean(PREF_ROSTER_COUNT_ZERO)) { + g_string_append_printf(title, " (%d)", itemcount); + } else { + g_string_append_printf(title, " (%d)", itemcount); + } + } else if (g_strcmp0(countpref, "unread") == 0) { + int unreadcount = 0; + GSList *curr = contacts; + while (curr) { + PContact contact = curr->data; + const char *barejid = p_contact_barejid(contact); + ProfChatWin *chatwin = wins_get_chat(barejid); + if (chatwin) { + unreadcount += chatwin->unread; + } + curr = g_slist_next(curr); + } + if (unreadcount == 0 && prefs_get_boolean(PREF_ROSTER_COUNT_ZERO)) { + g_string_append_printf(title, " (%d)", unreadcount); + } else if (unreadcount > 0) { + g_string_append_printf(title, " (%d)", unreadcount); + } } + prefs_free_string(countpref); + gboolean wrap = prefs_get_boolean(PREF_ROSTER_WRAP); win_sub_print(layout->subwin, title->str, FALSE, wrap, 1); g_string_free(title, TRUE); diff --git a/themes/boothj5 b/themes/boothj5 index d4c0bd9e..ce3ceb8e 100644 --- a/themes/boothj5 +++ b/themes/boothj5 @@ -120,6 +120,8 @@ roster.rooms.unread=after roster.rooms.pos=last roster.private=room roster.private.char=/ +roster.count=unread +roster.count.zero=false occupants=true occupants.size=15 occupants.jid=false diff --git a/themes/complex b/themes/complex index 2f42bc9e..db98ee8d 100644 --- a/themes/complex +++ b/themes/complex @@ -46,6 +46,8 @@ roster.rooms.pos=last roster.rooms.char=# roster.private=room roster.private.char=/ +roster.count=unread +roster.count.zero=true privileges=true presence=true intype=true diff --git a/themes/simple b/themes/simple index 79914b5e..a0af179d 100644 --- a/themes/simple +++ b/themes/simple @@ -34,6 +34,8 @@ roster.status=false roster.contacts=true roster.rooms=false roster.rooms.unread=off +roster.count=off +roster.count.zero=false privileges=false presence=false intype=false