057e7fba9b
Now, per each account, there is a read-only chat view associated with it, accessible through its item in the conversations list. This can be used to place system messages, MOTDs, insignificant errors, etc. Protocols can send text to this buffer by specifying no "chat_id" in an IM_MESSAGE_RECEIVED message.
231 lines
5.5 KiB
C++
231 lines
5.5 KiB
C++
/*
|
|
* Copyright 2021, Jaidyn Levesque <jadedctrl@teknik.io>
|
|
* All rights reserved. Distributed under the terms of the MIT license.
|
|
*/
|
|
|
|
#include "ConversationListView.h"
|
|
|
|
#include <Catalog.h>
|
|
#include <PopUpMenu.h>
|
|
#include <MenuItem.h>
|
|
#include <Window.h>
|
|
|
|
#include "AppMessages.h"
|
|
#include "ChatProtocolMessages.h"
|
|
#include "Conversation.h"
|
|
#include "ConversationAccountItem.h"
|
|
#include "ConversationItem.h"
|
|
#include "MainWindow.h"
|
|
#include "ProtocolLooper.h"
|
|
#include "Server.h"
|
|
#include "TheApp.h"
|
|
|
|
|
|
#undef B_TRANSLATION_CONTEXT
|
|
#define B_TRANSLATION_CONTEXT "ConversationListView"
|
|
|
|
|
|
const uint32 kOpenSelectedChat = 'CVos';
|
|
const uint32 kLeaveSelectedChat = 'CVcs';
|
|
|
|
|
|
static int
|
|
compare_by_name(const BListItem* _item1, const BListItem* _item2)
|
|
{
|
|
ConversationItem* item1 = (ConversationItem*)_item1;
|
|
ConversationItem* item2 = (ConversationItem*)_item2;
|
|
|
|
return strcasecmp(item1->GetConversation()->GetName().String(),
|
|
item2->GetConversation()->GetName().String());
|
|
}
|
|
|
|
|
|
static int
|
|
compare_conversations(const BListItem* _item1, const BListItem* _item2)
|
|
{
|
|
ConversationItem* item1 = (ConversationItem*)_item1;
|
|
ConversationItem* item2 = (ConversationItem*)_item2;
|
|
|
|
int32 userCount1 = item1->GetConversation()->Users().CountItems();
|
|
int32 userCount2 = item2->GetConversation()->Users().CountItems();
|
|
|
|
// Sort by name among chats/rooms
|
|
if ((userCount1 <= 2 && userCount2 <= 2)
|
|
|| (userCount1 > 2 && userCount2 > 2))
|
|
return compare_by_name(item1, item2);
|
|
|
|
// One-on-one chats should sort above rooms
|
|
if (userCount1 <=2 && userCount2 > 2)
|
|
return -1;
|
|
if (userCount1 > 2 && userCount2 <= 2)
|
|
return 1;
|
|
return 0;
|
|
}
|
|
|
|
|
|
ConversationListView::ConversationListView(const char* name)
|
|
: BOutlineListView(name)
|
|
{
|
|
}
|
|
|
|
|
|
void
|
|
ConversationListView::MessageReceived(BMessage* msg)
|
|
{
|
|
switch (msg->what) {
|
|
case kOpenSelectedChat:
|
|
{
|
|
ConversationItem* citem;
|
|
ConversationAccountItem* caitem;
|
|
int32 selIndex = CurrentSelection();
|
|
|
|
if (selIndex >= 0
|
|
&& (citem = (ConversationItem*)ItemAt(selIndex)) != NULL
|
|
&& citem->OutlineLevel() == 1)
|
|
citem->GetConversation()->ShowView(false, true);
|
|
|
|
else if (selIndex >= 0
|
|
&& (caitem = (ConversationAccountItem*)ItemAt(selIndex))
|
|
!= NULL
|
|
&& caitem->OutlineLevel() == 0)
|
|
caitem->GetLooper()->ShowView();
|
|
break;
|
|
}
|
|
default:
|
|
BListView::MessageReceived(msg);
|
|
}
|
|
}
|
|
|
|
|
|
void
|
|
ConversationListView::MouseDown(BPoint where)
|
|
{
|
|
int32 selection = CurrentSelection();
|
|
BOutlineListView::MouseDown(where);
|
|
int32 newSel = CurrentSelection();
|
|
|
|
// Don't allow deselecting anything
|
|
if (newSel < 0 && selection >= 0)
|
|
Select(selection);
|
|
|
|
uint32 buttons = 0;
|
|
Window()->CurrentMessage()->FindInt32("buttons", (int32*)&buttons);
|
|
|
|
if (!(buttons & B_SECONDARY_MOUSE_BUTTON))
|
|
return;
|
|
|
|
if (CurrentSelection() >= 0)
|
|
_ConversationPopUp()->Go(ConvertToScreen(where), true, false);
|
|
else
|
|
_BlankPopUp()->Go(ConvertToScreen(where), true, false);
|
|
}
|
|
|
|
|
|
void
|
|
ConversationListView::SelectionChanged()
|
|
{
|
|
MessageReceived(new BMessage(kOpenSelectedChat));
|
|
}
|
|
|
|
|
|
void
|
|
ConversationListView::AddConversation(Conversation* chat)
|
|
{
|
|
ConversationAccountItem* superItem = _EnsureAccountItem(chat);
|
|
ConversationItem* item = chat->GetListItem();
|
|
if (superItem == NULL || item == NULL)
|
|
return;
|
|
|
|
AddUnder(item, superItem);
|
|
SortItemsUnder(superItem, true, compare_conversations);
|
|
}
|
|
|
|
|
|
void
|
|
ConversationListView::RemoveConversation(Conversation* chat)
|
|
{
|
|
RemoveItem(chat->GetListItem());
|
|
}
|
|
|
|
|
|
void
|
|
ConversationListView::SortConversation(Conversation* chat)
|
|
{
|
|
ConversationAccountItem* superItem = _EnsureAccountItem(chat);
|
|
SortItemsUnder(superItem, true, compare_conversations);
|
|
}
|
|
|
|
|
|
BPopUpMenu*
|
|
ConversationListView::_ConversationPopUp()
|
|
{
|
|
BPopUpMenu* menu = new BPopUpMenu("chatPopUp");
|
|
int32 selIndex = CurrentSelection();
|
|
|
|
ConversationItem* item;
|
|
if ((item = (ConversationItem*)ItemAt(selIndex)) == NULL)
|
|
return _BlankPopUp();
|
|
Conversation* chat = item->GetConversation();
|
|
ProtocolLooper* looper = chat->GetProtocolLooper();
|
|
|
|
Server* server = ((TheApp*)be_app)->GetMainWindow()->GetServer();
|
|
BObjectList<BMessage> items = server->ChatPopUpItems();
|
|
BObjectList<BMessage> protoItems = looper->Protocol()->ChatPopUpItems();
|
|
items.AddList(&protoItems);
|
|
|
|
for (int i = 0; i < items.CountItems(); i++) {
|
|
BMessage* itemMsg = items.ItemAt(i);
|
|
BMessage* msg = new BMessage(*itemMsg);
|
|
BMessage toSend;
|
|
msg->FindMessage("_msg", &toSend);
|
|
toSend.AddString("chat_id", chat->GetId());
|
|
toSend.AddInt64("instance", looper->GetInstance());
|
|
msg->ReplaceMessage("_msg", &toSend);
|
|
|
|
BMenuItem* item = new BMenuItem(msg);
|
|
if (msg->GetBool("x_to_protocol", true) == true)
|
|
item->SetTarget(looper);
|
|
else
|
|
item->SetTarget(Window());
|
|
menu->AddItem(item);
|
|
}
|
|
return menu;
|
|
}
|
|
|
|
|
|
BPopUpMenu*
|
|
ConversationListView::_BlankPopUp()
|
|
{
|
|
bool enabled = false;
|
|
|
|
Server* server = ((TheApp*)be_app)->GetMainWindow()->GetServer();
|
|
if (server != NULL && server->GetAccounts().CountItems() > 0)
|
|
enabled = true;
|
|
|
|
BPopUpMenu* menu = new BPopUpMenu("blankPopUp");
|
|
BMenuItem* newChat = new BMenuItem(B_TRANSLATE("New chat" B_UTF8_ELLIPSIS),
|
|
new BMessage(APP_NEW_CHAT), 'M', B_COMMAND_KEY);
|
|
newChat->SetEnabled(enabled);
|
|
|
|
menu->AddItem(newChat);
|
|
menu->SetTargetForItems(Window());
|
|
return menu;
|
|
}
|
|
|
|
|
|
ConversationAccountItem*
|
|
ConversationListView::_EnsureAccountItem(Conversation* chat)
|
|
{
|
|
ProtocolLooper* looper;
|
|
if (chat == NULL || (looper = chat->GetProtocolLooper()) == NULL)
|
|
return NULL;
|
|
|
|
ConversationAccountItem* item = looper->GetListItem();
|
|
if (HasItem(item) == false)
|
|
AddItem(item);
|
|
|
|
return item;
|
|
}
|
|
|
|
|