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

View File

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

View File

@ -16,6 +16,7 @@
#include <LayoutBuilder.h>
#include <Notification.h>
#include <ScrollView.h>
#include <StringItem.h>
#include "AppMessages.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),
fAccount(-1),
fServer(server)
fServer(server),
fManualItem(new BStringItem("")),
fManualStr("Select user %user%" B_UTF8_ELLIPSIS)
{
fSearchBox = new BTextControl("searchBox", "", "",
new BMessage(kSearchContact));
@ -80,6 +83,18 @@ RosterView::MessageReceived(BMessage* message)
fListView->AddItem(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;
}
case IM_MESSAGE:
@ -133,9 +148,6 @@ RosterView::ImMessage(BMessage* msg)
UpdateListItem(rosterItem);
// Sort list view again
fListView->Sort();
// Check if the user want the notification
if (!AppPreferences::Item()->NotifyContactStatus)
break;
@ -224,6 +236,7 @@ RosterView::SetInvocationMessage(BMessage* msg)
fListView->SetInvocationMessage(msg);
}
void
RosterView::SetAccount(bigtime_t instance_id)
{

View File

@ -16,6 +16,7 @@
#include "Server.h"
class BStringItem;
class BTextControl;
class RosterItem;
class RosterListView;
@ -33,6 +34,10 @@ public:
void SetInvocationMessage(BMessage* msg);
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);
@ -45,6 +50,9 @@ private:
RosterListView* fListView;
BTextControl* fSearchBox;
bigtime_t fAccount;
BStringItem* fManualItem;
BString fManualStr;
};
#endif // _ROSTER_VIEW_H

View File

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

View File

@ -94,14 +94,27 @@ RosterWindow::MessageReceived(BMessage* message)
{
int index = message->FindInt32("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;
User* user = ritem->GetContact();
fMessage->AddString("user_id", user->GetId());
fMessage->AddInt64("instance", user->GetProtocolLooper()->GetInstance());
fMessage->AddString("user_id", user_id);
fMessage->AddInt64("instance", instance);
fTarget->SendMessage(fMessage);
fMessage->PrintToStream();
PostMessage(B_QUIT_REQUESTED);
break;
}