Room creation window; Catch-all template window

Explicit room-creation using protocol's own "room" template is now
supported.

Two new protocol API messages were added― IM_CREATE_ROOM and
IM_ROOM_CREATED, which are parallels to IM_CREATE_CHAT and
IM_CHAT_CREATED. Rather than the latter two, though, these are wholy
based on the "room" template― their slots are completely determined by
the protocol.

A generic "TemplateWindow" was created, which allows catch-all creation
of windows that leverage protocols' templates. It's used for the
room-creation window (Chat->New Room / Alt+N), for example.

At some point, it ideally should replace even the JoinRoom window, and
maybe others.
This commit is contained in:
Jaidyn Ann 2021-06-18 01:13:02 -05:00
parent 3fbe072d42
commit 7c002d8fcc
14 changed files with 304 additions and 78 deletions

View File

@ -20,8 +20,11 @@ const uint32 CAYA_CHAT = 'CYch';
//! Create a new chat
const uint32 CAYA_NEW_CHAT = 'CYnc';
//! Create a new chat
const uint32 CAYA_NEW_ROOM = 'CYnr';
//! Join a chat
const uint32 CAYA_JOIN_CHAT = 'CYjc';
const uint32 CAYA_JOIN_ROOM = 'CYjr';
//! Invite user to current chat
const uint32 CAYA_SEND_INVITE = 'CYin';

View File

