Allow selection of non-contacts in roster windows

Windows using RosterView (like for the invitiation/new chat dialogues)
have a search-box for filtering between contacts. This allows the user
to type a user ID into this search-box that isn't a contact's ID, which
can then be selected as the user.

This makes common operations (inviting a user/adding a new contact)
a little easier.
This commit is contained in:
Jaidyn Ann 2021-07-28 16:53:59 -05:00
parent e33dd92375
commit 37453ba2af
6 changed files with 113 additions and 34 deletions

View File

@ -39,24 +39,36 @@ const int32 kGetInfo = 'GINF';
static int static int
compare_by_name(const void* _item1, const void* _item2) compare_by_name(const void* _item1, const void* _item2)
{ {
RosterItem* item1 = *(RosterItem**)_item1; BListItem* item1 = *(BListItem**)_item1;
RosterItem* item2 = *(RosterItem**)_item2; BListItem* item2 = *(BListItem**)_item2;
RosterItem* roster1 = dynamic_cast<RosterItem*>(item1);
RosterItem* roster2 = dynamic_cast<RosterItem*>(item2);
return strcasecmp(item1->GetContact()->GetName().String(), if (roster1 == NULL && roster2 == NULL)
item2->GetContact()->GetName().String()); return 0;
if (roster1 == NULL)
return 1;
if (roster2 == NULL)
return -1;
return strcasecmp(roster1->GetContact()->GetName().String(),
roster2->GetContact()->GetName().String());
} }
static int static int
compare_by_status(const void* _item1, const void* _item2) compare_by_status(const void* _item1, const void* _item2)
{ {
RosterItem* item1 = *(RosterItem**)_item1; BListItem* item1 = *(RosterItem**)_item1;
RosterItem* item2 = *(RosterItem**)_item2; BListItem* item2 = *(RosterItem**)_item2;
RosterItem* roster1 = dynamic_cast<RosterItem*>(item1);
RosterItem* roster2 = dynamic_cast<RosterItem*>(item2);
if (item1->Status() < item2->Status()) if (roster1 == NULL && roster2 == NULL)
return 0;
if (roster1 == NULL || roster1->Status() < roster2->Status())
return 1; return 1;
if (item1->Status() > item2->Status()) if (roster2 == NULL || roster1->Status() > roster2->Status())
return 2; return -1;
return 0; return 0;
} }
@ -224,7 +236,7 @@ RosterListView::Draw(BRect updateRect)
bool bool
RosterListView::AddItem(RosterItem* item) RosterListView::AddItem(BListItem* item)
{ {
item->Deselect(); item->Deselect();
bool ret = false; bool ret = false;
@ -235,11 +247,11 @@ RosterListView::AddItem(RosterItem* item)
} }
void bool
RosterListView::RemoveItem(RosterItem* item) RosterListView::RemoveItem(BListItem* item)
{ {
item->Deselect(); item->Deselect();
BListView::RemoveItem(item); return BListView::RemoveItem(item);
} }

View File

@ -23,8 +23,8 @@ public:
virtual void Draw(BRect updateRect); virtual void Draw(BRect updateRect);
virtual void AttachedToWindow(); virtual void AttachedToWindow();
bool AddItem(RosterItem* item); virtual bool AddItem(BListItem* item);
void RemoveItem(RosterItem* item); virtual bool RemoveItem(BListItem* item);
RosterItem* RosterItemAt(int32 index); RosterItem* RosterItemAt(int32 index);
void Sort(); void Sort();

View File

