Multi-account StatusView; set info per-account

Now the StatusView (bottom-left corner, right below the room list) can
be used to set the nickname and status not only for all accounts at
once, but for managing the status/nick of individual accounts.

AccountManager now can set details of a single account, too.

MainWindow is no longer an Observer (as it just passed the information
along to StatusView― now StatusView manages that itself).

NicknameTextControl was removed, not being in use.
This commit is contained in:
Jaidyn Ann 2021-08-03 13:19:25 -05:00
parent 47ca0f4169
commit 984f066070
13 changed files with 180 additions and 222 deletions

View File

@ -23,15 +23,11 @@ AccountManager::AccountManager()
fStatus(STATUS_OFFLINE),
fReplicantMessenger(NULL)
{
TheApp* theApp = reinterpret_cast<TheApp*>(be_app);
RegisterObserver(theApp->GetMainWindow());
}
AccountManager::~AccountManager()
{
TheApp* theApp = reinterpret_cast<TheApp*>(be_app);
UnregisterObserver(theApp->GetMainWindow());
delete fReplicantMessenger;
}
@ -46,7 +42,7 @@ AccountManager::Get()
void
AccountManager::SetNickname(BString nick)
AccountManager::SetNickname(BString nick, int64 instance)
{
// Create message
BMessage* msg = new BMessage(IM_MESSAGE);
@ -56,7 +52,12 @@ AccountManager::SetNickname(BString nick)
// Send message
TheApp* theApp = reinterpret_cast<TheApp*>(be_app);
MainWindow* win = theApp->GetMainWindow();
win->GetServer()->SendAllProtocolMessage(msg);
if (instance > -1) {
msg->AddInt64("instance", instance);
win->GetServer()->SendProtocolMessage(msg);
}
else
win->GetServer()->SendAllProtocolMessage(msg);
}
@ -75,26 +76,40 @@ AccountManager::Status() const
void
AccountManager::SetStatus(UserStatus status, const char* str)
AccountManager::SetStatus(UserStatus status, const char* str, int64 instance)
{
if (fStatus != status) {
// Create status change message
BMessage* msg = new BMessage(IM_MESSAGE);
msg->AddInt32("im_what", IM_SET_OWN_STATUS);
msg->AddInt32("status", (int32)status);
if (str != NULL)
msg->AddString("message", str);
if (fStatus == status && instance == -1)
return;
// Send message
TheApp* theApp = reinterpret_cast<TheApp*>(be_app);
MainWindow* win = theApp->GetMainWindow();
// Create status change message
BMessage* msg = new BMessage(IM_MESSAGE);
msg->AddInt32("im_what", IM_SET_OWN_STATUS);
msg->AddInt32("status", (int32)status);
if (str != NULL)
msg->AddString("message", str);
// Send message
TheApp* theApp = reinterpret_cast<TheApp*>(be_app);
MainWindow* win = theApp->GetMainWindow();
if (instance > -1) {
msg->AddInt64("instance", instance);
win->GetServer()->SendProtocolMessage(msg);
}
else
win->GetServer()->SendAllProtocolMessage(msg);
// Notify status change
fStatus = status;
NotifyInteger(INT_ACCOUNT_STATUS, (int32)fStatus);
ReplicantStatusNotify((UserStatus)status);
}
// Notify status change
fStatus = status;
NotifyInteger(INT_ACCOUNT_STATUS, (int32)fStatus);
ReplicantStatusNotify((UserStatus)status);
}
void
AccountManager::SetStatus(UserStatus status, int64 instance)
{
SetStatus(status, NULL, instance);
}

View File