@ -208,66 +208,76 @@ enum im_what_code {
// Requires: String "chat_id", String "user_id"
IM_CHAT_CREATED = 151,
//! Create a room →Protocol
// The required slots for this message are completely determined by the
// protocol itself― the protocol will just receive data from the
// "room" template (which is fetched via
// CayaProtocol::SettingsTemplate("room")
IM_CREATE_ROOM = 152,
//! Create a room →Caya
// Requires: String "chat_id"
IM_ROOM_CREATED = 153,
//! Join a room →Protocol
// Requires: String "chat_id"
IM_JOIN_ROOM = 152,
IM_JOIN_ROOM = 154,
//! Confirm the room's been joined →Caya
// Requires: String "chat_id"
IM_ROOM_JOINED = 153,
IM_ROOM_JOINED = 155,
//! User wants to leave the room →Protocol
// Requires: String "chat_id"
IM_LEAVE_ROOM = 154,
IM_LEAVE_ROOM = 156,
//! User left the room →Caya
// Requires: String "chat_id"
IM_ROOM_LEFT = 155,
IM_ROOM_LEFT = 157,
//! Request a room's userlist →Protocol
// Requires: String "chat_id"
IM_GET_ROOM_PARTICIPANTS = 156,
IM_GET_ROOM_PARTICIPANTS = 158,
//! Quietly add user(s) to the chat →Caya
// Shouldn't be sent automatically on joining a room.
// Requires: String "chat_id", StringList "user_id"
// Accepts: StringList "user_name"
IM_ROOM_PARTICIPANTS = 157,
IM_ROOM_PARTICIPANTS = 159,
//! User has explicitly joined →Caya
// Requires: String "chat_id", String "user_id"
// Accepts: String "body"
IM_ROOM_PARTICIPANT_JOINED = 158,
IM_ROOM_PARTICIPANT_JOINED = 160,
//! A user left the room →Caya
// Requires: String "chat_id", String "user_id"
// Accepts: String "user_name", String "body"
IM_ROOM_PARTICIPANT_LEFT = 159,
IM_ROOM_PARTICIPANT_LEFT = 161,
//! Invite a user to a room →Protocol
// You can tell it succeded with IM_ROOM_PARTICIPANT_JOINED.
// Requires: String "chat_id", String "user_id"
// Accepts: String "body"
IM_ROOM_SEND_INVITE = 160,
IM_ROOM_SEND_INVITE = 162,
//! Invitee explicitly refused →Caya
// Requires: String "chat_id", String "user_id"
// Accepts: String "user_name", String "body"
IM_ROOM_INVITE_REFUSED = 161,
IM_ROOM_INVITE_REFUSED = 163,
//! User was invited to a room →Caya
// Requires: String "chat_id"
// Accepts: String "user_id", String "chat_name", String "body"
IM_ROOM_INVITE_RECEIVED = 162,
IM_ROOM_INVITE_RECEIVED = 164,
//! User accepted an invite →Protocol
// Requires: String "chat_id"
IM_ROOM_INVITE_ACCEPT = 163,
IM_ROOM_INVITE_ACCEPT = 165,
//! User denies an invite →Protocol
// Requires: String "chat_id"
IM_ROOM_INVITE_REFUSE = 164,
IM_ROOM_INVITE_REFUSE = 166,
/*

View File

@ -53,7 +53,6 @@ SRCS = \
application/User.cpp \
application/preferences/AccountDialog.cpp \
application/preferences/AccountListItem.cpp \
application/preferences/AccountView.cpp \
application/preferences/CayaPreferences.cpp \
application/preferences/PreferencesChatWindow.cpp \
application/preferences/PreferencesAccounts.cpp \
@ -73,6 +72,7 @@ SRCS = \
application/views/SearchBarTextControl.cpp \
application/views/StatusMenuItem.cpp \
application/views/StatusView.cpp \
application/views/TemplateView.cpp \
application/views/UserItem.cpp \
application/views/UserListView.cpp \
application/views/UserPopUp.cpp \
@ -81,6 +81,7 @@ SRCS = \
application/windows/MainWindow.cpp \
application/windows/PreferencesWindow.cpp \
application/windows/RosterWindow.cpp \
application/windows/TemplateWindow.cpp \
application/windows/UserInfoWindow.cpp

View File

@ -24,7 +24,8 @@
ProtocolSettings::ProtocolSettings(CayaProtocolAddOn* addOn)
:
fTemplate(addOn, "account")
fTemplate(addOn->Protocol(), "account"),
fAddOn(addOn)
{
}
@ -39,7 +40,7 @@ ProtocolSettings::InitCheck() const
CayaProtocolAddOn*
ProtocolSettings::AddOn() const
{
return fTemplate.AddOn();
return fAddOn;
}
@ -48,8 +49,7 @@ ProtocolSettings::Accounts() const
{
BObjectList<BString> list(true);
BPath path(CayaAccountPath(AddOn()->Signature(),
AddOn()->ProtoSignature()));
BPath path(CayaAccountPath(fAddOn->Signature(), fAddOn->ProtoSignature()));
if (path.InitCheck() != B_OK)
return list;
@ -90,16 +90,16 @@ ProtocolSettings::Save(const char* account, BView* parent)
if (!parent)
debugger("Couldn't save protocol's settings GUI on a NULL parent!");
BMessage* settings = fTemplate.Save(parent);
BMessage settings;
status_t status = fTemplate.Save(parent, &settings);
if (!account || !settings)
if (!account || status != B_OK)
return B_BAD_VALUE;
status_t ret = B_ERROR;
// Find user's settings path
BPath path(CayaAccountPath(AddOn()->Signature(),
AddOn()->ProtoSignature()));
BPath path(CayaAccountPath(fAddOn->Signature(), fAddOn->ProtoSignature()));
if ((ret = path.InitCheck()) != B_OK)
return ret;
@ -107,7 +107,7 @@ ProtocolSettings::Save(const char* account, BView* parent)
// Load settings file
path.Append(account);
BFile file(path.Path(), B_CREATE_FILE | B_ERASE_FILE | B_WRITE_ONLY);
return settings->Flatten(&file);
return settings.Flatten(&file);
}
@ -117,8 +117,7 @@ ProtocolSettings::Rename(const char* from, const char* to)
status_t ret = B_ERROR;
// Find user's settings path
BPath path(CayaAccountPath(AddOn()->Signature(),
AddOn()->ProtoSignature()));
BPath path(CayaAccountPath(fAddOn->Signature(), fAddOn->ProtoSignature()));
if ((ret = path.InitCheck()) != B_OK)
return ret;
@ -140,8 +139,7 @@ ProtocolSettings::Delete(const char* account)
status_t ret = B_ERROR;
// Find user's settings path
BPath path(CayaAccountPath(AddOn()->Signature(),
AddOn()->ProtoSignature()));
BPath path(CayaAccountPath(fAddOn->Signature(), fAddOn->ProtoSignature()));
if ((ret = path.InitCheck()) != B_OK)
return ret;
@ -168,8 +166,7 @@ ProtocolSettings::_Load(const char* account, BMessage** settings)
status_t ret = B_ERROR;
// Find user's settings path
BPath path(CayaAccountPath(AddOn()->Signature(),
AddOn()->ProtoSignature()));
BPath path(CayaAccountPath(fAddOn->Signature(), fAddOn->ProtoSignature()));
if ((ret = path.InitCheck()) != B_OK)
return ret;

View File

@ -33,6 +33,7 @@ public:
private:
status_t _Load(const char* account, BMessage** settings);
CayaProtocolAddOn* fAddOn;
ProtocolTemplate fTemplate;
status_t fStatus;
};

View File

@ -32,13 +32,13 @@
const float kDividerWidth = 1.0f;
ProtocolTemplate::ProtocolTemplate(CayaProtocolAddOn* addOn, const char* type)
ProtocolTemplate::ProtocolTemplate(CayaProtocol* protocol, const char* type)
:
fAddOn(addOn),
fProtocol(protocol),
fTemplate(new BMessage())
{
// Load protocol's settings template
BMessage settingsTemplate = fAddOn->Protocol()->SettingsTemplate(type);
BMessage settingsTemplate = fProtocol->SettingsTemplate(type);
*fTemplate = settingsTemplate;
}
@ -49,10 +49,10 @@ ProtocolTemplate::~ProtocolTemplate()
}
CayaProtocolAddOn*
ProtocolTemplate::AddOn() const
CayaProtocol*
ProtocolTemplate::Protocol() const
{
return fAddOn;
return fProtocol;
}
@ -227,14 +227,12 @@ ProtocolTemplate::Load(BView* parent, BMessage* settings)
}
BMessage*
ProtocolTemplate::Save(BView* parent)
status_t
ProtocolTemplate::Save(BView* parent, BMessage* settings)
{
if (!parent)
debugger("Couldn't save protocol's settings GUI on a NULL parent!");
BMessage* settings = new BMessage();
BMessage cur;
for (int32 i = 0; fTemplate->FindMessage("setting", i, &cur) == B_OK; i++) {
const char* name = cur.FindString("name");
@ -262,7 +260,7 @@ ProtocolTemplate::Save(BView* parent)
settings->AddInt32(name, atoi(textControl->Text()));
break;
default:
return NULL;
return B_ERROR;
}
}
@ -271,7 +269,7 @@ ProtocolTemplate::Save(BView* parent)
if (menuField) {
BMenuItem* item = menuField->Menu()->FindMarked();
if (!item)
return NULL;
return B_ERROR;
switch (type) {
case B_STRING_TYPE:
@ -281,7 +279,7 @@ ProtocolTemplate::Save(BView* parent)
settings->AddInt32(name, atoi(item->Label()));
break;
default:
return NULL;
return B_ERROR;
}
}
@ -296,5 +294,5 @@ ProtocolTemplate::Save(BView* parent)
settings->AddString(name, textView->Text());
}
return settings;
return B_OK;
}

View File

@ -11,23 +11,23 @@
class BMessage;
class BView;
class CayaProtocolAddOn;
class CayaProtocol;
class ProtocolTemplate {
public:
ProtocolTemplate(CayaProtocolAddOn* addOn,
ProtocolTemplate(CayaProtocol* protocol,
const char* type);
~ProtocolTemplate();
status_t InitCheck() const;
CayaProtocolAddOn* AddOn() const;
CayaProtocol* Protocol() const;
status_t Load(BView* parent, BMessage* settings = NULL);
BMessage* Save(BView* parent);
status_t Save(BView* parent, BMessage* settings);
private:
CayaProtocolAddOn* fAddOn;
CayaProtocol* fProtocol;
BMessage* fTemplate;
};

View File

@ -16,8 +16,8 @@
#include <libinterface/Divider.h>
#include "AccountDialog.h"
#include "AccountView.h"
#include "ProtocolSettings.h"
#include "TemplateView.h"
const uint32 kCancel = 'canc';
const uint32 kOK = 'save';
@ -40,7 +40,7 @@ AccountDialog::AccountDialog(const char* title, ProtocolSettings* settings,
Divider* divider = new Divider("divider", B_WILL_DRAW);
fTop = new AccountView("top");
fTop = new TemplateView("top");
if (fAccount.Length() > 0)
fSettings->Load(fAccount.String(), fTop);
else

View File

@ -10,8 +10,8 @@
class BTextControl;
class AccountView;
class ProtocolSettings;
class TemplateView;
const uint32 kAccountAdded = 'acad';
const uint32 kAccountRenamed = 'acrd';
@ -29,7 +29,7 @@ public:
private:
ProtocolSettings* fSettings;
BString fAccount;
AccountView* fTop;
TemplateView* fTop;
BTextControl* fAccountName;
BHandler* fTarget;
};

View File

@ -6,6 +6,8 @@
* Pier Luigi Fiorini, pierluigi.fiorini@gmail.com
*/
#include "TemplateView.h"
#include <Button.h>
#include <ControlLook.h>
#include <CheckBox.h>
@ -20,17 +22,15 @@
#include <libinterface/NotifyingTextView.h>
#include "AccountView.h"
AccountView::AccountView(const char* name)
TemplateView::TemplateView(const char* name)
: BView(name, B_WILL_DRAW)
{
}
void
AccountView::AttachedToWindow()
TemplateView::AttachedToWindow()
{
// Once we are attached to window, the GUI is already created
// so we can set our window as target for messages

View File

@ -2,18 +2,20 @@
* Copyright 2009-2010, Pier Luigi Fiorini. All rights reserved.
* Distributed under the terms of the MIT License.
*/
#ifndef _ACCOUNT_VIEW_H
#define _ACCOUNT_VIEW_H
#ifndef _TEMPLATE_VIEW_H
#define _TEMPLATE_VIEW_H
#include <View.h>
const uint32 kChanged = 'CHGD';
class AccountView : public BView {
class TemplateView : public BView {
public:
AccountView(const char* name);
TemplateView(const char* name);
virtual void AttachedToWindow();
};
#endif // _ACCOUNT_VIEW_H
#endif // _TEMPLATE_VIEW_H

View File

@ -34,6 +34,7 @@
#include "RosterWindow.h"
#include "Server.h"
#include "StatusView.h"
#include "TemplateWindow.h"
const uint32 kLogin = 'LOGI';
@ -111,7 +112,6 @@ MainWindow::MessageReceived(BMessage* message)
win->Show();
break;
}
case CAYA_NEW_CHAT:
{
BMessage* newMsg = new BMessage(IM_MESSAGE);
@ -122,15 +122,23 @@ MainWindow::MessageReceived(BMessage* message)
fRosterWindow->Show();
break;
}
case CAYA_NEW_ROOM:
{
BMessage* createMsg = new BMessage(IM_MESSAGE);
createMsg->AddInt32("im_what", IM_CREATE_ROOM);
case CAYA_JOIN_CHAT:
TemplateWindow* win = new TemplateWindow("Create room",
"room", createMsg, fServer);
win->Show();
break;
}
case CAYA_JOIN_ROOM:
{
JoinWindow* win = new JoinWindow(new BMessenger(this),
fServer->GetAccounts());
win->Show();
break;
}
case CAYA_SEND_INVITE:
{
if (fConversation == NULL)
@ -148,7 +156,6 @@ MainWindow::MessageReceived(BMessage* message)
fRosterWindow->Show();
break;
}
case CAYA_MOVE_UP:
{
if (fConversation == NULL)
@ -159,7 +166,6 @@ MainWindow::MessageReceived(BMessage* message)
fListView->SelectConversation(index - 1);
break;
}
case CAYA_MOVE_DOWN:
{
if (fConversation == NULL)
@ -171,7 +177,6 @@ MainWindow::MessageReceived(BMessage* message)
fListView->SelectConversation(index + 1);
break;
}
case CAYA_REPLICANT_STATUS_SET:
{
int32 status;
@ -180,7 +185,6 @@ MainWindow::MessageReceived(BMessage* message)
accountManager->SetStatus((CayaStatus)status);
break;
}
case CAYA_REPLICANT_SHOW_WINDOW:
{
if (LockLooper()) {
@ -199,7 +203,6 @@ MainWindow::MessageReceived(BMessage* message)
}
break;
}
case CAYA_CHAT:
{
message->AddString("body", fSendView->Text());
@ -207,11 +210,9 @@ MainWindow::MessageReceived(BMessage* message)
fSendView->SetText("");
break;
}
case CAYA_DISABLE_ACCOUNT:
_ToggleMenuItems();
break;
case IM_MESSAGE:
ImMessage(message);
break;
@ -221,7 +222,6 @@ MainWindow::MessageReceived(BMessage* message)
case B_ABOUT_REQUESTED:
be_app->PostMessage(message);
break;
default:
BWindow::MessageReceived(message);
}
@ -452,14 +452,14 @@ MainWindow::_CreateMenuBar()
// Chat
BMenu* chatMenu = new BMenu("Chat");
BMenuItem* joinRoom = new BMenuItem("Join room" B_UTF8_ELLIPSIS,
new BMessage(CAYA_JOIN_CHAT), 'J', B_COMMAND_KEY);
new BMessage(CAYA_JOIN_ROOM), 'J', B_COMMAND_KEY);
BMenuItem* invite = new BMenuItem("Invite user" B_UTF8_ELLIPSIS,
new BMessage(CAYA_SEND_INVITE), 'I', B_COMMAND_KEY);
BMenuItem* newChat = new BMenuItem("New chat" B_UTF8_ELLIPSIS,
new BMessage(CAYA_NEW_CHAT), 'M', B_COMMAND_KEY);
BMenuItem* newRoom = new BMenuItem("New room" B_UTF8_ELLIPSIS,
new BMessage(), 'N', B_COMMAND_KEY);
new BMessage(CAYA_NEW_ROOM), 'N', B_COMMAND_KEY);
chatMenu->AddItem(joinRoom);
chatMenu->AddSeparatorItem();
@ -524,5 +524,3 @@ MainWindow::_EnsureConversationItem(BMessage* msg)
return NULL;
}