@ -16,6 +16,7 @@
#include <LayoutBuilder.h> #include <LayoutBuilder.h>
#include <Notification.h> #include <Notification.h>
#include <ScrollView.h> #include <ScrollView.h>
#include <StringItem.h>
#include "AppMessages.h" #include "AppMessages.h"
#include "AppPreferences.h" #include "AppPreferences.h"
@ -36,7 +37,9 @@ RosterView::RosterView(const char* title, Server* server, bigtime_t account)
: :
BGroupView(title, B_VERTICAL, B_USE_DEFAULT_SPACING), BGroupView(title, B_VERTICAL, B_USE_DEFAULT_SPACING),
fAccount(-1), fAccount(-1),
fServer(server) fServer(server),
fManualItem(new BStringItem("")),
fManualStr("Select user %user%" B_UTF8_ELLIPSIS)
{ {
fSearchBox = new BTextControl("searchBox", "", "", fSearchBox = new BTextControl("searchBox", "", "",
new BMessage(kSearchContact)); new BMessage(kSearchContact));
@ -80,6 +83,18 @@ RosterView::MessageReceived(BMessage* message)
fListView->AddItem(item); fListView->AddItem(item);
UpdateListItem(item); UpdateListItem(item);
} }
// If view has specific account selected, we want the user to be
// able to select non-contacts of that protocol
if (fAccount != - 1 && strcmp(fSearchBox->Text(), "") != 0) {
BString label = fManualStr;
label.ReplaceAll("%user%", fSearchBox->Text());
fManualItem->SetText(label.String());
fListView->AddItem(fManualItem);
}
else if (fListView->HasItem(fManualItem))
fListView->RemoveItem(fManualItem);
break; break;
} }
case IM_MESSAGE: case IM_MESSAGE:
@ -133,9 +148,6 @@ RosterView::ImMessage(BMessage* msg)
UpdateListItem(rosterItem); UpdateListItem(rosterItem);
// Sort list view again
fListView->Sort();
// Check if the user want the notification // Check if the user want the notification
if (!AppPreferences::Item()->NotifyContactStatus) if (!AppPreferences::Item()->NotifyContactStatus)
break; break;
@ -224,6 +236,7 @@ RosterView::SetInvocationMessage(BMessage* msg)
fListView->SetInvocationMessage(msg); fListView->SetInvocationMessage(msg);
} }
void void
RosterView::SetAccount(bigtime_t instance_id) RosterView::SetAccount(bigtime_t instance_id)
{ {

View File

@ -16,6 +16,7 @@
#include "Server.h" #include "Server.h"
class BStringItem;
class BTextControl; class BTextControl;
class RosterItem; class RosterItem;
class RosterListView; class RosterListView;
@ -33,6 +34,10 @@ public:
void SetInvocationMessage(BMessage* msg); void SetInvocationMessage(BMessage* msg);
void SetAccount(bigtime_t instance_id); void SetAccount(bigtime_t instance_id);
void SetManualString(const char* text) { fManualStr = text; }
int64 GetAccount() { return fAccount; }
BTextControl* SearchBox() { return fSearchBox; }
void UpdateListItem(RosterItem* item); void UpdateListItem(RosterItem* item);
@ -45,6 +50,9 @@ private:
RosterListView* fListView; RosterListView* fListView;
BTextControl* fSearchBox; BTextControl* fSearchBox;
bigtime_t fAccount; bigtime_t fAccount;
BStringItem* fManualItem;
BString fManualStr;
}; };
#endif // _ROSTER_VIEW_H #endif // _ROSTER_VIEW_H

View File