@ -15,11 +15,12 @@ class AccountManager : public Notifier {
public:
static AccountManager* Get();
void SetNickname(BString nick);
void SetNickname(BString nick, int64 instance = -1);
UserStatus Status() const;
void SetStatus(UserStatus status,
const char* str = NULL);
void SetStatus(UserStatus status, int64 instance = -1);
void SetStatus(UserStatus status, const char* str,
int64 instance = -1);
void SetReplicantMessenger(BMessenger* messenger);
void ReplicantStatusNotify(UserStatus status,

View File

@ -63,7 +63,6 @@ SRCS = \
application/views/ConversationListView.cpp \
application/views/ConversationView.cpp \
application/views/InviteDialogue.cpp \
application/views/NicknameTextControl.cpp \
application/views/ReplicantStatusView.cpp \
application/views/ReplicantMenuItem.cpp \
application/views/RosterItem.cpp \

View File

@ -253,15 +253,18 @@ Server::ImMessage(BMessage* msg)
case IM_OWN_STATUS_SET:
{
int32 status;
const char* protocol;
if (msg->FindInt32("status", &status) != B_OK)
return B_SKIP_MESSAGE;
if (msg->FindString("protocol", &protocol) != B_OK)
ProtocolLooper* looper = _LooperFromMessage(msg);
if (msg->FindInt32("status", &status) != B_OK || looper == NULL)
return B_SKIP_MESSAGE;
AccountManager* accountManager = AccountManager::Get();
accountManager->SetStatus((UserStatus)status);
Contact* contact = looper->GetOwnContact();
if (contact != NULL) {
contact->SetNotifyStatus((UserStatus)status);
BString statusMsg;
if (msg->FindString("message", &statusMsg) == B_OK)
contact->SetNotifyPersonalStatus(statusMsg);
}
break;
}
case IM_STATUS_SET:

View File

@ -26,27 +26,35 @@
int32 AccountsMenu::fDefaultSelection = 0;
AccountsMenu::AccountsMenu(const char* name, BMessage msg, BMessage* allMsg)
AccountsMenu::AccountsMenu(const char* name, BMessage msg, BMessage* allMsg,
Server* server)
:
BMenu(name),
BPopUpMenu(name),
fAccountMessage(msg),
fAllMessage(allMsg)
fAllMessage(allMsg),
fServer(server)
{
_PopulateMenu();
SetRadioMode(true);
SetLabelFromMarked(true);
Server* server = ((TheApp*)be_app)->GetMainWindow()->GetServer();
server->RegisterObserver(this);
fServer->RegisterObserver(this);
}
AccountsMenu::AccountsMenu(const char* name, BMessage msg, BMessage* allMsg)
:
AccountsMenu(name, msg, allMsg,
((TheApp*)be_app)->GetMainWindow()->GetServer())
{
}
AccountsMenu::~AccountsMenu()
{
delete fAllMessage;
Server* server = ((TheApp*)be_app)->GetMainWindow()->GetServer();
server->UnregisterObserver(this);
fServer->UnregisterObserver(this);
}
@ -69,9 +77,6 @@ AccountsMenu::SetDefaultSelection(BMenuItem* item)
void
AccountsMenu::_PopulateMenu()
{
BFont font;
GetFont(&font);
// Add 'all' item if missing
if (fAllMessage != NULL && FindItem(B_TRANSLATE("All")) == NULL) {
BBitmap* icon = _EnsureAsteriskIcon();
@ -79,8 +84,7 @@ AccountsMenu::_PopulateMenu()
icon, 0, 0, false));
}
Server* server = ((TheApp*)be_app)->GetMainWindow()->GetServer();
AccountInstances accounts = server->GetActiveAccounts();
AccountInstances accounts = fServer->GetActiveAccounts();
// Add protocol item if not already in menu
for (int i = 0; i < accounts.CountItems(); i++) {
@ -94,7 +98,7 @@ AccountsMenu::_PopulateMenu()
if (FindItem(label.String()) != NULL)
continue;
ProtocolLooper* looper = server->GetProtocolLooper(instance);
ProtocolLooper* looper = fServer->GetProtocolLooper(instance);
BBitmap* icon = _EnsureProtocolIcon(label.String(), looper);
BMessage* message = new BMessage(fAccountMessage);
@ -132,7 +136,6 @@ BBitmap*
AccountsMenu::_EnsureProtocolIcon(const char* label, ProtocolLooper* looper)
{
BFont font;
GetFont(&font);
BBitmap* icon = ImageCache::Get()->GetImage(label);
if (icon == NULL && looper != NULL && looper->Protocol()->Icon() != NULL) {
@ -148,7 +151,6 @@ BBitmap*
AccountsMenu::_EnsureAsteriskIcon()
{
BFont font;
GetFont(&font);
BBitmap* icon = ImageCache::Get()->GetImage("kAsteriskScaled");
if (icon == NULL) {

View File

@ -5,15 +5,18 @@
#ifndef _ACCOUNTS_MENU_H
#define _ACCOUNTS_MENU_H
#include <Menu.h>
#include <PopUpMenu.h>
#include "Observer.h"
class ProtocolLooper;
class Server;
class AccountsMenu : public BMenu, public Observer {
class AccountsMenu : public BPopUpMenu, public Observer {
public:
AccountsMenu(const char* name, BMessage msg,
BMessage* allMsg, Server* server);
AccountsMenu(const char* name, BMessage msg,
BMessage* allMsg = NULL);
~AccountsMenu();
@ -33,6 +36,7 @@ private:
BMessage fAccountMessage;
BMessage* fAllMessage;
static int32 fDefaultSelection;
Server* fServer;
};
#endif // _ACCOUNTS_MENU_H

View File

@ -1,29 +0,0 @@
/*
* Copyright 2009, Pier Luigi Fiorini. All rights reserved.
* Distributed under the terms of the MIT License.
*
* Authors:
* Pier Luigi Fiorini, pierluigi.fiorini@gmail.com
*/
#include "AppConstants.h"
#include "NicknameTextControl.h"
#include <Font.h>
NicknameTextControl::NicknameTextControl(const char* name, BMessage* message)
: BTextView(name, B_WILL_DRAW)
{
SetViewColor(ui_color(B_PANEL_BACKGROUND_COLOR));
}
/*
void
NicknameTextControl::Draw(BRect updateRect)
{
// BRect rect(Bounds());
// FillRect(rect);
}
*/

View File

@ -1,17 +0,0 @@
/*
* Copyright 2009, Pier Luigi Fiorini. All rights reserved.
* Distributed under the terms of the MIT License.
*/
#ifndef _NICKNAME_TEXT_CONTROL_H
#define _NICKNAME_TEXT_CONTROL_H
#include <TextView.h>
class NicknameTextControl : public BTextView {
public:
NicknameTextControl(const char* name, BMessage* message);
// virtual void Draw(BRect updateRect);
};
#endif // _NICKNAME_TEXT_CONTROL_H

View File

@ -32,7 +32,6 @@
#include "AppMessages.h"
#include "AppPreferences.h"
#include "ChatProtocolMessages.h"
#include "NicknameTextControl.h"
#include "ReplicantMenuItem.h"
#include "Utils.h"

View File

@ -1,9 +1,11 @@
/*
* Copyright 2009, Pier Luigi Fiorini. All rights reserved.
* Copyright 2021, Jaidyn Levesque. All rights reserved.
* Distributed under the terms of the MIT License.
*
* Authors:
* Pier Luigi Fiorini, pierluigi.fiorini@gmail.com
* Jaidyn Levesque, jadedctrl@teknik.io
*/
#include "StatusView.h"
@ -16,30 +18,36 @@
#include <libinterface/BitmapMenuItem.h>
#include <libinterface/BitmapUtils.h>
#include <libinterface/BitmapView.h>
#include <libinterface/EnterTextView.h>
#include <libinterface/MenuButton.h>
#include "AccountManager.h"
#include "AccountsMenu.h"
#include "ChatProtocolMessages.h"
#include "Contact.h"
#include "ImageCache.h"
#include "NicknameTextControl.h"
#include "NotifyMessage.h"
#include "Server.h"
#include "StatusMenuItem.h"
#include "Utils.h"
const int32 kSetNickname = 'SVnk';
const int32 kSelectAllAccounts = 'SVaa';
const int32 kSelectAccount = 'SVsa';
const int32 kSetNick = 'SVsn';
StatusView::StatusView(const char* name, Server* server)
:
BView(name, B_WILL_DRAW),
fServer(server)
fServer(server),
fAccount(-1)
{
// Nick name
fNickname = new NicknameTextControl("Nickname",
new BMessage(kSetNickname));
fNickname = new EnterTextView("nicknameTextView");
fNickname->MakeEditable(true);
fNickname->MakeResizable(true);
fNickname->SetTarget(this);
fNickname->SetMessage(BMessage(kSetNick), "nick");
// Status menu
fStatusMenu = new BPopUpMenu("-");
@ -76,12 +84,12 @@ StatusView::StatusView(const char* name, Server* server)
fAvatar->SetBitmap(ImageCache::Get()->GetImage("kPersonIcon"));
// Changing the account used
fAccountsMenu = new BPopUpMenu("statusAccountsMenu", true, false);
fAccountsMenu = new AccountsMenu("statusAccountsMenu",
BMessage(kSelectAccount), new BMessage(kSelectAccount), fServer);
fAccountsButton = new MenuButton("statusAccountsButton", "", new BMessage());
fAccountsButton->SetMenu(fAccountsMenu);
_PopulateAccountMenu();
BMessage selected(kSelectAllAccounts);
BMessage selected(kSelectAccount);
MessageReceived(&selected);
// Set layout
@ -111,36 +119,45 @@ void
StatusView::MessageReceived(BMessage* msg)
{
switch (msg->what) {
case kSetNickname:
case kSetNick:
{
AccountManager* accountManager = AccountManager::Get();
accountManager->SetNickname(fNickname->Text());
BString nick;
if (msg->FindString("nick", &nick) == B_OK)
AccountManager::Get()->SetNickname(nick, fAccount);
_SetToAccount();
break;
}
case kSetStatus:
{
int32 status;
if (msg->FindInt32("status", &status) != B_OK)
return;
AccountManager* accountManager = AccountManager::Get();
accountManager->SetStatus((UserStatus)status, "");
if (msg->FindInt32("status", &status) == B_OK)
AccountManager::Get()->SetStatus((UserStatus)status, "",
fAccount);
_SetToAccount();
break;
}
case kSelectAllAccounts:
case kSelectAccount:
{
int32 index = msg->FindInt32("index");
int32 index = msg->GetInt32("index", 0);
BitmapMenuItem* item = (BitmapMenuItem*)fAccountsMenu->ItemAt(index);
// Set button icon/label
fAccountsButton->SetLabel("");
BBitmap* bitmap = item->Bitmap();
fAccountsButton->SetIcon(bitmap);
if (bitmap == NULL) {
char label[2] = { item->Label()[0], '\0' };
fAccountsButton->SetLabel(label);
}
fAccount = msg->GetInt64("instance", -1);
_SetToAccount();
break;
}
case IM_MESSAGE:
{
case IM_MESSAGE: {
int32 im_what = msg->GetInt32("im_what", 0);
if (im_what == IM_PROTOCOL_DISABLE || im_what == IM_PROTOCOL_READY)
_PopulateAccountMenu();
if (im_what == IM_PROTOCOL_READY || im_what == IM_PROTOCOL_DISABLE)
fAccountsMenu->SetTargetForItems(this);
break;
}
default:
@ -150,14 +167,56 @@ StatusView::MessageReceived(BMessage* msg)
void
StatusView::SetName(BString name)
StatusView::ObserveString(int32 what, BString str)
{
if (what == STR_CONTACT_NAME || what == STR_PERSONAL_STATUS)
_SetToAccount();
}
void
StatusView::ObserveInteger(int32 what, int32 value)
{
if (what == INT_ACCOUNT_STATUS || what == INT_CONTACT_STATUS)
_SetToAccount();
}
void
StatusView::ObservePointer(int32 what, void* ptr)
{
if (what == PTR_AVATAR_BITMAP)
_SetToAccount();
}
void
StatusView::_SetToAccount()
{
int64 instance = fAccount;
if (instance == -1)
instance = fServer->GetActiveAccounts().ValueAt(0);
ProtocolLooper* looper = fServer->GetProtocolLooper(instance);
if (looper == NULL || looper->GetOwnContact() == NULL)
return;
Contact* contact = looper->GetOwnContact();
_SetAvatarIcon(contact->AvatarBitmap());
_SetName(contact->GetName());
_SetStatus(contact->GetNotifyStatus());
}
void
StatusView::_SetName(BString name)
{
fNickname->SetText(name.String());
}
void
StatusView::SetStatus(UserStatus status)
StatusView::_SetStatus(UserStatus status)
{
for (int32 i = 0; i < fStatusMenu->CountItems(); i++) {
StatusMenuItem* item
@ -169,61 +228,7 @@ StatusView::SetStatus(UserStatus status)
void
StatusView::SetAvatarIcon(const BBitmap* bitmap)
StatusView::_SetAvatarIcon(const BBitmap* bitmap)
{
// We don't want the default avatar to override a real one
if (bitmap != ImageCache::Get()->GetImage("kPersonIcon"))
fAvatar->SetBitmap(bitmap);
}
void
StatusView::_PopulateAccountMenu()
{
AccountInstances accounts = fServer->GetActiveAccounts();
BFont font;
GetFont(&font);
if (fAccountsMenu->FindItem(B_TRANSLATE("All")) == NULL) {
BBitmap* icon = ImageCache::Get()->GetImage("kAsteriskIcon");
BBitmap* resized = RescaleBitmap(icon, font.Size(), font.Size());
fAccountsMenu->AddItem(new BitmapMenuItem(B_TRANSLATE("All"),
new BMessage(kSelectAllAccounts), resized));
fAccountsMenu->FindItem(B_TRANSLATE("All"))->SetMarked(true);
}
// Add unpopulated entries
for (int i = 0; i < accounts.CountItems(); i++) {
BString name = accounts.KeyAt(i);
int64 instance = accounts.ValueAt(i);
ProtocolLooper* looper = fServer->GetProtocolLooper(instance);
if (looper == NULL || looper->Protocol() == NULL
|| fAccountsMenu->FindItem(name.String()) != NULL)
continue;
BBitmap* icon = looper->Protocol()->Icon();
BBitmap* resized = RescaleBitmap(icon, font.Size(), font.Size());
BMessage* selected = new BMessage(kSelectAccount);
selected->AddInt64("instance", instance);
fAccountsMenu->AddItem(new BitmapMenuItem(name.String(), selected,
resized));
}
// Remove disabled accounts
if (fAccountsMenu->CountItems() - 1 > accounts.CountItems()) {
fAccountsMenu->FindMarked()->SetMarked(false);
fAccountsMenu->ItemAt(0)->SetMarked(true);
BMessage select(kSelectAllAccounts);
MessageReceived(&select);
for (int i = 0; i < fAccountsMenu->CountItems(); i++) {
bool found = false;
accounts.ValueFor(BString(fAccountsMenu->ItemAt(i)->Label()), &found);
if (found == false)
fAccountsMenu->RemoveItem(i);
}
}
fAccountsMenu->SetTargetForItems(this);
fAvatar->SetBitmap(bitmap);
}

View File

@ -1,5 +1,6 @@
/*
* Copyright 2009, Pier Luigi Fiorini. All rights reserved.
* Copyright 2021, Jaidyn Levesque. All rights reserved.
* Distributed under the terms of the MIT License.
*/
#ifndef _STATUS_VIEW_H
@ -8,34 +9,42 @@
#include <View.h>
#include "AppConstants.h"
#include "Observer.h"
class BPopUpMenu;
class AccountsMenu;
class BitmapView;
class EnterTextView;
class MenuButton;
class NicknameTextControl;
class Server;
class StatusView : public BView {
class StatusView : public BView, public Observer {
public:
StatusView(const char* name, Server* server);
virtual void AttachedToWindow();
virtual void MessageReceived(BMessage* msg);
void SetName(BString name);
void SetStatus(UserStatus status);
void SetAvatarIcon(const BBitmap* bitmap);
virtual void ObserveString(int32 what, BString str);
virtual void ObserveInteger(int32 what, int32 value);
virtual void ObservePointer(int32 what, void* ptr);
private:
void _PopulateAccountMenu();
void _SetName(BString name);
void _SetStatus(UserStatus status);
void _SetAvatarIcon(const BBitmap* bitmap);
NicknameTextControl* fNickname;
void _SetToAccount();
EnterTextView* fNickname;
BitmapView* fAvatar;
BPopUpMenu* fStatusMenu;
MenuButton* fAccountsButton;
BPopUpMenu* fAccountsMenu;
AccountsMenu* fAccountsMenu;
int64 fAccount;
Server* fServer;
};

View File

@ -234,17 +234,12 @@ MainWindow::ImMessage(BMessage* msg)
switch (im_what) {
case IM_OWN_CONTACT_INFO:
{
BString name;
if (msg->FindString("name", &name) == B_OK)
fStatusView->SetName(msg->FindString("name"));
int64 instance;
if (msg->FindInt64("instance", &instance) == B_OK) {
ProtocolLooper* looper = fServer->GetProtocolLooper(instance);
if (looper != NULL) {
Contact* contact = looper->GetOwnContact();
contact->RegisterObserver(this);
fStatusView->SetAvatarIcon(contact->AvatarBitmap());
contact->RegisterObserver(fStatusView);
}
}
break;
@ -293,28 +288,6 @@ MainWindow::ImMessage(BMessage* msg)
}
void
MainWindow::ObserveInteger(int32 what, int32 val)
{
switch (what) {
case INT_ACCOUNT_STATUS:
fStatusView->SetStatus((UserStatus)val);
break;
}
}
void
MainWindow::ObservePointer(int32 what, void* ptr)
{
if (what == PTR_AVATAR_BITMAP) {
BBitmap* bmp = (BBitmap*)ptr;
if (bmp != NULL)
fStatusView->SetAvatarIcon(bmp);
}
}
void
MainWindow::WorkspaceActivated(int32 workspace, bool active)
{

View File

@ -9,8 +9,6 @@
#include <Window.h>
#include "Observer.h"
class BSplitView;
class BTextView;
@ -25,7 +23,7 @@ class Server;
class StatusView;
class MainWindow: public BWindow, public Observer {
class MainWindow: public BWindow {
public:
MainWindow();
@ -35,10 +33,6 @@ public:
virtual void MessageReceived(BMessage* message);
void ImMessage(BMessage* msg);
// Observer inheritance
void ObserveInteger(int32 what, int32 val);
void ObservePointer(int32 what, void* ptr);
virtual void WorkspaceActivated(int32 workspace,
bool active);