Replace CreateAccountMenu() with dedicated class

CreateAccountMenu() is used to populate a BMenu with items corresponding
to the map of accounts provided to it― but when an account is disabled
or enabled, it can't update automatically.

A dedicated class, fAccountsMenu, now replaces it― it'll automatically
repopulate the list whenever the active accounts update.
This commit is contained in:
Jaidyn Ann 2021-07-21 12:12:02 -05:00
parent 9245dc7135
commit 0ffe3e5ce8
14 changed files with 178 additions and 71 deletions

View File

@ -55,6 +55,7 @@ SRCS = \
application/preferences/PreferencesAccounts.cpp \ application/preferences/PreferencesAccounts.cpp \
application/preferences/PreferencesBehavior.cpp \ application/preferences/PreferencesBehavior.cpp \
application/preferences/PreferencesReplicant.cpp \ application/preferences/PreferencesReplicant.cpp \
application/views/AccountsMenu.cpp \
application/views/RenderView.cpp \ application/views/RenderView.cpp \
application/views/ConversationAccountItem.cpp \ application/views/ConversationAccountItem.cpp \
application/views/ConversationItem.cpp \ application/views/ConversationItem.cpp \

View File

@ -18,7 +18,9 @@ enum {
INT_USER_PERMS, INT_USER_PERMS,
INT_NEW_MESSAGE, INT_NEW_MESSAGE,
INT_NEW_MENTION, INT_NEW_MENTION,
INT_WINDOW_FOCUSED
INT_WINDOW_FOCUSED,
INT_ACCOUNTS_UPDATED
}; };
#endif // _NOTIFY_MESSAGE_H #endif // _NOTIFY_MESSAGE_H

View File