View File

@ -0,0 +1,164 @@
/*
* Copyright 2009-2010, 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 "TemplateWindow.h"
#include <Alert.h>
#include <Button.h>
#include <ControlLook.h>
#include <LayoutBuilder.h>
#include <TextControl.h>
#include <String.h>
#include "TemplateView.h"
const uint32 kCancel = 'canc';
const uint32 kOK = 'save';
const uint32 kAccSelected = 'JWas';
TemplateWindow::TemplateWindow(const char* title, const char* templateType,
BMessage* msg, Server* server)
:
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),
fMessage(msg),
fTarget(NULL)
{
_InitInterface();
_LoadTemplate();
CenterOnScreen();
}
void
TemplateWindow::MessageReceived(BMessage* msg)
{
switch (msg->what) {
case kAccSelected:
{
int32 index;
if (msg->FindInt32("index", &index) == B_OK)
fSelectedAcc = index;
_LoadTemplate();
break;
}
case kOK: {
// Save account settings
if (fTemplate == NULL || fTemplateView == NULL)
break;
BMessage* settings = new BMessage(*fMessage);
status_t result = fTemplate->Save(fTemplateView, settings);
if (result != B_OK) {
BAlert* alert = new BAlert("", "Invalid settings― make sure "
"each item is filled out.\n", "OK", NULL, NULL);
alert->Go();
break;
}
ProtocolLooper* looper
= fServer->GetProtocolLooper(fAccounts.ValueAt(fSelectedAcc));
if (looper == NULL)
break;
looper->PostMessage(settings);
Close();
break;
}
case kCancel:
Close();
break;
case kChanged:
break;
default:
BWindow::MessageReceived(msg);
}
}
void
TemplateWindow::SetTarget(BHandler* target)
{
fTarget = target;
}
void
TemplateWindow::_InitInterface()
{
fTemplateView = new TemplateView("template");
fMenuField = new BMenuField("accountMenuField", NULL, _CreateAccountMenu());
BButton* cancel = new BButton("Cancel", new BMessage(kCancel));
BButton* fOkButton = new BButton("OK", new BMessage(kOK));
if (fAccounts.CountItems() <= 0)
fOkButton->SetEnabled(false);
const float spacing = be_control_look->DefaultItemSpacing();
BLayoutBuilder::Group<>(this, B_VERTICAL)
.Add(fTemplateView)
.AddGroup(B_HORIZONTAL)
.Add(fMenuField)
.AddGlue()
.Add(cancel)
.Add(fOkButton)
.End()
.AddGlue()
.SetInsets(spacing, spacing, spacing, 0);
}
void
TemplateWindow::_LoadTemplate()
{
if (fAccounts.CountItems() == 0)
return;
// fOkButton->SetEnabled(true);
ProtocolLooper* looper
= fServer->GetProtocolLooper(fAccounts.ValueAt(fSelectedAcc));
if (looper == NULL)
return;
fTemplate = new ProtocolTemplate(looper->Protocol(), fTemplateType.String());
for (int i = 0; fTemplateView->CountChildren(); i++)
fTemplateView->RemoveChild(fTemplateView->ChildAt(i));
fTemplate->Load(fTemplateView);
}
BMenu*
TemplateWindow::_CreateAccountMenu()
{
BMenu* menu = new BMenu("accountMenu");
for (int i = 0; i < fAccounts.CountItems(); i++)
menu->AddItem(new BMenuItem(fAccounts.KeyAt(i).String(),
new BMessage(kAccSelected)));
menu->SetRadioMode(true);
menu->SetLabelFromMarked(true);
menu->ItemAt(fSelectedAcc)->SetMarked(true);
if (fAccounts.CountItems() == 0)
menu->SetEnabled(false);
return menu;
}

View File

@ -0,0 +1,52 @@
/*
* Copyright 2009-2010, Pier Luigi Fiorini. All rights reserved.
* Copyright 2021, Jaidyn Levesque. All rights reserved.
* Distributed under the terms of the MIT License.
*/
#ifndef _TEMPLATE_WINDOW_H
#define _TEMPLATE_WINDOW_H
#include <String.h>
#include <Window.h>
#include "ProtocolTemplate.h"
#include "Server.h"
class BMenu;
class BMenuField;
class BTextControl;
class ProtocolSettings;
class TemplateView;
class TemplateWindow : public BWindow {
public:
TemplateWindow(const char* title,
const char* templateType, BMessage* msg,
Server* server);
virtual void MessageReceived(BMessage* msg);
void SetTarget(BHandler* target);
private:
void _InitInterface();
void _LoadTemplate();
BMenu* _CreateAccountMenu();
Server* fServer;
AccountInstances fAccounts;
int32 fSelectedAcc;
BMenuField* fMenuField;
ProtocolTemplate* fTemplate;
BString fTemplateType;
TemplateView* fTemplateView;
BButton* fOkButton;
BMessage* fMessage;
BHandler* fTarget;
};
#endif // _TEMPLATE_WINDOW_H