@ -41,6 +41,9 @@ const uint32 kEditMember = 'RWEM';
const uint32 kSelAccount = 'RWSA'; const uint32 kSelAccount = 'RWSA';
const uint32 kSelNoAccount = 'RWNA'; const uint32 kSelNoAccount = 'RWNA';
const char* kAddTitle = B_TRANSLATE("Adding contact");
const char* kEditTitle = B_TRANSLATE("Editing contact");
RosterEditWindow* RosterEditWindow::fInstance = NULL; RosterEditWindow* RosterEditWindow::fInstance = NULL;
@ -53,6 +56,8 @@ RosterEditWindow::RosterEditWindow(Server* server)
{ {
fRosterView = new RosterView("buddyView", server); fRosterView = new RosterView("buddyView", server);
fRosterView->SetInvocationMessage(new BMessage(kEditMember)); fRosterView->SetInvocationMessage(new BMessage(kEditMember));
fRosterView->SetManualString(BString("Add %user% as contact"
B_UTF8_ELLIPSIS));
fAccountField = new BMenuField("accountMenuField", NULL, fAccountField = new BMenuField("accountMenuField", NULL,
new AccountsMenu("accountMenu", BMessage(kSelAccount), new AccountsMenu("accountMenu", BMessage(kSelAccount),
@ -128,26 +133,54 @@ RosterEditWindow::MessageReceived(BMessage* message)
int index = message->FindInt32("index"); int index = message->FindInt32("index");
RosterItem* ritem = fRosterView->ListView()->RosterItemAt(index); RosterItem* ritem = fRosterView->ListView()->RosterItemAt(index);
if (ritem == NULL) const char* search = fRosterView->SearchBox()->Text();
return; User* user;
BString user_id;
int64 instance;
User* user = ritem->GetContact(); if (ritem != NULL) {
fEditingUser.SetTo(user->GetId().String()); user = ritem->GetContact();
user_id = user->GetId();
instance = user->GetProtocolLooper()->GetInstance();
}
else if (search != NULL) {
user_id = search;
instance = fRosterView->GetAccount();
}
else
break;
fEditingUser.SetTo(user_id.String());
// The response IM_EXTENDED_CONTACT_INFO is used to populate the // The response IM_EXTENDED_CONTACT_INFO is used to populate the
// TemplateWindow. // TemplateWindow― if we're editing a pre-existing contact
if (ritem != NULL) {
user = ritem->GetContact();
BMessage* request = new BMessage(IM_MESSAGE); BMessage* request = new BMessage(IM_MESSAGE);
request->AddInt32("im_what", IM_GET_EXTENDED_CONTACT_INFO); request->AddInt32("im_what", IM_GET_EXTENDED_CONTACT_INFO);
request->AddString("user_id", user->GetId()); request->AddString("user_id", user_id);
user->GetProtocolLooper()->PostMessage(request); user->GetProtocolLooper()->PostMessage(request);
}
BMessage* edit = new BMessage(IM_MESSAGE); BMessage* edit = new BMessage(IM_MESSAGE);
edit->AddInt32("im_what", IM_CONTACT_LIST_EDIT_CONTACT); edit->AddInt32("im_what", IM_CONTACT_LIST_EDIT_CONTACT);
const char* title;
if (ritem == NULL)
title = kAddTitle;
else
title = kEditTitle;
fEditingWindow = fEditingWindow =
new TemplateWindow(B_TRANSLATE("Editing contact"), "roster", new TemplateWindow(title, "roster",
edit, fServer, user->GetProtocolLooper()->GetInstance()); edit, fServer, instance);
fEditingWindow->Show(); fEditingWindow->Show();
if (ritem == NULL) {
BMessage* idMsg = new BMessage(IM_MESSAGE);
idMsg->AddString("user_id", user_id);
fEditingWindow->PostMessage(idMsg);
}
break; break;
} }
case kAddMember: case kAddMember:
@ -155,7 +188,7 @@ RosterEditWindow::MessageReceived(BMessage* message)
BMessage* add = new BMessage(IM_MESSAGE); BMessage* add = new BMessage(IM_MESSAGE);
add->AddInt32("im_what", IM_CONTACT_LIST_ADD_CONTACT); add->AddInt32("im_what", IM_CONTACT_LIST_ADD_CONTACT);
TemplateWindow* win = TemplateWindow* win =
new TemplateWindow(B_TRANSLATE("Adding contact"), "roster", new TemplateWindow(B_TRANSLATE(kAddTitle), "roster",
add, fServer); add, fServer);
win->Show(); win->Show();
break; break;

View File

@ -94,14 +94,27 @@ RosterWindow::MessageReceived(BMessage* message)
{ {
int index = message->FindInt32("index"); int index = message->FindInt32("index");
RosterItem* ritem = fRosterView->ListView()->RosterItemAt(index); RosterItem* ritem = fRosterView->ListView()->RosterItemAt(index);
const char* search = fRosterView->SearchBox()->Text();
BString user_id;
int64 instance;
if (ritem == NULL) if (ritem != NULL) {
User* user = ritem->GetContact();
user_id = user->GetId();
instance = user->GetProtocolLooper()->GetInstance();
}
else if (search != NULL) {
user_id = search;
instance = fRosterView->GetAccount();
}
else
return; return;
User* user = ritem->GetContact(); User* user = ritem->GetContact();
fMessage->AddString("user_id", user->GetId()); fMessage->AddString("user_id", user_id);
fMessage->AddInt64("instance", user->GetProtocolLooper()->GetInstance()); fMessage->AddInt64("instance", instance);
fTarget->SendMessage(fMessage); fTarget->SendMessage(fMessage);
fMessage->PrintToStream();
PostMessage(B_QUIT_REQUESTED); PostMessage(B_QUIT_REQUESTED);
break; break;
} }