@ -34,6 +34,7 @@
#include "Flags.h" #include "Flags.h"
#include "ImageCache.h" #include "ImageCache.h"
#include "InviteDialogue.h" #include "InviteDialogue.h"
#include "NotifyMessage.h"
#include "ProtocolLooper.h" #include "ProtocolLooper.h"
#include "ProtocolManager.h" #include "ProtocolManager.h"
#include "RosterItem.h" #include "RosterItem.h"
@ -582,6 +583,8 @@ Server::ImMessage(BMessage* msg)
ProtocolLooper* looper = _LooperFromMessage(msg); ProtocolLooper* looper = _LooperFromMessage(msg);
if (looper == NULL) break; if (looper == NULL) break;
fAccountEnabled.AddItem(looper->Protocol()->GetName(), true);
// Ready notification // Ready notification
if (AppPreferences::Item()->NotifyProtocolStatus == true) if (AppPreferences::Item()->NotifyProtocolStatus == true)
_ProtocolNotification(looper, BString(B_TRANSLATE("Connected")), _ProtocolNotification(looper, BString(B_TRANSLATE("Connected")),
@ -616,16 +619,19 @@ Server::ImMessage(BMessage* msg)
join.AddString("chat_id", fileName); join.AddString("chat_id", fileName);
looper->PostMessage(&join); looper->PostMessage(&join);
} }
NotifyInteger(INT_ACCOUNTS_UPDATED, 0);
break; break;
} }
case IM_PROTOCOL_DISABLE: case IM_PROTOCOL_DISABLE:
{ {
int64 instance = 0; int64 instance = 0;
if (msg->FindInt64("instance", &instance) != B_OK) { if (msg->FindInt64("instance", &instance) != B_OK)
result = B_SKIP_MESSAGE; result = B_SKIP_MESSAGE;
break; else
} RemoveProtocolLooper(instance);
RemoveProtocolLooper(instance);
NotifyInteger(INT_ACCOUNTS_UPDATED, 0);
break; break;
} }
default: default:
@ -664,6 +670,7 @@ Server::AddProtocolLooper(bigtime_t instanceId, ChatProtocol* cayap)
ProtocolLooper* looper = new ProtocolLooper(cayap, instanceId); ProtocolLooper* looper = new ProtocolLooper(cayap, instanceId);
fLoopers.AddItem(instanceId, looper); fLoopers.AddItem(instanceId, looper);
fAccounts.AddItem(cayap->GetName(), instanceId); fAccounts.AddItem(cayap->GetName(), instanceId);
fAccountEnabled.AddItem(cayap->GetName(), false);
} }
@ -684,6 +691,7 @@ Server::RemoveProtocolLooper(bigtime_t instanceId)
fLoopers.RemoveItemFor(instanceId); fLoopers.RemoveItemFor(instanceId);
fAccounts.RemoveItemFor(looper->Protocol()->GetName()); fAccounts.RemoveItemFor(looper->Protocol()->GetName());
fAccountEnabled.AddItem(looper->Protocol()->GetName(), false);
looper->Lock(); looper->Lock();
looper->Quit(); looper->Quit();
} }
@ -704,6 +712,17 @@ Server::GetAccounts()
} }
AccountInstances
Server::GetActiveAccounts()
{
AccountInstances fActive;
for (int i = 0; i < fAccounts.CountItems(); i++)
if (fAccountEnabled.ValueFor(fAccounts.KeyAt(i)) == true)
fActive.AddItem(fAccounts.KeyAt(i), fAccounts.ValueAt(i));
return fActive;
}
void void
Server::SendProtocolMessage(BMessage* msg) Server::SendProtocolMessage(BMessage* msg)
{ {

View File

@ -16,6 +16,7 @@
#include "ChatCommand.h" #include "ChatCommand.h"
#include "Contact.h" #include "Contact.h"
#include "Conversation.h" #include "Conversation.h"
#include "Notifier.h"
#include "ProtocolLooper.h" #include "ProtocolLooper.h"
#include "User.h" #include "User.h"
@ -26,9 +27,10 @@ class ProtocolLooper;
typedef KeyMap<bigtime_t, ProtocolLooper*> ProtocolLoopers; typedef KeyMap<bigtime_t, ProtocolLooper*> ProtocolLoopers;
typedef KeyMap<BString, bigtime_t> AccountInstances; typedef KeyMap<BString, bigtime_t> AccountInstances;
typedef KeyMap<BString, bool> BoolMap;
class Server: public BMessageFilter { class Server: public BMessageFilter, public Notifier {
public: public:
Server(); Server();
void Quit(); void Quit();
@ -43,8 +45,8 @@ public:
void RemoveProtocolLooper(bigtime_t instanceId); void RemoveProtocolLooper(bigtime_t instanceId);
ProtocolLooper* GetProtocolLooper(bigtime_t instanceId); ProtocolLooper* GetProtocolLooper(bigtime_t instanceId);
AccountInstances AccountInstances GetAccounts();
GetAccounts(); AccountInstances GetActiveAccounts();
void SendProtocolMessage(BMessage* msg); void SendProtocolMessage(BMessage* msg);
void SendAllProtocolMessage(BMessage* msg); void SendAllProtocolMessage(BMessage* msg);
@ -87,14 +89,12 @@ private:
void _ReplicantStatusNotify(UserStatus status); void _ReplicantStatusNotify(UserStatus status);
ProtocolLoopers fLoopers; ProtocolLoopers fLoopers;
AccountInstances AccountInstances fAccounts;
fAccounts; BoolMap fAccountEnabled;
CommandMap fCommands; CommandMap fCommands;
BObjectList<BMessage> BObjectList<BMessage> fChatItems;
fChatItems; BObjectList<BMessage> fUserItems;
BObjectList<BMessage>
fUserItems;
}; };

View File

@ -96,26 +96,6 @@ ChatResources()
} }
BMenu*
CreateAccountMenu(AccountInstances accounts, BMessage msg, BMessage* allMsg)
{
BMenu* menu = new BMenu("accountMenu");
if (allMsg != NULL)
menu->AddItem(new BMenuItem("All", new BMessage(*allMsg)));
for (int i = 0; i < accounts.CountItems(); i++)
menu->AddItem(new BMenuItem(accounts.KeyAt(i).String(), new BMessage(msg)));
menu->SetRadioMode(true);
menu->SetLabelFromMarked(true);
menu->ItemAt(0)->SetMarked(true);
if (accounts.CountItems() == 0)
menu->SetEnabled(false);
return menu;
}
const char* const char*
AccountsPath() AccountsPath()
{ {

View File

@ -27,9 +27,6 @@ BString CommandArgs(BString line);
BResources* ChatResources(); BResources* ChatResources();
BMenu* CreateAccountMenu(AccountInstances accounts, BMessage msg,
BMessage* allMsg = NULL);
const char* AccountsPath(); const char* AccountsPath();
const char* AccountPath(const char* signature, const char* subsignature); const char* AccountPath(const char* signature, const char* subsignature);

View File

@ -0,0 +1,65 @@
/*
* Copyright 2021, Jaidyn Levesque <jadedctrl@teknik.io>
* All rights reserved. Distributed under the terms of the MIT license.
*/
#include "AccountsMenu.h"
#include "MainWindow.h"
#include "Server.h"
#include "TheApp.h"
#include <MenuItem.h>
AccountsMenu::AccountsMenu(const char* name, BMessage msg, BMessage* allMsg)
:
BMenu(name),
fAccountMessage(msg),
fAllMessage(allMsg)
{
_PopulateMenu();
SetRadioMode(true);
SetLabelFromMarked(true);
Server* server = ((TheApp*)be_app)->GetMainWindow()->GetServer();
server->RegisterObserver(this);
}
AccountsMenu::~AccountsMenu()
{
delete fAllMessage;
Server* server = ((TheApp*)be_app)->GetMainWindow()->GetServer();
server->UnregisterObserver(this);
}
void
AccountsMenu::ObserveInteger(int32 what, int32 value)
{
_PopulateMenu();
}
void
AccountsMenu::_PopulateMenu()
{
if (CountItems() > 0)
RemoveItems(0, CountItems(), true);
if (fAllMessage != NULL)
AddItem(new BMenuItem("All", new BMessage(*fAllMessage)));
Server* server = ((TheApp*)be_app)->GetMainWindow()->GetServer();
AccountInstances accounts = server->GetActiveAccounts();
for (int i = 0; i < accounts.CountItems(); i++)
AddItem(new BMenuItem(accounts.KeyAt(i).String(),
new BMessage(fAccountMessage)));
if (CountItems() > 0)
ItemAt(0)->SetMarked(true);
else
SetEnabled(false);
}

View File

@ -0,0 +1,27 @@
/*
* Copyright 2021, Jaidyn Levesque <jadedctrl@teknik.io>
* All rights reserved. Distributed under the terms of the MIT license.
*/
#ifndef _ACCOUNTS_MENU_H
#define _ACCOUNTS_MENU_H
#include <Menu.h>
#include "Observer.h"
class AccountsMenu : public BMenu, public Observer {
public:
AccountsMenu(const char* name, BMessage msg, BMessage* allMsg = NULL);
~AccountsMenu();
virtual void ObserveInteger(int32 what, int32 value);
private:
void _PopulateMenu();
BMessage fAccountMessage;
BMessage* fAllMessage;
};
#endif // _ACCOUNTS_MENU_H

View File

@ -20,6 +20,7 @@
#include <ScrollView.h> #include <ScrollView.h>
#include <SeparatorView.h> #include <SeparatorView.h>
#include "AccountsMenu.h"
#include "AppMessages.h" #include "AppMessages.h"
#include "AppPreferences.h" #include "AppPreferences.h"
#include "ChatProtocolMessages.h" #include "ChatProtocolMessages.h"
@ -27,7 +28,6 @@
#include "RosterListView.h" #include "RosterListView.h"
#include "RosterView.h" #include "RosterView.h"
#include "TemplateWindow.h" #include "TemplateWindow.h"
#include "Utils.h"
#undef B_TRANSLATION_CONTEXT #undef B_TRANSLATION_CONTEXT
@ -47,7 +47,6 @@ RosterEditWindow* RosterEditWindow::fInstance = NULL;
RosterEditWindow::RosterEditWindow(Server* server) RosterEditWindow::RosterEditWindow(Server* server)
: :
BWindow(BRect(0, 0, 300, 400), B_TRANSLATE("Roster"), B_FLOATING_WINDOW, 0), BWindow(BRect(0, 0, 300, 400), B_TRANSLATE("Roster"), B_FLOATING_WINDOW, 0),
fAccounts(server->GetAccounts()),
fServer(server), fServer(server),
fEditingWindow(NULL) fEditingWindow(NULL)
{ {
@ -55,7 +54,7 @@ RosterEditWindow::RosterEditWindow(Server* server)
fRosterView->SetInvocationMessage(new BMessage(kEditMember)); fRosterView->SetInvocationMessage(new BMessage(kEditMember));
fAccountField = new BMenuField("accountMenuField", NULL, fAccountField = new BMenuField("accountMenuField", NULL,
CreateAccountMenu(fAccounts, BMessage(kSelAccount), new AccountsMenu("accountMenu", BMessage(kSelAccount),
new BMessage(kSelNoAccount))); new BMessage(kSelNoAccount)));
font_height fontHeight; font_height fontHeight;
@ -183,10 +182,12 @@ RosterEditWindow::MessageReceived(BMessage* message)
} }
case kSelAccount: case kSelAccount:
{ {
AccountInstances accounts = fServer->GetActiveAccounts();
int index = message->FindInt32("index") - 1; int index = message->FindInt32("index") - 1;
if (index < 0 || index > (fAccounts.CountItems() - 1)) if (index < 0 || index > (accounts.CountItems() - 1))
return; return;
fRosterView->SetAccount(fAccounts.ValueAt(index)); fRosterView->SetAccount(accounts.ValueAt(index));
break; break;
} }
case kSelNoAccount: case kSelNoAccount:

View File

@ -36,7 +36,6 @@ public:
private: private:
BMenuField* fAccountField; BMenuField* fAccountField;
AccountInstances fAccounts;
BString fEditingUser; BString fEditingUser;
TemplateWindow* fEditingWindow; TemplateWindow* fEditingWindow;

View File

@ -18,10 +18,10 @@
#include <Notification.h> #include <Notification.h>
#include <ScrollView.h> #include <ScrollView.h>
#include "AccountsMenu.h"
#include "AppMessages.h" #include "AppMessages.h"
#include "AppPreferences.h" #include "AppPreferences.h"
#include "ChatProtocolMessages.h" #include "ChatProtocolMessages.h"
#include "Utils.h"
#include "RosterItem.h" #include "RosterItem.h"
#include "RosterListView.h" #include "RosterListView.h"
#include "RosterView.h" #include "RosterView.h"
@ -38,7 +38,6 @@ RosterWindow::RosterWindow(const char* title, BMessage* selectMsg,
BWindow(BRect(0, 0, 300, 400), title, B_FLOATING_WINDOW, 0), BWindow(BRect(0, 0, 300, 400), title, B_FLOATING_WINDOW, 0),
fTarget(messenger), fTarget(messenger),
fMessage(selectMsg), fMessage(selectMsg),
fAccounts(server->GetAccounts()),
fServer(server) fServer(server)
{ {
fRosterView = new RosterView("buddyView", server, instance), fRosterView = new RosterView("buddyView", server, instance),
@ -46,27 +45,31 @@ RosterWindow::RosterWindow(const char* title, BMessage* selectMsg,
fOkButton = new BButton("OK", new BMessage(kSendMessage)); fOkButton = new BButton("OK", new BMessage(kSendMessage));
BMenu* accountMenu; AccountInstances accounts = fServer->GetActiveAccounts();
// If a specific instance is given, disallow selecting other accounts // If a specific instance is given, disallow selecting other accounts
// In fact, don't even bother populating with them
if (instance > -1) { if (instance > -1) {
accountMenu = new BMenu("accountMenu"); BMenu* accountMenu = new BMenu("accountMenu");
BString name = "N/A"; BString name = "N/A";
for (int i = 0; i < fAccounts.CountItems(); i++) for (int i = 0; i < accounts.CountItems(); i++)
if (fAccounts.ValueAt(i) == instance) { if (accounts.ValueAt(i) == instance) {
name = fAccounts.KeyAt(i); name = accounts.KeyAt(i);
break; break;
} }
accountMenu->AddItem(new BMenuItem(name.String(), NULL)); accountMenu->AddItem(new BMenuItem(name.String(), NULL));
accountMenu->SetLabelFromMarked(true); accountMenu->SetLabelFromMarked(true);
accountMenu->ItemAt(0)->SetMarked(true); accountMenu->ItemAt(0)->SetMarked(true);
accountMenu->SetEnabled(false); accountMenu->SetEnabled(false);
fAccountField = new BMenuField("accountMenuField", NULL, accountMenu);
} }
else else
accountMenu = CreateAccountMenu(fAccounts, BMessage(kSelAccount), fAccountField = new BMenuField("accountMenuField", NULL,
new BMessage(kSelNoAccount)); new AccountsMenu("accountMenu", BMessage(kSelAccount),
new BMessage(kSelNoAccount)));
fAccountField = new BMenuField("accountMenuField", NULL, accountMenu);
BLayoutBuilder::Group<>(this, B_VERTICAL, 0.0f) BLayoutBuilder::Group<>(this, B_VERTICAL, 0.0f)
.SetInsets(B_USE_DEFAULT_SPACING) .SetInsets(B_USE_DEFAULT_SPACING)
@ -103,10 +106,12 @@ RosterWindow::MessageReceived(BMessage* message)
} }
case kSelAccount: case kSelAccount:
{ {
AccountInstances accounts = fServer->GetActiveAccounts();
int index = message->FindInt32("index") - 1; int index = message->FindInt32("index") - 1;
if (index < 0 || index > (fAccounts.CountItems() - 1)) if (index < 0 || index > (accounts.CountItems() - 1))
return; return;
fRosterView->SetAccount(fAccounts.ValueAt(index)); fRosterView->SetAccount(accounts.ValueAt(index));
break; break;
} }
case kSelNoAccount: case kSelNoAccount:

View File

@ -35,7 +35,6 @@ public:
private: private:
BButton* fOkButton; BButton* fOkButton;
BMenuField* fAccountField; BMenuField* fAccountField;
AccountInstances fAccounts;
Server* fServer; Server* fServer;

View File

@ -18,8 +18,8 @@
#include <TextControl.h> #include <TextControl.h>
#include <String.h> #include <String.h>
#include "AccountsMenu.h"
#include "ChatProtocolMessages.h" #include "ChatProtocolMessages.h"
#include "Utils.h"
#include "TemplateView.h" #include "TemplateView.h"
@ -38,7 +38,6 @@ TemplateWindow::TemplateWindow(const char* title, const char* templateType,
BWindow(BRect(0, 0, 400, 100), title, B_FLOATING_WINDOW, BWindow(BRect(0, 0, 400, 100), title, B_FLOATING_WINDOW,
B_NOT_RESIZABLE | B_AUTO_UPDATE_SIZE_LIMITS | B_CLOSE_ON_ESCAPE), B_NOT_RESIZABLE | B_AUTO_UPDATE_SIZE_LIMITS | B_CLOSE_ON_ESCAPE),
fServer(server), fServer(server),
fAccounts(server->GetAccounts()),
fSelectedAcc(0), fSelectedAcc(0),
fTemplate(NULL), fTemplate(NULL),
fTemplateType(templateType), fTemplateType(templateType),
@ -57,7 +56,6 @@ TemplateWindow::TemplateWindow(const char* title, ProtocolTemplate* temp,
BWindow(BRect(0, 0, 400, 100), title, B_FLOATING_WINDOW, BWindow(BRect(0, 0, 400, 100), title, B_FLOATING_WINDOW,
B_NOT_RESIZABLE | B_AUTO_UPDATE_SIZE_LIMITS | B_CLOSE_ON_ESCAPE), B_NOT_RESIZABLE | B_AUTO_UPDATE_SIZE_LIMITS | B_CLOSE_ON_ESCAPE),
fServer(server), fServer(server),
fAccounts(server->GetAccounts()),
fSelectedAcc(0), fSelectedAcc(0),
fTemplate(temp), fTemplate(temp),
fMessage(msg) fMessage(msg)
@ -100,8 +98,11 @@ TemplateWindow::MessageReceived(BMessage* msg)
alert->Go(); alert->Go();
break; break;
} }
AccountInstances accounts = fServer->GetActiveAccounts();
ProtocolLooper* looper ProtocolLooper* looper
= fServer->GetProtocolLooper(fAccounts.ValueAt(fSelectedAcc)); = fServer->GetProtocolLooper(accounts.ValueAt(fSelectedAcc));
if (looper == NULL) if (looper == NULL)
break; break;
looper->PostMessage(settings); looper->PostMessage(settings);
@ -133,25 +134,36 @@ void
TemplateWindow::_InitInterface(bigtime_t instance) TemplateWindow::_InitInterface(bigtime_t instance)
{ {
fTemplateView = new TemplateView("template"); fTemplateView = new TemplateView("template");
BMenu* menu = CreateAccountMenu(fAccounts, BMessage(kAccSelected)); AccountInstances accounts = fServer->GetActiveAccounts();
fMenuField = new BMenuField("accountMenuField", NULL, menu);
if (instance > -1) { if (instance > -1) {
for (int i = 0; i < fAccounts.CountItems(); i++) BMenu* accountMenu = new BMenu("accountMenu");
if (fAccounts.ValueAt(i) == instance) { BString name = "N/A";
menu->ItemAt(i)->SetMarked(true);
for (int i = 0; i < accounts.CountItems(); i++)
if (accounts.ValueAt(i) == instance) {
name = accounts.KeyAt(i);
break; break;
} }
fMenuField->SetEnabled(false); accountMenu->AddItem(new BMenuItem(name.String(), NULL));
accountMenu->SetLabelFromMarked(true);
accountMenu->ItemAt(0)->SetMarked(true);
accountMenu->SetEnabled(false);
fMenuField = new BMenuField("accountMenuField", NULL, accountMenu);
} }
else
fMenuField = new BMenuField("accountMenuField", NULL,
new AccountsMenu("accountMenu", BMessage(kAccSelected)));
BButton* fOkButton = new BButton(B_TRANSLATE("OK"), new BMessage(kOK)); BButton* fOkButton = new BButton(B_TRANSLATE("OK"), new BMessage(kOK));
if (fAccounts.CountItems() <= 0) if (accounts.CountItems() <= 0)
fOkButton->SetEnabled(false); fOkButton->SetEnabled(false);
fOkButton->MakeDefault(true); fOkButton->MakeDefault(true);
const float spacing = be_control_look->DefaultItemSpacing(); const float spacing = be_control_look->DefaultItemSpacing();
BLayoutBuilder::Group<>(this, B_VERTICAL) BLayoutBuilder::Group<>(this, B_VERTICAL)
.SetInsets(B_USE_DEFAULT_SPACING) .SetInsets(B_USE_DEFAULT_SPACING)
.Add(fTemplateView) .Add(fTemplateView)
@ -169,11 +181,12 @@ TemplateWindow::_InitInterface(bigtime_t instance)
void void
TemplateWindow::_LoadTemplate() TemplateWindow::_LoadTemplate()
{ {
if (fAccounts.CountItems() == 0 || fTemplateType.IsEmpty() == true) AccountInstances accounts = fServer->GetActiveAccounts();
if (accounts.CountItems() == 0 || fTemplateType.IsEmpty() == true)
return; return;
ProtocolLooper* looper ProtocolLooper* looper
= fServer->GetProtocolLooper(fAccounts.ValueAt(fSelectedAcc)); = fServer->GetProtocolLooper(accounts.ValueAt(fSelectedAcc));
if (looper == NULL) if (looper == NULL)
return; return;

View File

@ -42,7 +42,6 @@ private:
void _LoadTemplate(); void _LoadTemplate();
Server* fServer; Server* fServer;
AccountInstances fAccounts;
int32 fSelectedAcc; int32 fSelectedAcc;
BMenuField* fMenuField; BMenuField* fMenuField;