Add "system buffer" per protocol
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.
This commit is contained in:
parent
d16f397fe6
commit
057e7fba9b
|
@ -70,7 +70,13 @@ enum im_what_code {
|
|||
IM_MESSAGE_SENT = 21,
|
||||
|
||||
/*! Chat message received →App
|
||||
Requires: String "chat_id", String "user_id", String "body" */
|
||||
To send a normal chat message, specify chat_id and user_id― if
|
||||
user_id is ommitted, the message is treated as a "system message"
|
||||
printed in chat.
|
||||
If chat_id is ommitted, the message is sent to the protocol's system
|
||||
buffer, rather than a specific conversation.
|
||||
Requires: String "body"
|
||||
Allows: String "chat_id", String "user_id", String "user_name" */
|
||||
IM_MESSAGE_RECEIVED = 22,
|
||||
|
||||
/*! Logs received →App
|
||||
|
|
|
@ -317,7 +317,6 @@ Conversation::SetNotifyIconBitmap(BBitmap* icon)
|
|||
{
|
||||
if (icon != NULL) {
|
||||
fIcon = icon;
|
||||
GetView()->UpdateIcon();
|
||||
NotifyPointer(PTR_ROOM_BITMAP, (void*)icon);
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -17,8 +17,13 @@
|
|||
|
||||
#include "Account.h"
|
||||
#include "AppMessages.h"
|
||||
#include "ChatProtocolMessages.h"
|
||||
#include "Conversation.h"
|
||||
#include "ConversationAccountItem.h"
|
||||
#include "ConversationView.h"
|
||||
#include "MainWindow.h"
|
||||
#include "NotifyMessage.h"
|
||||
#include "TheApp.h"
|
||||
|
||||
|
||||
ProtocolLooper::ProtocolLooper(ChatProtocol* protocol, int64 instance)
|
||||
|
@ -36,8 +41,10 @@ ProtocolLooper::ProtocolLooper(ChatProtocol* protocol, int64 instance)
|
|||
|
||||
BString name(protocol->FriendlySignature());
|
||||
name << " - " << account->Name();
|
||||
|
||||
SetName(name.String());
|
||||
|
||||
_InitChatView();
|
||||
|
||||
Run();
|
||||
}
|
||||
|
||||
|
@ -65,6 +72,22 @@ ProtocolLooper::MessageReceived(BMessage* msg)
|
|||
}
|
||||
|
||||
|
||||
ConversationView*
|
||||
ProtocolLooper::GetView()
|
||||
{
|
||||
return fSystemChatView;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
ProtocolLooper::ShowView()
|
||||
{
|
||||
MainWindow* win = ((TheApp*)be_app)->GetMainWindow();
|
||||
win->SetConversation(NULL);
|
||||
win->SetConversationView(fSystemChatView);
|
||||
}
|
||||
|
||||
|
||||
ChatProtocol*
|
||||
ProtocolLooper::Protocol()
|
||||
{
|
||||
|
@ -213,7 +236,7 @@ ProtocolLooper::GetListItem()
|
|||
{
|
||||
if (fListItem == NULL)
|
||||
fListItem = new ConversationAccountItem(fProtocol->GetName(),
|
||||
fInstance);
|
||||
fInstance, this);
|
||||
return fListItem;
|
||||
}
|
||||
|
||||
|
@ -228,3 +251,26 @@ ProtocolLooper::LoadCommands()
|
|||
fCommands.AddItem(cmd->GetName(), cmd);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
ProtocolLooper::_InitChatView()
|
||||
{
|
||||
fSystemChatView = new ConversationView();
|
||||
|
||||
BMessage clear(kClearText);
|
||||
fSystemChatView->MessageReceived(&clear);
|
||||
|
||||
BMessage init(IM_MESSAGE);
|
||||
init.AddInt32("im_what", IM_MESSAGE_RECEIVED);
|
||||
init.AddString("user_name", "Cardie");
|
||||
init.AddString("body", B_TRANSLATE("I'm rearing to go!"));
|
||||
fSystemChatView->MessageReceived(&init);
|
||||
|
||||
fSystemChatView->ObserveString(STR_ROOM_NAME, fProtocol->GetName());
|
||||
fSystemChatView->ObserveString(STR_ROOM_SUBJECT, "System buffer");
|
||||
|
||||
BBitmap* icon = fProtocol->Icon();
|
||||
if (icon != NULL)
|
||||
fSystemChatView->ObservePointer(PTR_ROOM_BITMAP, (void*)icon);
|
||||
}
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
class Contact;
|
||||
class Conversation;
|
||||
class ConversationAccountItem;
|
||||
class ConversationView;
|
||||
class User;
|
||||
|
||||
|
||||
|
@ -34,6 +35,10 @@ public:
|
|||
|
||||
void MessageReceived(BMessage* msg);
|
||||
|
||||
ConversationView*
|
||||
GetView();
|
||||
void ShowView();
|
||||
|
||||
ChatProtocol* Protocol();
|
||||
|
||||
ChatMap Conversations() const;
|
||||
|
@ -64,6 +69,8 @@ public:
|
|||
void LoadCommands();
|
||||
|
||||
private:
|
||||
void _InitChatView();
|
||||
|
||||
ChatProtocol* fProtocol;
|
||||
int64 fInstance;
|
||||
|
||||
|
@ -74,6 +81,8 @@ private:
|
|||
UserMap fUserMap;
|
||||
CommandMap fCommands;
|
||||
|
||||
ConversationView*
|
||||
fSystemChatView;
|
||||
ConversationAccountItem*
|
||||
fListItem;
|
||||
};
|
||||
|
|
|
@ -32,6 +32,7 @@
|
|||
#include "Cardie.h"
|
||||
#include "ChatProtocol.h"
|
||||
#include "ConversationInfoWindow.h"
|
||||
#include "ConversationView.h"
|
||||
#include "ChatProtocolMessages.h"
|
||||
#include "Flags.h"
|
||||
#include "ImageCache.h"
|
||||
|
@ -461,8 +462,14 @@ Server::ImMessage(BMessage* msg)
|
|||
}
|
||||
break;
|
||||
}
|
||||
case IM_MESSAGE_SENT:
|
||||
case IM_MESSAGE_RECEIVED:
|
||||
if (msg->HasString("chat_id") == false) {
|
||||
ProtocolLooper* looper = _LooperFromMessage(msg);
|
||||
if (looper != NULL)
|
||||
looper->GetView()->MessageReceived(msg);
|
||||
return B_SKIP_MESSAGE;
|
||||
}
|
||||
case IM_MESSAGE_SENT:
|
||||
case IM_ROOM_JOINED:
|
||||
case IM_ROOM_CREATED:
|
||||
case IM_ROOM_METADATA:
|
||||
|
@ -992,7 +999,7 @@ Server::_EnsureConversation(BMessage* message)
|
|||
if (!message || (looper = _LooperFromMessage(message)) == NULL)
|
||||
return NULL;
|
||||
|
||||
BString chat_id = message->FindString("chat_id");
|
||||
BString chat_id = message->GetString("chat_id", "");
|
||||
Conversation* item = NULL;
|
||||
|
||||
if (chat_id.IsEmpty() == false) {
|
||||
|
|
|
@ -5,11 +5,15 @@
|
|||
|
||||
#include "ConversationAccountItem.h"
|
||||
|
||||
#include "ProtocolLooper.h"
|
||||
|
||||
ConversationAccountItem::ConversationAccountItem(const char* name, int64 instance)
|
||||
|
||||
ConversationAccountItem::ConversationAccountItem(const char* name,
|
||||
int64 instance, ProtocolLooper* looper)
|
||||
:
|
||||
BStringItem(name),
|
||||
fInstance(instance)
|
||||
fInstance(instance),
|
||||
fProtocolLooper(looper)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -21,3 +25,8 @@ ConversationAccountItem::GetInstance()
|
|||
}
|
||||
|
||||
|
||||
ProtocolLooper*
|
||||
ConversationAccountItem::GetLooper()
|
||||
{
|
||||
return fProtocolLooper;
|
||||
}
|
||||
|
|
|
@ -8,16 +8,20 @@
|
|||
#include <StringItem.h>
|
||||
|
||||
class Conversation;
|
||||
class ProtocolLooper;
|
||||
|
||||
|
||||
class ConversationAccountItem : public BStringItem {
|
||||
public:
|
||||
ConversationAccountItem(const char* name, int64 instance);
|
||||
ConversationAccountItem(const char* name, int64 instance,
|
||||
ProtocolLooper* looper);
|
||||
|
||||
int64 GetInstance();
|
||||
ProtocolLooper* GetLooper();
|
||||
|
||||
private:
|
||||
int64 fInstance;
|
||||
ProtocolLooper* fProtocolLooper;
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -75,16 +75,22 @@ ConversationListView::MessageReceived(BMessage* msg)
|
|||
switch (msg->what) {
|
||||
case kOpenSelectedChat:
|
||||
{
|
||||
ConversationItem* item;
|
||||
ConversationItem* citem;
|
||||
ConversationAccountItem* caitem;
|
||||
int32 selIndex = CurrentSelection();
|
||||
|
||||
if (selIndex >= 0
|
||||
&& (item = (ConversationItem*)ItemAt(selIndex)) != NULL
|
||||
&& item->OutlineLevel() == 1)
|
||||
item->GetConversation()->ShowView(false, true);
|
||||
&& (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);
|
||||
}
|
||||
|
@ -95,18 +101,10 @@ void
|
|||
ConversationListView::MouseDown(BPoint where)
|
||||
{
|
||||
int32 selection = CurrentSelection();
|
||||
|
||||
BOutlineListView::MouseDown(where);
|
||||
|
||||
int32 newSel = CurrentSelection();
|
||||
|
||||
// Don't allow selecting an AccountItem
|
||||
if (newSel >= 0 && ItemAt(newSel)->OutlineLevel() == 0) {
|
||||
Select(selection);
|
||||
return;
|
||||
}
|
||||
|
||||
// Don't allow deselecting a room
|
||||
// Don't allow deselecting anything
|
||||
if (newSel < 0 && selection >= 0)
|
||||
Select(selection);
|
||||
|
||||
|
@ -158,49 +156,6 @@ ConversationListView::SortConversation(Conversation* chat)
|
|||
}
|
||||
|
||||
|
||||
int32
|
||||
ConversationListView::CountConversations()
|
||||
{
|
||||
int32 count = 0;
|
||||
for (int32 i = 0; i < CountItems(); i++)
|
||||
if (ItemAt(i)->OutlineLevel() == 1)
|
||||
count++;
|
||||
return count;
|
||||
}
|
||||
|
||||
|
||||
int32
|
||||
ConversationListView::ConversationIndexOf(Conversation* chat)
|
||||
{
|
||||
ConversationItem* item = chat->GetListItem();
|
||||
int32 index = IndexOf(item);
|
||||
int32 chatIndex = index;
|
||||
|
||||
if (item == NULL || index < 0)
|
||||
return -1;
|
||||
|
||||
for (int i = 0; i < index; i++)
|
||||
if (ItemAt(i)->OutlineLevel() == 0) // If AccountItem
|
||||
chatIndex--;
|
||||
return chatIndex;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
ConversationListView::SelectConversation(int32 index)
|
||||
{
|
||||
for (int32 i = 0, cindex = -1; i < CountItems(); i++) {
|
||||
if (ItemAt(i)->OutlineLevel() == 1) // If ConversationItem
|
||||
cindex++;
|
||||
|
||||
if (cindex == index) {
|
||||
Select(i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
BPopUpMenu*
|
||||
ConversationListView::_ConversationPopUp()
|
||||
{
|
||||
|
|
|
@ -24,10 +24,6 @@ public:
|
|||
void RemoveConversation(Conversation* chat);
|
||||
void SortConversation(Conversation* chat);
|
||||
|
||||
int32 CountConversations();
|
||||
int32 ConversationIndexOf(Conversation* chat);
|
||||
void SelectConversation(int32 index);
|
||||
|
||||
private:
|
||||
BPopUpMenu* _ConversationPopUp();
|
||||
BPopUpMenu* _BlankPopUp();
|
||||
|
|
|
@ -59,7 +59,7 @@ ConversationView::AttachedToWindow()
|
|||
{
|
||||
while (fMessageQueue.IsEmpty() == false) {
|
||||
BMessage* msg = fMessageQueue.RemoveItemAt(0);
|
||||
ImMessage(msg);
|
||||
MessageReceived(msg);
|
||||
}
|
||||
if (fConversation != NULL) {
|
||||
if (fNameTextView->Text() != fConversation->GetName())
|
||||
|
@ -95,6 +95,9 @@ ConversationView::MessageReceived(BMessage* message)
|
|||
fSendView->ScrollToOffset(0);
|
||||
break;
|
||||
}
|
||||
case kClearText:
|
||||
_AppendOrEnqueueMessage(message);
|
||||
break;
|
||||
case IM_MESSAGE:
|
||||
ImMessage(message);
|
||||
break;
|
||||
|
@ -243,14 +246,6 @@ ConversationView::SetConversation(Conversation* chat)
|
|||
}
|
||||
|
||||
|
||||
void
|
||||
ConversationView::UpdateIcon()
|
||||
{
|
||||
if (fConversation != NULL && fConversation->IconBitmap() != NULL)
|
||||
fIcon->SetBitmap(fConversation->IconBitmap());
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
ConversationView::UpdateUserList(UserMap users)
|
||||
{
|
||||
|
@ -299,6 +294,21 @@ ConversationView::ObserveString(int32 what, BString str)
|
|||
}
|
||||
|
||||
|
||||
void
|
||||
ConversationView::ObservePointer(int32 what, void* ptr)
|
||||
{
|
||||
switch (what)
|
||||
{
|
||||
case PTR_ROOM_BITMAP:
|
||||
{
|
||||
if (ptr != NULL)
|
||||
fIcon->SetBitmap((BBitmap*)ptr);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
ConversationView::GetWeights(float* horizChat, float* horizList,
|
||||
float* vertChat, float* vertSend)
|
||||
|
@ -401,6 +411,13 @@ ConversationView::_AppendOrEnqueueMessage(BMessage* msg)
|
|||
void
|
||||
ConversationView::_AppendMessage(BMessage* msg)
|
||||
{
|
||||
// If ordered to clear buffer… well, I guess we can't refuse
|
||||
if (msg->what == kClearText) {
|
||||
fReceiveView->SetText("");
|
||||
return;
|
||||
}
|
||||
|
||||
// … else we're jamming a message into this view no matter what it takes!
|
||||
BStringList user_ids, user_names, bodies;
|
||||
if (msg->FindStrings("body", &bodies) != B_OK)
|
||||
return;
|
||||
|
|
|
@ -24,6 +24,9 @@ class User;
|
|||
class UserListView;
|
||||
|
||||
|
||||
const uint32 kClearText = 'CVct';
|
||||
|
||||
|
||||
class ConversationView : public BGroupView, public Observer, public Notifier {
|
||||
public:
|
||||
ConversationView(Conversation* chat = NULL);
|
||||
|
@ -36,12 +39,11 @@ public:
|
|||
Conversation* GetConversation();
|
||||
void SetConversation(Conversation* chat);
|
||||
|
||||
void UpdateIcon();
|
||||
|
||||
void UpdateUserList(UserMap users);
|
||||
void InvalidateUserList();
|
||||
|
||||
void ObserveString(int32 what, BString str);
|
||||
void ObservePointer(int32 what, void* ptr);
|
||||
|
||||
void GetWeights(float* horizChat, float* horizList,
|
||||
float* vertChat, float* vertSend);
|
||||
|
|
|
@ -210,23 +210,17 @@ MainWindow::MessageReceived(BMessage* message)
|
|||
}
|
||||
case APP_MOVE_UP:
|
||||
{
|
||||
if (fConversation == NULL)
|
||||
break;
|
||||
|
||||
int32 index = fListView->ConversationIndexOf(fConversation);
|
||||
int32 index = fListView->CurrentSelection();
|
||||
if (index > 0)
|
||||
fListView->SelectConversation(index - 1);
|
||||
fListView->Select(index - 1);
|
||||
break;
|
||||
}
|
||||
case APP_MOVE_DOWN:
|
||||
{
|
||||
if (fConversation == NULL)
|
||||
break;
|
||||
|
||||
int32 index = fListView->ConversationIndexOf(fConversation);
|
||||
int32 count = fListView->CountConversations();
|
||||
int32 index = fListView->CurrentSelection();
|
||||
int32 count = fListView->CountItems();
|
||||
if (index < (count - 1))
|
||||
fListView->SelectConversation(index + 1);
|
||||
fListView->Select(index + 1);
|
||||
break;
|
||||
}
|
||||
case APP_REPLICANT_STATUS_SET:
|
||||
|
@ -346,6 +340,24 @@ MainWindow::WorkspaceActivated(int32 workspace, bool active)
|
|||
|
||||
void
|
||||
MainWindow::SetConversation(Conversation* chat)
|
||||
{
|
||||
fConversation = chat;
|
||||
if (chat != NULL) {
|
||||
SetConversationView(chat->GetView());
|
||||
|
||||
BString title(chat->GetName());
|
||||
title << " ― " << APP_NAME;
|
||||
SetTitle(title.String());
|
||||
}
|
||||
else {
|
||||
SetConversationView(fBackupChatView);
|
||||
SetTitle(APP_NAME);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
MainWindow::SetConversationView(ConversationView* chatView)
|
||||
{
|
||||
// Save split weights
|
||||
float weightChat = fRightView->ItemWeight((int32)0);
|
||||
|
@ -354,17 +366,7 @@ MainWindow::SetConversation(Conversation* chat)
|
|||
fChatView->GetWeights(&horizChat, &horizList, &vertChat, &vertSend);
|
||||
|
||||
fRightView->RemoveChild(fRightView->FindView("chatView"));
|
||||
|
||||
if (chat != NULL) {
|
||||
fChatView = chat->GetView();
|
||||
fConversation = chat;
|
||||
|
||||
BString title(chat->GetName());
|
||||
title << " ― " << APP_NAME;
|
||||
SetTitle(title.String());
|
||||
}
|
||||
else
|
||||
SetTitle(APP_NAME);
|
||||
fChatView = chatView;
|
||||
|
||||
fRightView->AddChild(fChatView, 9);
|
||||
|
||||
|
@ -418,18 +420,16 @@ MainWindow::SetConversation(Conversation* chat)
|
|||
void
|
||||
MainWindow::RemoveConversation(Conversation* chat)
|
||||
{
|
||||
int32 index = fListView->ConversationIndexOf(chat);
|
||||
SetConversation(NULL);
|
||||
|
||||
int32 index = fListView->IndexOf(chat->GetListItem());
|
||||
if (index > 0)
|
||||
index--;
|
||||
|
||||
fListView->RemoveConversation(chat);
|
||||
|
||||
if (fListView->CountConversations() == 0) {
|
||||
fChatView = new ConversationView();
|
||||
SetConversation(NULL);
|
||||
}
|
||||
else
|
||||
fListView->SelectConversation(index);
|
||||
if (fListView->CountItems() > 0)
|
||||
fListView->Select(index);
|
||||
_ToggleMenuItems();
|
||||
}
|
||||
|
||||
|
@ -451,7 +451,8 @@ MainWindow::_InitInterface()
|
|||
|
||||
// Right-side of window, Chat + Textbox
|
||||
fRightView = new BSplitView(B_VERTICAL, 0);
|
||||
fChatView = new ConversationView();
|
||||
fBackupChatView = new ConversationView();
|
||||
fChatView = fBackupChatView;
|
||||
|
||||
// Load weights from settings
|
||||
float horizChat, horizList, vertChat, vertSend;
|
||||
|
@ -587,7 +588,7 @@ MainWindow::_ToggleMenuItems()
|
|||
|
||||
BMenuItem* windowMenuItem = fMenuBar->FindItem(B_TRANSLATE("Window"));
|
||||
BMenu* windowMenu = windowMenuItem->Submenu();
|
||||
enabled = (fListView->CountConversations() > 0);
|
||||
enabled = (fListView->CountItems() > 0);
|
||||
|
||||
for (int i = 0; i < windowMenu->CountItems(); i++)
|
||||
windowMenu->ItemAt(i)->SetEnabled(enabled);
|
||||
|
@ -611,8 +612,8 @@ MainWindow::_EnsureConversationItem(BMessage* msg)
|
|||
_ToggleMenuItems();
|
||||
}
|
||||
|
||||
if (fListView->CountConversations() == 1)
|
||||
fListView->SelectConversation(0);
|
||||
if (fListView->CountItems() == 1)
|
||||
fListView->Select(0);
|
||||
return item;
|
||||
}
|
||||
return NULL;
|
||||
|
|
|
@ -41,6 +41,7 @@ public:
|
|||
bool active);
|
||||
|
||||
void SetConversation(Conversation* chat);
|
||||
void SetConversationView(ConversationView* chatView);
|
||||
void RemoveConversation(Conversation* chat);
|
||||
void SortConversation(Conversation* chat);
|
||||
|
||||
|
@ -75,8 +76,9 @@ private:
|
|||
|
||||
// Right panel, chat
|
||||
BSplitView* fRightView;
|
||||
ConversationView* fChatView;
|
||||
Conversation* fConversation;
|
||||
ConversationView* fChatView;
|
||||
ConversationView* fBackupChatView;
|
||||
};
|
||||
|
||||
|
||||
|
|
Ŝarĝante…
Reference in New Issue