diff --git a/application/Makefile b/application/Makefile index d0c1e14..06f0969 100644 --- a/application/Makefile +++ b/application/Makefile @@ -55,6 +55,7 @@ SRCS = \ application/preferences/PreferencesAccounts.cpp \ application/preferences/PreferencesBehavior.cpp \ application/preferences/PreferencesReplicant.cpp \ + application/views/AccountsMenu.cpp \ application/views/RenderView.cpp \ application/views/ConversationAccountItem.cpp \ application/views/ConversationItem.cpp \ diff --git a/application/NotifyMessage.h b/application/NotifyMessage.h index 3f77d92..4a229b5 100644 --- a/application/NotifyMessage.h +++ b/application/NotifyMessage.h @@ -18,7 +18,9 @@ enum { INT_USER_PERMS, INT_NEW_MESSAGE, INT_NEW_MENTION, - INT_WINDOW_FOCUSED + + INT_WINDOW_FOCUSED, + INT_ACCOUNTS_UPDATED }; #endif // _NOTIFY_MESSAGE_H diff --git a/application/Server.cpp b/application/Server.cpp index 335bad5..3f61d4f 100644 --- a/application/Server.cpp +++ b/application/Server.cpp @@ -34,6 +34,7 @@ #include "Flags.h" #include "ImageCache.h" #include "InviteDialogue.h" +#include "NotifyMessage.h" #include "ProtocolLooper.h" #include "ProtocolManager.h" #include "RosterItem.h" @@ -582,6 +583,8 @@ Server::ImMessage(BMessage* msg) ProtocolLooper* looper = _LooperFromMessage(msg); if (looper == NULL) break; + fAccountEnabled.AddItem(looper->Protocol()->GetName(), true); + // Ready notification if (AppPreferences::Item()->NotifyProtocolStatus == true) _ProtocolNotification(looper, BString(B_TRANSLATE("Connected")), @@ -616,16 +619,19 @@ Server::ImMessage(BMessage* msg) join.AddString("chat_id", fileName); looper->PostMessage(&join); } + + NotifyInteger(INT_ACCOUNTS_UPDATED, 0); break; } case IM_PROTOCOL_DISABLE: { int64 instance = 0; - if (msg->FindInt64("instance", &instance) != B_OK) { + if (msg->FindInt64("instance", &instance) != B_OK) result = B_SKIP_MESSAGE; - break; - } - RemoveProtocolLooper(instance); + else + RemoveProtocolLooper(instance); + + NotifyInteger(INT_ACCOUNTS_UPDATED, 0); break; } default: @@ -664,6 +670,7 @@ Server::AddProtocolLooper(bigtime_t instanceId, ChatProtocol* cayap) ProtocolLooper* looper = new ProtocolLooper(cayap, instanceId); fLoopers.AddItem(instanceId, looper); fAccounts.AddItem(cayap->GetName(), instanceId); + fAccountEnabled.AddItem(cayap->GetName(), false); } @@ -684,6 +691,7 @@ Server::RemoveProtocolLooper(bigtime_t instanceId) fLoopers.RemoveItemFor(instanceId); fAccounts.RemoveItemFor(looper->Protocol()->GetName()); + fAccountEnabled.AddItem(looper->Protocol()->GetName(), false); looper->Lock(); 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 Server::SendProtocolMessage(BMessage* msg) { diff --git a/application/Server.h b/application/Server.h index ebeea70..6d1c8ac 100644 --- a/application/Server.h +++ b/application/Server.h @@ -16,6 +16,7 @@ #include "ChatCommand.h" #include "Contact.h" #include "Conversation.h" +#include "Notifier.h" #include "ProtocolLooper.h" #include "User.h" @@ -26,9 +27,10 @@ class ProtocolLooper; typedef KeyMap ProtocolLoopers; typedef KeyMap AccountInstances; +typedef KeyMap BoolMap; -class Server: public BMessageFilter { +class Server: public BMessageFilter, public Notifier { public: Server(); void Quit(); @@ -43,8 +45,8 @@ public: void RemoveProtocolLooper(bigtime_t instanceId); ProtocolLooper* GetProtocolLooper(bigtime_t instanceId); - AccountInstances - GetAccounts(); + AccountInstances GetAccounts(); + AccountInstances GetActiveAccounts(); void SendProtocolMessage(BMessage* msg); void SendAllProtocolMessage(BMessage* msg); @@ -87,14 +89,12 @@ private: void _ReplicantStatusNotify(UserStatus status); ProtocolLoopers fLoopers; - AccountInstances - fAccounts; + AccountInstances fAccounts; + BoolMap fAccountEnabled; - CommandMap fCommands; - BObjectList - fChatItems; - BObjectList - fUserItems; + CommandMap fCommands; + BObjectList fChatItems; + BObjectList fUserItems; }; diff --git a/application/Utils.cpp b/application/Utils.cpp index 6544225..5cc7803 100644 --- a/application/Utils.cpp +++ b/application/Utils.cpp @@ -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* AccountsPath() { diff --git a/application/Utils.h b/application/Utils.h index 7c5f9a3..913967a 100644 --- a/application/Utils.h +++ b/application/Utils.h @@ -27,9 +27,6 @@ BString CommandArgs(BString line); BResources* ChatResources(); -BMenu* CreateAccountMenu(AccountInstances accounts, BMessage msg, - BMessage* allMsg = NULL); - const char* AccountsPath(); const char* AccountPath(const char* signature, const char* subsignature); diff --git a/application/views/AccountsMenu.cpp b/application/views/AccountsMenu.cpp new file mode 100644 index 0000000..9d90bda --- /dev/null +++ b/application/views/AccountsMenu.cpp @@ -0,0 +1,65 @@ +/* + * Copyright 2021, Jaidyn Levesque + * All rights reserved. Distributed under the terms of the MIT license. + */ + +#include "AccountsMenu.h" +#include "MainWindow.h" +#include "Server.h" +#include "TheApp.h" + +#include + + +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); +} diff --git a/application/views/AccountsMenu.h b/application/views/AccountsMenu.h new file mode 100644 index 0000000..2c1bfac --- /dev/null +++ b/application/views/AccountsMenu.h @@ -0,0 +1,27 @@ +/* + * Copyright 2021, Jaidyn Levesque + * All rights reserved. Distributed under the terms of the MIT license. + */ +#ifndef _ACCOUNTS_MENU_H +#define _ACCOUNTS_MENU_H + +#include + +#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 diff --git a/application/windows/RosterEditWindow.cpp b/application/windows/RosterEditWindow.cpp index c5dafc9..edc8723 100644 --- a/application/windows/RosterEditWindow.cpp +++ b/application/windows/RosterEditWindow.cpp @@ -20,6 +20,7 @@ #include #include +#include "AccountsMenu.h" #include "AppMessages.h" #include "AppPreferences.h" #include "ChatProtocolMessages.h" @@ -27,7 +28,6 @@ #include "RosterListView.h" #include "RosterView.h" #include "TemplateWindow.h" -#include "Utils.h" #undef B_TRANSLATION_CONTEXT @@ -47,7 +47,6 @@ RosterEditWindow* RosterEditWindow::fInstance = NULL; RosterEditWindow::RosterEditWindow(Server* server) : BWindow(BRect(0, 0, 300, 400), B_TRANSLATE("Roster"), B_FLOATING_WINDOW, 0), - fAccounts(server->GetAccounts()), fServer(server), fEditingWindow(NULL) { @@ -55,7 +54,7 @@ RosterEditWindow::RosterEditWindow(Server* server) fRosterView->SetInvocationMessage(new BMessage(kEditMember)); fAccountField = new BMenuField("accountMenuField", NULL, - CreateAccountMenu(fAccounts, BMessage(kSelAccount), + new AccountsMenu("accountMenu", BMessage(kSelAccount), new BMessage(kSelNoAccount))); font_height fontHeight; @@ -183,10 +182,12 @@ RosterEditWindow::MessageReceived(BMessage* message) } case kSelAccount: { + AccountInstances accounts = fServer->GetActiveAccounts(); + int index = message->FindInt32("index") - 1; - if (index < 0 || index > (fAccounts.CountItems() - 1)) + if (index < 0 || index > (accounts.CountItems() - 1)) return; - fRosterView->SetAccount(fAccounts.ValueAt(index)); + fRosterView->SetAccount(accounts.ValueAt(index)); break; } case kSelNoAccount: diff --git a/application/windows/RosterEditWindow.h b/application/windows/RosterEditWindow.h index 03dddd5..fbe7493 100644 --- a/application/windows/RosterEditWindow.h +++ b/application/windows/RosterEditWindow.h @@ -36,7 +36,6 @@ public: private: BMenuField* fAccountField; - AccountInstances fAccounts; BString fEditingUser; TemplateWindow* fEditingWindow; diff --git a/application/windows/RosterWindow.cpp b/application/windows/RosterWindow.cpp index 163c6dc..71152ab 100644 --- a/application/windows/RosterWindow.cpp +++ b/application/windows/RosterWindow.cpp @@ -18,10 +18,10 @@ #include #include +#include "AccountsMenu.h" #include "AppMessages.h" #include "AppPreferences.h" #include "ChatProtocolMessages.h" -#include "Utils.h" #include "RosterItem.h" #include "RosterListView.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), fTarget(messenger), fMessage(selectMsg), - fAccounts(server->GetAccounts()), fServer(server) { fRosterView = new RosterView("buddyView", server, instance), @@ -46,27 +45,31 @@ RosterWindow::RosterWindow(const char* title, BMessage* selectMsg, fOkButton = new BButton("OK", new BMessage(kSendMessage)); - BMenu* accountMenu; + AccountInstances accounts = fServer->GetActiveAccounts(); // If a specific instance is given, disallow selecting other accounts + // In fact, don't even bother populating with them if (instance > -1) { - accountMenu = new BMenu("accountMenu"); + BMenu* accountMenu = new BMenu("accountMenu"); + BString name = "N/A"; - for (int i = 0; i < fAccounts.CountItems(); i++) - if (fAccounts.ValueAt(i) == instance) { - name = fAccounts.KeyAt(i); + for (int i = 0; i < accounts.CountItems(); i++) + if (accounts.ValueAt(i) == instance) { + name = accounts.KeyAt(i); break; } accountMenu->AddItem(new BMenuItem(name.String(), NULL)); accountMenu->SetLabelFromMarked(true); accountMenu->ItemAt(0)->SetMarked(true); accountMenu->SetEnabled(false); + + fAccountField = new BMenuField("accountMenuField", NULL, accountMenu); } else - accountMenu = CreateAccountMenu(fAccounts, BMessage(kSelAccount), - new BMessage(kSelNoAccount)); + fAccountField = new BMenuField("accountMenuField", NULL, + new AccountsMenu("accountMenu", BMessage(kSelAccount), + new BMessage(kSelNoAccount))); - fAccountField = new BMenuField("accountMenuField", NULL, accountMenu); BLayoutBuilder::Group<>(this, B_VERTICAL, 0.0f) .SetInsets(B_USE_DEFAULT_SPACING) @@ -103,10 +106,12 @@ RosterWindow::MessageReceived(BMessage* message) } case kSelAccount: { + AccountInstances accounts = fServer->GetActiveAccounts(); + int index = message->FindInt32("index") - 1; - if (index < 0 || index > (fAccounts.CountItems() - 1)) + if (index < 0 || index > (accounts.CountItems() - 1)) return; - fRosterView->SetAccount(fAccounts.ValueAt(index)); + fRosterView->SetAccount(accounts.ValueAt(index)); break; } case kSelNoAccount: diff --git a/application/windows/RosterWindow.h b/application/windows/RosterWindow.h index 6e0a7c6..ae4856c 100644 --- a/application/windows/RosterWindow.h +++ b/application/windows/RosterWindow.h @@ -35,7 +35,6 @@ public: private: BButton* fOkButton; BMenuField* fAccountField; - AccountInstances fAccounts; Server* fServer; diff --git a/application/windows/TemplateWindow.cpp b/application/windows/TemplateWindow.cpp index 961e2bb..8ed3be6 100644 --- a/application/windows/TemplateWindow.cpp +++ b/application/windows/TemplateWindow.cpp @@ -18,8 +18,8 @@ #include #include +#include "AccountsMenu.h" #include "ChatProtocolMessages.h" -#include "Utils.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, B_NOT_RESIZABLE | B_AUTO_UPDATE_SIZE_LIMITS | B_CLOSE_ON_ESCAPE), fServer(server), - fAccounts(server->GetAccounts()), fSelectedAcc(0), fTemplate(NULL), fTemplateType(templateType), @@ -57,7 +56,6 @@ TemplateWindow::TemplateWindow(const char* title, ProtocolTemplate* temp, BWindow(BRect(0, 0, 400, 100), title, B_FLOATING_WINDOW, B_NOT_RESIZABLE | B_AUTO_UPDATE_SIZE_LIMITS | B_CLOSE_ON_ESCAPE), fServer(server), - fAccounts(server->GetAccounts()), fSelectedAcc(0), fTemplate(temp), fMessage(msg) @@ -100,8 +98,11 @@ TemplateWindow::MessageReceived(BMessage* msg) alert->Go(); break; } + + AccountInstances accounts = fServer->GetActiveAccounts(); ProtocolLooper* looper - = fServer->GetProtocolLooper(fAccounts.ValueAt(fSelectedAcc)); + = fServer->GetProtocolLooper(accounts.ValueAt(fSelectedAcc)); + if (looper == NULL) break; looper->PostMessage(settings); @@ -133,25 +134,36 @@ void TemplateWindow::_InitInterface(bigtime_t instance) { fTemplateView = new TemplateView("template"); - BMenu* menu = CreateAccountMenu(fAccounts, BMessage(kAccSelected)); - fMenuField = new BMenuField("accountMenuField", NULL, menu); + AccountInstances accounts = fServer->GetActiveAccounts(); if (instance > -1) { - for (int i = 0; i < fAccounts.CountItems(); i++) - if (fAccounts.ValueAt(i) == instance) { - menu->ItemAt(i)->SetMarked(true); + BMenu* accountMenu = new BMenu("accountMenu"); + BString name = "N/A"; + + for (int i = 0; i < accounts.CountItems(); i++) + if (accounts.ValueAt(i) == instance) { + name = accounts.KeyAt(i); 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)); - if (fAccounts.CountItems() <= 0) + if (accounts.CountItems() <= 0) fOkButton->SetEnabled(false); fOkButton->MakeDefault(true); const float spacing = be_control_look->DefaultItemSpacing(); + BLayoutBuilder::Group<>(this, B_VERTICAL) .SetInsets(B_USE_DEFAULT_SPACING) .Add(fTemplateView) @@ -169,11 +181,12 @@ TemplateWindow::_InitInterface(bigtime_t instance) void TemplateWindow::_LoadTemplate() { - if (fAccounts.CountItems() == 0 || fTemplateType.IsEmpty() == true) + AccountInstances accounts = fServer->GetActiveAccounts(); + if (accounts.CountItems() == 0 || fTemplateType.IsEmpty() == true) return; ProtocolLooper* looper - = fServer->GetProtocolLooper(fAccounts.ValueAt(fSelectedAcc)); + = fServer->GetProtocolLooper(accounts.ValueAt(fSelectedAcc)); if (looper == NULL) return; diff --git a/application/windows/TemplateWindow.h b/application/windows/TemplateWindow.h index 0ad38db..5403b6c 100644 --- a/application/windows/TemplateWindow.h +++ b/application/windows/TemplateWindow.h @@ -42,7 +42,6 @@ private: void _LoadTemplate(); Server* fServer; - AccountInstances fAccounts; int32 fSelectedAcc; BMenuField* fMenuField;