Compare commits

..

No commits in common. "master" and "v0.0.1" have entirely different histories.

234 changed files with 2374 additions and 2726 deletions

View File

@ -1,2 +0,0 @@
APP_NAME ?= Chat-O-Matic
APP_SIGNATURE ?= application/x-vnd.chat-o-matic

View File

@ -12,9 +12,6 @@ irc:
xmpp: xmpp:
$(MAKE) -f protocols/xmpp/Makefile $(MAKE) -f protocols/xmpp/Makefile
matrix:
$(MAKE) -f protocols/matrix/Makefile
purple: purple:
ifneq ($(shell uname -m), x86_gcc2) ifneq ($(shell uname -m), x86_gcc2)
$(MAKE) -f protocols/purple/Makefile $(MAKE) -f protocols/purple/Makefile

View File

@ -2,8 +2,6 @@ LIBPATHS = $(OBJ_DIR)
PROTOCOL_DIR = $(OBJ_DIR)/chat-o-matic/ PROTOCOL_DIR = $(OBJ_DIR)/chat-o-matic/
DEBUG_ENABLED ?= false DEBUG_ENABLED ?= false
DEFINES = VERSION="\"0.0.2\"" \ DEFINES := VERSION="\"0.0.2\"" \
BUILD_DATE="\"$(shell date +"%Y-%m-%d %H:%M")\"" \ BUILD_DATE="\"$(shell date +"%Y-%m-%d %H:%M")\"" \
DEBUG_ENABLED=$(DEBUG_ENABLED) \ DEBUG_ENABLED=$(DEBUG_ENABLED)
APP_NAME="\"$(APP_NAME)"\" \
APP_SIGNATURE="\"$(APP_SIGNATURE)"\"

View File

@ -14,8 +14,6 @@ Protocols natively supported include IRC and XMPP.
Protocols generally supported through libpurple include GroupWise, Zephyr, and Protocols generally supported through libpurple include GroupWise, Zephyr, and
[others through plugins](https://pidgin.im/plugins/?type=Protocol). [others through plugins](https://pidgin.im/plugins/?type=Protocol).
You can find the user documentation [here](http://htmlpreview.github.io/?https://github.com/JadedCtrl/Chat-O-Matic/master/documentation/Documentation.html).
## Building ## Building
You can make Chat-O-Matic and its protocols with: You can make Chat-O-Matic and its protocols with:

View File

@ -31,13 +31,11 @@ Account::Account(bigtime_t instanceId, ChatProtocol* cayap,
fProtocol->Init(this); fProtocol->Init(this);
// Find user's settings path // Find user's settings path
BPath path = AccountPath(addOnSignature, fProtocol->Signature()); BPath path(AccountPath(addOnSignature, fProtocol->Signature()));
if (path.InitCheck() == B_OK) { if (path.InitCheck() == B_OK) {
path.Append(name); path.Append(name);
fProtocol->SetName(name); fProtocol->SetName(name);
fProtocol->SetAccountCachePath(AccountCachePath(name));
fProtocol->SetAddOnCachePath(AddOnCachePath(addOnSignature));
// Load settings file // Load settings file
BFile file(path.Path(), B_READ_ONLY); BFile file(path.Path(), B_READ_ONLY);

View File

@ -8,9 +8,6 @@
//! Show settings window //! Show settings window
const uint32 APP_SHOW_SETTINGS = 'RPST'; const uint32 APP_SHOW_SETTINGS = 'RPST';
//! Show documentation
const uint32 APP_SHOW_HELP = 'Rhlp';
//! Show accounts window //! Show accounts window
const uint32 APP_SHOW_ACCOUNTS = 'RPac'; const uint32 APP_SHOW_ACCOUNTS = 'RPac';
@ -26,9 +23,6 @@ const uint32 APP_NEW_ROOM = 'CYnr';
//! Join a chat //! Join a chat
const uint32 APP_JOIN_ROOM = 'CYjr'; const uint32 APP_JOIN_ROOM = 'CYjr';
//! Room directory
const uint32 APP_ROOM_DIRECTORY = 'CYrd';
//! Invite user to current chat //! Invite user to current chat
const uint32 APP_SEND_INVITE = 'CYin'; const uint32 APP_SEND_INVITE = 'CYin';
@ -65,9 +59,6 @@ const uint32 APP_USER_INFO = 'CYuw';
//! Display a "room info" window //! Display a "room info" window
const uint32 APP_ROOM_INFO = 'CYrw'; const uint32 APP_ROOM_INFO = 'CYrw';
//! Open the room's logs with TextSearch
const uint32 APP_ROOM_SEARCH = 'CYrs';
//! Toggle a specific flag for a room //! Toggle a specific flag for a room
const uint32 APP_ROOM_FLAG = 'Rlag'; const uint32 APP_ROOM_FLAG = 'Rlag';

View File

@ -10,9 +10,7 @@
#include "Conversation.h" #include "Conversation.h"
#include "MainWindow.h" #include "MainWindow.h"
#include "ProtocolLooper.h"
#include "TheApp.h" #include "TheApp.h"
#include "User.h"
#undef B_TRANSLATION_CONTEXT #undef B_TRANSLATION_CONTEXT

View File

@ -12,11 +12,10 @@
#include <libsupport/KeyMap.h> #include <libsupport/KeyMap.h>
#include <libsupport/List.h> #include <libsupport/List.h>
#include "Maps.h"
class Conversation; class Conversation;
class User; class User;
typedef KeyMap<BString, User*> UserMap;
enum cmd_arg_type enum cmd_arg_type
@ -62,4 +61,7 @@ private:
List<int32> fArgTypes; List<int32> fArgTypes;
}; };
typedef KeyMap<BString, ChatCommand*> CommandMap;
#endif // CHAT_COMMAND_H #endif // CHAT_COMMAND_H

11
application/ChatOMatic.h Normal file
View File

@ -0,0 +1,11 @@
/*
* Copyright 2009-2011, Andrea Anzani. All rights reserved.
* Distributed under the terms of the MIT License.
*/
#ifndef _APP_H
#define _APP_H
#define APP_SIGNATURE "application/x-vnd.chat-o-matic"
#define APP_NAME "Chat-O-Matic"
#endif // _APP_H

View File

@ -1,3 +1,5 @@
#include "ChatOMatic.h"
resource app_signature APP_SIGNATURE; resource app_signature APP_SIGNATURE;
resource app_version { resource app_version {
@ -16,18 +18,3 @@ resource app_flags B_SINGLE_LAUNCH;
resource file_types message; resource file_types message;
resource vector_icon {
$"6E636966040500020106033D835C3C19B2BA8B0B3C20794769624A510E00FFFF"
$"FFB4FFE405FFFFA405020106023D835C3C19B2BA8B0B3C20794769624A510E00"
$"FFE405FFFFA405020106033D429E3C5148BB5ADA3C5C1B4A23AA46EC1800FFFF"
$"FFB47FE583FF04B10C0902093F404644383C273F2E3A244122482245224D2755"
$"245126572256245725582A5828592C5A315C2F5B345D3C5E385E425E4957475C"
$"4D4E02043F4044433D3FBC95BE953B3D333D3D493844424E4A5148534A4A0403"
$"3B2F4E2F4E2D4E2A4D2F532D522F530003334F334F364F345337533755325636"
$"59325602085645C8FEC3AFCA30C0E55E3A5E405EBA4D52B58359B71B4AB38537"
$"B51D3EB31FBA16B69933353130363E4A4641444D475346C657C27B554BCB01C6"
$"35584F5A4F080239BA0539BA6B0802BD1CBC1DBD2FBCA908023E37423904032E"
$"4535473C4739473F4540070A000100123FFFFE2FDACEAFDACE3FFFFE3AB6A5B8"
$"4CC101178400040A010100000A020101000A000202031001178210040A000104"
$"1001178400040A030104000A000407050608100117821004"
};

View File

@ -88,11 +88,9 @@ public:
//! Protocol icon //! Protocol icon
virtual BBitmap* Icon() const { return NULL; } virtual BBitmap* Icon() const { return NULL; }
//! Pertinent paths //! Add-on's path
virtual BPath AddOnPath() = 0;
virtual void SetAddOnPath(BPath path) = 0; virtual void SetAddOnPath(BPath path) = 0;
virtual void SetAccountCachePath(BPath path) { }; virtual BPath AddOnPath() = 0;
virtual void SetAddOnCachePath(BPath path) { };
//! Name of account file (leaf) //! Name of account file (leaf)
virtual const char* GetName() = 0; virtual const char* GetName() = 0;

View File

@ -27,13 +27,6 @@ ChatProtocolAddOn::ChatProtocolAddOn(image_id image, const char* path, int32 sub
} }
ChatProtocolAddOn::~ChatProtocolAddOn()
{
delete fIcon;
unload_add_on(fImage);
}
status_t status_t
ChatProtocolAddOn::InitCheck() const ChatProtocolAddOn::InitCheck() const
{ {
@ -59,7 +52,7 @@ ChatProtocol*
ChatProtocolAddOn::ProtocolAt(int32 i) const ChatProtocolAddOn::ProtocolAt(int32 i) const
{ {
ChatProtocol* proto = fGetProtocol(i); ChatProtocol* proto = fGetProtocol(i);
proto->SetAddOnPath(fPath.String()); proto->SetAddOnPath(BPath(fPath.String()));
return proto; return proto;
} }

View File

@ -17,7 +17,6 @@ class ChatProtocolAddOn {
public: public:
ChatProtocolAddOn(image_id image, const char* path, ChatProtocolAddOn(image_id image, const char* path,
int32 subProto=0); int32 subProto=0);
~ChatProtocolAddOn();
status_t InitCheck() const; status_t InitCheck() const;

View File

@ -262,8 +262,8 @@ enum im_what_code {
/*! Quietly add user(s) to the chat →App /*! Quietly add user(s) to the chat →App
Shouldn't be sent automatically on joining a room. Shouldn't be sent automatically on joining a room.
Requires: String "chat_id", Strings "user_id" Requires: String "chat_id", StringList "user_id"
Accepts: Strings "user_name" */ Accepts: StringList "user_name" */
IM_ROOM_PARTICIPANTS = 159, IM_ROOM_PARTICIPANTS = 159,
/*! User has explicitly joined →App /*! User has explicitly joined →App
@ -405,29 +405,6 @@ enum im_what_code {
IM_ROOM_PARTICIPANT_STOPPED_TYPING = 211, IM_ROOM_PARTICIPANT_STOPPED_TYPING = 211,
/*
* Room directory messages
*/
/*! Request a list of rooms →Protocol */
IM_GET_ROOM_DIRECTORY = 230,
/*! Send a room in the directory →App
This can be used to send either a list of publically available rooms
or a list of "hidden"/"disabled" rooms, one-by-one.
A room listed thanks to this message might be joined through
IM_JOIN_ROOM. Since IM_JOIN_ROOM accepts slots from the template, you
must fill in IM_ROOM_DIRECTORY messages with any required custom slots
you use for room-joining the message you send will be actually be
copied and sent back verbatim (with im_what changed to IM_JOIN_ROOM)
to join.
Requires: Strings "chat_id"
Allows: String "chat_name", String "subject", String "category",
int32 "user_count" */
IM_ROOM_DIRECTORY = 231,
/* /*
* Misc. UI messages * Misc. UI messages
*/ */

View File

@ -35,5 +35,8 @@ Contact::_EnsureCachePath()
{ {
if (fCachePath.InitCheck() == B_OK) if (fCachePath.InitCheck() == B_OK)
return; return;
fCachePath = ContactCachePath(fLooper->Protocol()->GetName(), fID.String()); fCachePath.SetTo(ContactCachePath(fLooper->Protocol()->GetName(),
fID.String()));
} }

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2021-2022, Jaidyn Levesque <jadedctrl@teknik.io> * Copyright 2021, Jaidyn Levesque <jadedctrl@teknik.io>
* All rights reserved. Distributed under the terms of the MIT license. * All rights reserved. Distributed under the terms of the MIT license.
*/ */
@ -14,6 +14,7 @@
#include "AppConstants.h" #include "AppConstants.h"
#include "AppPreferences.h" #include "AppPreferences.h"
#include "ChatOMatic.h"
#include "ChatProtocolMessages.h" #include "ChatProtocolMessages.h"
#include "RenderView.h" #include "RenderView.h"
#include "ChatCommand.h" #include "ChatCommand.h"
@ -25,7 +26,6 @@
#include "NotifyMessage.h" #include "NotifyMessage.h"
#include "ProtocolLooper.h" #include "ProtocolLooper.h"
#include "ProtocolManager.h" #include "ProtocolManager.h"
#include "Role.h"
#include "Server.h" #include "Server.h"
#include "TheApp.h" #include "TheApp.h"
#include "Utils.h" #include "Utils.h"
@ -147,10 +147,10 @@ Conversation::ImMessage(BMessage* msg)
// Misc. features Caya contributors planned on adding // Misc. features Caya contributors planned on adding
BWindow* mainWin = ((TheApp*)be_app)->GetMainWindow(); BWindow* mainWin = ((TheApp*)be_app)->GetMainWindow();
if (winFocus == false && AppPreferences::Get()->MarkUnreadWindow == true) if (win == NULL && AppPreferences::Get()->MarkUnreadWindow == true)
mainWin->SetTitle(BString(mainWin->Title()).Prepend("[!]")); mainWin->SetTitle(BString(mainWin->Title()).Prepend("[!]"));
if (winFocus == false && AppPreferences::Get()->MoveToCurrentWorkspace) if (win == NULL && AppPreferences::Get()->MoveToCurrentWorkspace)
mainWin->SetWorkspaces(B_CURRENT_WORKSPACE); mainWin->SetWorkspaces(B_CURRENT_WORKSPACE);
if (win == NULL && AppPreferences::Get()->RaiseOnMessageReceived) if (win == NULL && AppPreferences::Get()->RaiseOnMessageReceived)
@ -158,9 +158,9 @@ Conversation::ImMessage(BMessage* msg)
// If unattached, highlight the ConversationItem // If unattached, highlight the ConversationItem
if ((win == NULL || GetView()->IsHidden() == true) && mentioned == true) if (win == NULL && mentioned == true)
NotifyInteger(INT_NEW_MENTION, fNotifyMentionCount); NotifyInteger(INT_NEW_MENTION, fNotifyMentionCount);
else if (win == NULL || GetView()->IsHidden()) else if (win == NULL)
NotifyInteger(INT_NEW_MESSAGE, fNotifyMessageCount); NotifyInteger(INT_NEW_MESSAGE, fNotifyMessageCount);
break; break;
@ -187,7 +187,7 @@ Conversation::ImMessage(BMessage* msg)
BString name = CommandName(body); BString name = CommandName(body);
BString args = CommandArgs(body); BString args = CommandArgs(body);
ChatCommand* cmd = Server::Get()->CommandById(name, fLooper->GetInstance()); ChatCommand* cmd = _GetServer()->CommandById(name, fLooper->GetInstance());
if (cmd == NULL) { if (cmd == NULL) {
if (name == "me") if (name == "me")
@ -320,7 +320,7 @@ Conversation::ObserveString(int32 what, BString str)
void void
Conversation::ObserveInteger(int32 what, int32 value) Conversation::ObserveInteger(int32 what, int32 value)
{ {
if (what == INT_CONV_VIEW_SELECTED) { if (what == INT_WINDOW_FOCUSED) {
fNotifyMessageCount = 0; fNotifyMessageCount = 0;
fNotifyMentionCount = 0; fNotifyMentionCount = 0;
} }
@ -576,10 +576,6 @@ Conversation::_LogChatMessage(BMessage* msg)
BFile logFile(fCachePath.Path(), B_READ_WRITE | B_OPEN_AT_END | B_CREATE_FILE); BFile logFile(fCachePath.Path(), B_READ_WRITE | B_OPEN_AT_END | B_CREATE_FILE);
WriteAttributeMessage(&logFile, "Chat:logs", &logMsg); WriteAttributeMessage(&logFile, "Chat:logs", &logMsg);
BString mime = BString("text/plain");
logFile.WriteAttr("BEOS:TYPE", B_MIME_STRING_TYPE, 0, mime.String(),
mime.CountChars() + 1);
// Plain-text logs // Plain-text logs
// Gotta make sure the formatting's pretty! // Gotta make sure the formatting's pretty!
BString date; BString date;
@ -637,7 +633,8 @@ Conversation::_EnsureCachePath()
{ {
if (fCachePath.InitCheck() == B_OK) if (fCachePath.InitCheck() == B_OK)
return; return;
fCachePath = RoomCachePath(fLooper->Protocol()->GetName(), fID.String()); fCachePath.SetTo(RoomCachePath(fLooper->Protocol()->GetName(),
fID.String()));
} }
@ -656,7 +653,7 @@ Conversation::_EnsureUser(BMessage* msg, bool implicit)
user = serverUser; user = serverUser;
// Not anywhere; create user // Not anywhere; create user
else if (user == NULL) { else if (user == NULL) {
user = new User(id, Server::Get()->Looper()); user = new User(id, _GetServer()->Looper());
user->SetProtocolLooper(fLooper); user->SetProtocolLooper(fLooper);
fLooper->AddUser(user); fLooper->AddUser(user);
} }
@ -760,3 +757,10 @@ Conversation::_SortConversationList()
if (fUsers.CountItems() <= 2 || fUsers.CountItems() == 3) if (fUsers.CountItems() <= 2 || fUsers.CountItems() == 3)
((TheApp*)be_app)->GetMainWindow()->SortConversation(this); ((TheApp*)be_app)->GetMainWindow()->SortConversation(this);
} }
Server*
Conversation::_GetServer()
{
return ((TheApp*)be_app)->GetMainWindow()->GetServer();
}

View File

@ -10,18 +10,22 @@
#include <Path.h> #include <Path.h>
#include <StringList.h> #include <StringList.h>
#include "Maps.h" #include <libsupport/KeyMap.h>
#include "Notifier.h"
#include "Observer.h" #include "Observer.h"
#include "Role.h"
#include "Server.h"
#include "User.h"
class BBitmap; class BBitmap;
class Contact;
class ConversationItem; class ConversationItem;
class ConversationView; class ConversationView;
class ProtocolLooper; class ProtocolLooper;
class Role;
class Server; class Server;
class User;
typedef KeyMap<BString, User*> UserMap;
typedef KeyMap<BString, Role*> RoleMap;
class Conversation : public Notifier, public Observer { class Conversation : public Notifier, public Observer {
@ -72,11 +76,7 @@ public:
void SetFlags(int32 flags); void SetFlags(int32 flags);
int32 DisallowedFlags() { return fDisallowedFlags; } int32 DisallowedFlags() { return fDisallowedFlags; }
BPath CachePath() { return fCachePath; }
private: private:
typedef KeyMap<BString, Role*> RoleMap;
void _WarnUser(BString message); void _WarnUser(BString message);
void _LogChatMessage(BMessage* msg); void _LogChatMessage(BMessage* msg);
@ -94,6 +94,8 @@ private:
void _SortConversationList(); void _SortConversationList();
Server* _GetServer();
BMessenger fMessenger; BMessenger fMessenger;
ProtocolLooper* fLooper; ProtocolLooper* fLooper;
ConversationView* fChatView; ConversationView* fChatView;

View File

@ -1,5 +1,3 @@
include Make.pre
## Haiku Generic Makefile v2.6 ## ## Haiku Generic Makefile v2.6 ##
## Fill in this file to specify the project being created, and the referenced ## Fill in this file to specify the project being created, and the referenced
@ -10,7 +8,7 @@ include Make.pre
## file:///system/develop/documentation/makefile-engine.html ## file:///system/develop/documentation/makefile-engine.html
# The name of the binary. # The name of the binary.
NAME = $(APP_NAME) NAME = Chat-O-Matic
# The type of binary, must be one of: # The type of binary, must be one of:
# APP: Application # APP: Application
@ -20,7 +18,7 @@ NAME = $(APP_NAME)
TYPE = APP TYPE = APP
# If you plan to use localization, specify the application's MIME signature. # If you plan to use localization, specify the application's MIME signature.
APP_MIME_SIG = $(APP_SIGNATURE) APP_MIME_SIG = application/x-vnd.chat-o-matic
# The following lines tell Pe and Eddie where the SRCS, RDEFS, and RSRCS are # The following lines tell Pe and Eddie where the SRCS, RDEFS, and RSRCS are
# so that Pe and Eddie can fill them in for you. # so that Pe and Eddie can fill them in for you.
@ -66,7 +64,6 @@ SRCS = \
application/views/InviteDialogue.cpp \ application/views/InviteDialogue.cpp \
application/views/ReplicantStatusView.cpp \ application/views/ReplicantStatusView.cpp \
application/views/ReplicantMenuItem.cpp \ application/views/ReplicantMenuItem.cpp \
application/views/RoomListRow.cpp \
application/views/RosterItem.cpp \ application/views/RosterItem.cpp \
application/views/RosterListView.cpp \ application/views/RosterListView.cpp \
application/views/RosterView.cpp \ application/views/RosterView.cpp \
@ -77,11 +74,11 @@ SRCS = \
application/views/UserItem.cpp \ application/views/UserItem.cpp \
application/views/UserListView.cpp \ application/views/UserListView.cpp \
application/views/UserPopUp.cpp \ application/views/UserPopUp.cpp \
application/windows/AboutWindow.cpp \
application/windows/AccountsWindow.cpp \ application/windows/AccountsWindow.cpp \
application/windows/ConversationInfoWindow.cpp \ application/windows/ConversationInfoWindow.cpp \
application/windows/MainWindow.cpp \ application/windows/MainWindow.cpp \
application/windows/PreferencesWindow.cpp \ application/windows/PreferencesWindow.cpp \
application/windows/RoomListWindow.cpp \
application/windows/RosterEditWindow.cpp \ application/windows/RosterEditWindow.cpp \
application/windows/RosterWindow.cpp \ application/windows/RosterWindow.cpp \
application/windows/TemplateWindow.cpp \ application/windows/TemplateWindow.cpp \
@ -133,7 +130,7 @@ RSRCS =
# - if your library does not follow the standard library naming scheme, # - if your library does not follow the standard library naming scheme,
# you need to specify the path to the library and it's name. # you need to specify the path to the library and it's name.
# (e.g. for mylib.a, specify "mylib.a" or "path/mylib.a") # (e.g. for mylib.a, specify "mylib.a" or "path/mylib.a")
LIBS = be columnlistview expat interface localestub runview shared translation $(STDCPPLIBS) LIBS = be expat interface localestub runview shared translation $(STDCPPLIBS)
# Specify additional paths to directories following the standard libXXX.so # Specify additional paths to directories following the standard libXXX.so
@ -146,9 +143,7 @@ LIBPATHS =
# Additional paths to look for system headers. These use the form # Additional paths to look for system headers. These use the form
# "#include <header>". Directories that contain the files in SRCS are # "#include <header>". Directories that contain the files in SRCS are
# NOT auto-included here. # NOT auto-included here.
SYSTEM_INCLUDE_PATHS = libs/ \ SYSTEM_INCLUDE_PATHS = libs/
$(shell findpaths -e B_FIND_PATH_HEADERS_DIRECTORY private/interface)
# Additional paths paths to look for local headers. These use the form # Additional paths paths to look for local headers. These use the form
# #include "header". Directories that contain the files in SRCS are # #include "header". Directories that contain the files in SRCS are
@ -171,7 +166,7 @@ LOCALES = en eo
# use. For example, setting DEFINES to "DEBUG=1" will cause the compiler # use. For example, setting DEFINES to "DEBUG=1" will cause the compiler
# option "-DDEBUG=1" to be used. Setting DEFINES to "DEBUG" would pass # option "-DDEBUG=1" to be used. Setting DEFINES to "DEBUG" would pass
# "-DDEBUG" on the compiler's command line. # "-DDEBUG" on the compiler's command line.
DEFINES = DEFINES :=
# Specify the warning level. Either NONE (suppress all warnings), # Specify the warning level. Either NONE (suppress all warnings),
# ALL (enable all warnings), or leave blank (enable default warnings). # ALL (enable all warnings), or leave blank (enable default warnings).
@ -207,6 +202,7 @@ DRIVER_PATH =
## Include the Makefile-Engine ## Include the Makefile-Engine
DEVEL_DIRECTORY := /boot/system/develop/ DEVEL_DIRECTORY := /boot/system/develop/
include $(DEVEL_DIRECTORY)/etc/makefile-engine include $(DEVEL_DIRECTORY)/etc/makefile-engine
include Make.post
include Makefile.common
CC = g++ CC = g++

View File

@ -1,26 +0,0 @@
/*
* Copyright 2022, Jaidyn Levesque <jadedctrl@teknik.io>
* All rights reserved. Distributed under the terms of the MIT license.
*/
#ifndef _MAPS_H
#define _MAPS_H
#include <String.h>
#include "libsupport/KeyMap.h"
class ChatCommand;
class Command;
class Contact;
class Conversation;
class User;
// Defining some commonly-used KeyMaps
typedef KeyMap<BString, bigtime_t> AccountInstances;
typedef KeyMap<BString, ChatCommand*> CommandMap;
typedef KeyMap<BString, Conversation*> ChatMap;
typedef KeyMap<BString, Contact*> RosterMap;
typedef KeyMap<BString, User*> UserMap;
#endif // _MAPS_H

View File

@ -21,7 +21,7 @@ enum {
INT_NEW_MESSAGE, INT_NEW_MESSAGE,
INT_NEW_MENTION, INT_NEW_MENTION,
INT_CONV_VIEW_SELECTED, INT_WINDOW_FOCUSED,
INT_ACCOUNTS_UPDATED INT_ACCOUNTS_UPDATED
}; };

View File

@ -13,13 +13,12 @@
#include "ProtocolLooper.h" #include "ProtocolLooper.h"
#include <Bitmap.h> #include <Bitmap.h>
#include <Catalog.h>
#include <String.h> #include <String.h>
#include "Account.h" #include "Account.h"
#include "AppMessages.h" #include "AppMessages.h"
#include "ChatOMatic.h"
#include "ChatProtocolMessages.h" #include "ChatProtocolMessages.h"
#include "Contact.h"
#include "Conversation.h" #include "Conversation.h"
#include "ConversationAccountItem.h" #include "ConversationAccountItem.h"
#include "ConversationView.h" #include "ConversationView.h"
@ -255,10 +254,6 @@ ProtocolLooper::LoadCommands()
} }
#undef B_TRANSLATION_CONTEXT
#define B_TRANSLATION_CONTEXT "Protocol system buffer"
void void
ProtocolLooper::_InitChatView() ProtocolLooper::_InitChatView()
{ {

View File

@ -11,9 +11,10 @@
#include <ObjectList.h> #include <ObjectList.h>
#include <String.h> #include <String.h>
#include <libsupport/KeyMap.h>
#include "ChatProtocol.h" #include "ChatProtocol.h"
#include "ChatCommand.h" #include "ChatCommand.h"
#include "Maps.h"
class Contact; class Contact;
class Conversation; class Conversation;
@ -22,6 +23,11 @@ class ConversationView;
class User; class User;
typedef KeyMap<BString, Conversation*> ChatMap;
typedef KeyMap<BString, Contact*> RosterMap;
typedef KeyMap<BString, User*> UserMap;
class ProtocolLooper : public BLooper { class ProtocolLooper : public BLooper {
public: public:
ProtocolLooper(ChatProtocol* protocol, int64 instance); ProtocolLooper(ChatProtocol* protocol, int64 instance);

View File

@ -47,18 +47,10 @@ ProtocolManager::Init(BDirectory dir, BHandler* target)
if (id < 0) if (id < 0)
continue; continue;
// Refuse to load add-on under some circumstances… // If add-on's API version fits then load accounts…
ChatProtocolAddOn* addOn = new ChatProtocolAddOn(id, path.Path()); ChatProtocolAddOn* addOn = new ChatProtocolAddOn(id, path.Path());
if (addOn->Version() != APP_VERSION || ProtocolAddOn(addOn->Signature()) != NULL) {
if (addOn->Version() != APP_VERSION) if (addOn->Version() != APP_VERSION)
printf("%s not loaded, due to insufficient version (%i v %i).\n",
addOn->Signature(), addOn->Version(), APP_VERSION);
else if (ProtocolAddOn(addOn->Signature()) != NULL)
printf("%s not loaded, due to another instance already having been loaded.\n",
addOn->Signature());
delete addOn;
continue; continue;
}
ret = true; ret = true;
// If add-on has multiple protocols, also load them // If add-on has multiple protocols, also load them
@ -140,7 +132,7 @@ ProtocolManager::AddAccount(ChatProtocolAddOn* addOn, const char* account,
{ {
// If already active, don't double-dip! // If already active, don't double-dip!
bool active = false; bool active = false;
Server::Get()->GetActiveAccounts().ValueFor(BString(account), &active); _Server()->GetActiveAccounts().ValueFor(BString(account), &active);
if (active == true) if (active == true)
return; return;
@ -165,7 +157,7 @@ ProtocolManager::AddAccount(ChatProtocolAddOn* addOn, const char* account,
fProtocolMap.AddItem(instanceId, cayap); fProtocolMap.AddItem(instanceId, cayap);
Server::Get()->AddProtocolLooper(instanceId, cayap); _Server()->AddProtocolLooper(instanceId, cayap);
} }
@ -189,7 +181,7 @@ ProtocolManager::DisableAccount(ProtocolSettings* settings, const char* account)
{ {
bool active = false; bool active = false;
int64 instance int64 instance
= Server::Get()->GetActiveAccounts().ValueFor(BString(account), &active); = _Server()->GetActiveAccounts().ValueFor(BString(account), &active);
if (active == false) if (active == false)
return; return;
@ -214,7 +206,7 @@ ProtocolManager::ToggleAccount(ProtocolSettings* settings, const char* account)
{ {
bool active = false; bool active = false;
int64 instance int64 instance
= Server::Get()->GetActiveAccounts().ValueFor(BString(account), &active); = _Server()->GetActiveAccounts().ValueFor(BString(account), &active);
if (active == true) if (active == true)
DisableAccount(settings, account); DisableAccount(settings, account);
@ -280,3 +272,11 @@ ProtocolManager::_MainWin()
{ {
return ((TheApp*)be_app)->GetMainWindow(); return ((TheApp*)be_app)->GetMainWindow();
} }
Server*
ProtocolManager::_Server()
{
MainWindow* win = _MainWin();
return win ? win->GetServer() : NULL;
}

View File

@ -64,6 +64,7 @@ private:
BEntry accountEntry, BHandler* target); BEntry accountEntry, BHandler* target);
MainWindow* _MainWin(); MainWindow* _MainWin();
Server* _Server();
AddOnMap fAddOnMap; AddOnMap fAddOnMap;
ProtocolMap fProtocolMap; ProtocolMap fProtocolMap;

View File

@ -49,7 +49,7 @@ ProtocolSettings::Accounts() const
{ {
BObjectList<BString> list(true); BObjectList<BString> list(true);
BPath path = AccountPath(fAddOn->Signature(), fAddOn->ProtoSignature()); BPath path(AccountPath(fAddOn->Signature(), fAddOn->ProtoSignature()));
if (path.InitCheck() != B_OK) if (path.InitCheck() != B_OK)
return list; return list;
@ -93,7 +93,7 @@ ProtocolSettings::Load(const char* account, BMessage** settings)
status_t ret = B_ERROR; status_t ret = B_ERROR;
// Find user's settings path // Find user's settings path
BPath path = AccountPath(fAddOn->Signature(), fAddOn->ProtoSignature()); BPath path(AccountPath(fAddOn->Signature(), fAddOn->ProtoSignature()));
if ((ret = path.InitCheck()) != B_OK) if ((ret = path.InitCheck()) != B_OK)
return ret; return ret;
@ -127,7 +127,7 @@ status_t
ProtocolSettings::Save(const char* account, BMessage settings) ProtocolSettings::Save(const char* account, BMessage settings)
{ {
// Find user's settings path // Find user's settings path
BPath path = AccountPath(fAddOn->Signature(), fAddOn->ProtoSignature()); BPath path(AccountPath(fAddOn->Signature(), fAddOn->ProtoSignature()));
status_t ret; status_t ret;
if ((ret = path.InitCheck()) != B_OK) if ((ret = path.InitCheck()) != B_OK)
@ -146,7 +146,7 @@ ProtocolSettings::Rename(const char* from, const char* to)
status_t ret = B_ERROR; status_t ret = B_ERROR;
// Find user's settings path // Find user's settings path
BPath path = AccountPath(fAddOn->Signature(), fAddOn->ProtoSignature()); BPath path(AccountPath(fAddOn->Signature(), fAddOn->ProtoSignature()));
if ((ret = path.InitCheck()) != B_OK) if ((ret = path.InitCheck()) != B_OK)
return ret; return ret;
@ -168,7 +168,7 @@ ProtocolSettings::Delete(const char* account)
status_t ret = B_ERROR; status_t ret = B_ERROR;
// Find user's settings path // Find user's settings path
BPath path = AccountPath(fAddOn->Signature(), fAddOn->ProtoSignature()); BPath path(AccountPath(fAddOn->Signature(), fAddOn->ProtoSignature()));
if ((ret = path.InitCheck()) != B_OK) if ((ret = path.InitCheck()) != B_OK)
return ret; return ret;

View File

@ -28,6 +28,7 @@
#include "Account.h" #include "Account.h"
#include "AppMessages.h" #include "AppMessages.h"
#include "AppPreferences.h" #include "AppPreferences.h"
#include "ChatOMatic.h"
#include "ChatProtocol.h" #include "ChatProtocol.h"
#include "ConversationInfoWindow.h" #include "ConversationInfoWindow.h"
#include "ConversationView.h" #include "ConversationView.h"
@ -48,9 +49,6 @@
#define B_TRANSLATION_CONTEXT "Server" #define B_TRANSLATION_CONTEXT "Server"
Server* Server::fInstance = NULL;
Server::Server() Server::Server()
: :
BMessageFilter(B_ANY_DELIVERY, B_ANY_SOURCE) BMessageFilter(B_ANY_DELIVERY, B_ANY_SOURCE)
@ -85,15 +83,6 @@ Server::Server()
} }
Server*
Server::Get()
{
if (fInstance == NULL)
fInstance = new Server();
return fInstance;
}
void void
Server::Quit() Server::Quit()
{ {
@ -639,7 +628,7 @@ Server::ImMessage(BMessage* msg)
// Join cached rooms // Join cached rooms
BEntry entry; BEntry entry;
char fileName[B_FILE_NAME_LENGTH] = {'\0'}; char fileName[B_FILE_NAME_LENGTH] = {'\0'};
BDirectory dir(RoomsCachePath(looper->Protocol()->GetName()).Path()); BDirectory dir(RoomsCachePath(looper->Protocol()->GetName()));
while (dir.GetNextEntry(&entry, true) == B_OK) while (dir.GetNextEntry(&entry, true) == B_OK)
if (entry.GetName(fileName) == B_OK) { if (entry.GetName(fileName) == B_OK) {

View File

@ -1,7 +1,6 @@
/* /*
* Copyright 2009-2011, Andrea Anzani. All rights reserved. * Copyright 2009-2011, Andrea Anzani. All rights reserved.
* Copyright 2009-2011, Pier Luigi Fiorini. All rights reserved. * Copyright 2009-2011, Pier Luigi Fiorini. All rights reserved.
* Copyright 2021-2022, Jaidyn Levesque. All rights reserved.
* Distributed under the terms of the MIT License. * Distributed under the terms of the MIT License.
*/ */
#ifndef _SERVER_H #ifndef _SERVER_H
@ -26,10 +25,14 @@ class RosterItem;
class ProtocolLooper; class ProtocolLooper;
typedef KeyMap<bigtime_t, ProtocolLooper*> ProtocolLoopers;
typedef KeyMap<BString, bigtime_t> AccountInstances;
typedef KeyMap<BString, bool> BoolMap;
class Server: public BMessageFilter, public Notifier { class Server: public BMessageFilter, public Notifier {
public: public:
Server(); Server();
static Server* Get();
void Quit(); void Quit();
void LoginAll(); void LoginAll();
void Login(ProtocolLooper* looper); void Login(ProtocolLooper* looper);
@ -67,9 +70,6 @@ public:
BObjectList<BMessage> UserPopUpItems(); BObjectList<BMessage> UserPopUpItems();
private: private:
typedef KeyMap<BString, bool> BoolMap;
typedef KeyMap<bigtime_t, ProtocolLooper*> ProtocolLoopers;
ProtocolLooper* _LooperFromMessage(BMessage* message); ProtocolLooper* _LooperFromMessage(BMessage* message);
Contact* _EnsureContact(BMessage* message); Contact* _EnsureContact(BMessage* message);
@ -87,8 +87,6 @@ private:
void _ReplicantStatusNotify(UserStatus status); void _ReplicantStatusNotify(UserStatus status);
static Server* fInstance;
ProtocolLoopers fLoopers; ProtocolLoopers fLoopers;
AccountInstances fAccounts; AccountInstances fAccounts;
BoolMap fAccountEnabled; BoolMap fAccountEnabled;

View File

@ -11,8 +11,10 @@
#include <stdio.h> #include <stdio.h>
#include "ChatProtocolMessages.h" #include "ChatProtocolMessages.h"
#include "MainWindow.h"
#include "NotifyMessage.h" #include "NotifyMessage.h"
#include "Server.h" #include "Server.h"
#include "TheApp.h"
static StatusManager* fInstance = NULL; static StatusManager* fInstance = NULL;
@ -50,12 +52,14 @@ StatusManager::SetNickname(BString nick, int64 instance)
msg->AddString("user_name", nick); msg->AddString("user_name", nick);
// Send message // Send message
TheApp* theApp = reinterpret_cast<TheApp*>(be_app);
MainWindow* win = theApp->GetMainWindow();
if (instance > -1) { if (instance > -1) {
msg->AddInt64("instance", instance); msg->AddInt64("instance", instance);
Server::Get()->SendProtocolMessage(msg); win->GetServer()->SendProtocolMessage(msg);
} }
else else
Server::Get()->SendAllProtocolMessage(msg); win->GetServer()->SendAllProtocolMessage(msg);
} }
@ -87,12 +91,15 @@ StatusManager::SetStatus(UserStatus status, const char* str, int64 instance)
msg->AddString("message", str); msg->AddString("message", str);
// Send message // Send message
TheApp* theApp = reinterpret_cast<TheApp*>(be_app);
MainWindow* win = theApp->GetMainWindow();
if (instance > -1) { if (instance > -1) {
msg->AddInt64("instance", instance); msg->AddInt64("instance", instance);
Server::Get()->SendProtocolMessage(msg); win->GetServer()->SendProtocolMessage(msg);
} }
else else
Server::Get()->SendAllProtocolMessage(msg); win->GetServer()->SendAllProtocolMessage(msg);
// Notify status change // Notify status change
fStatus = status; fStatus = status;

View File

@ -14,7 +14,6 @@
#include <stdio.h> #include <stdio.h>
#include <AboutWindow.h>
#include <Alert.h> #include <Alert.h>
#include <Catalog.h> #include <Catalog.h>
#include <Path.h> #include <Path.h>
@ -22,6 +21,8 @@
#include <librunview/Emoticor.h> #include <librunview/Emoticor.h>
#include "AboutWindow.h"
#include "ChatOMatic.h"
#include "AppMessages.h" #include "AppMessages.h"
#include "FilePanel.h" #include "FilePanel.h"
#include "MainWindow.h" #include "MainWindow.h"
@ -89,7 +90,7 @@ TheApp::ReadyToRun()
if (win == false) { if (win == false) {
BString msg(B_TRANSLATE("No protocols found!\nPlease make sure %app% was installed correctly.")); BString msg(B_TRANSLATE("No protocols found!\nPlease make sure %app% was installed correctly."));
msg.ReplaceAll("%app%", B_TRANSLATE_SYSTEM_NAME(APP_NAME)); msg.ReplaceAll("%app%", APP_NAME);
BAlert* alert = new BAlert("", msg.String(), B_TRANSLATE("Ouch!")); BAlert* alert = new BAlert("", msg.String(), B_TRANSLATE("Ouch!"));
alert->Go(); alert->Go();
PostMessage(B_QUIT_REQUESTED); PostMessage(B_QUIT_REQUESTED);
@ -108,21 +109,28 @@ TheApp::AboutRequested()
"2009-2010 Andrea Anzani", "2009-2010 Andrea Anzani",
"2010-2015 Dario Casalinuovo", "2010-2015 Dario Casalinuovo",
"2009-2010 Pier Luigi Fiorini", "2009-2010 Pier Luigi Fiorini",
"2021 Jaidyn Levesque",
NULL
};
const char* authors[] = {
"Andrea Anzani",
"Dario Casalinuovo",
"Pier Luigi Fiorini",
"Jaidyn Levesque",
NULL NULL
}; };
BString extraInfo(B_TRANSLATE("%app% is released under the MIT License.\n" BString extraInfo(B_TRANSLATE("%app% is released under the MIT License.\n"
"Add-on and library licenses may vary.\n" "Add-on and library licenses may vary.\n"
"Built: %buildDate%")); "Built: %buildDate%"));
extraInfo.ReplaceAll("%buildDate%", BUILD_DATE); extraInfo.ReplaceAll("%buildDate", BUILD_DATE);
extraInfo.ReplaceAll("%app%", B_TRANSLATE_SYSTEM_NAME(APP_NAME)); extraInfo.ReplaceAll("%app%", B_TRANSLATE_SYSTEM_NAME(APP_NAME));
BAboutWindow* about = new BAboutWindow(B_TRANSLATE_SYSTEM_NAME(APP_NAME), AboutWindow* about = new AboutWindow(B_TRANSLATE_SYSTEM_NAME(APP_NAME),
APP_SIGNATURE); holders, authors, extraInfo.String());
about->AddDescription(B_TRANSLATE("A multi-protocol chat program."));
about->AddCopyright(2021, "Jaidyn Levesque", holders);
about->AddExtraInfo(extraInfo);
about->Show(); about->Show();
delete about;
} }

View File

@ -227,7 +227,8 @@ User::_EnsureCachePath()
{ {
if (fCachePath.InitCheck() == B_OK) if (fCachePath.InitCheck() == B_OK)
return; return;
fCachePath = UserCachePath(fLooper->Protocol()->GetName(), fID.String()); fCachePath.SetTo(UserCachePath(fLooper->Protocol()->GetName(),
fID.String()));
} }

View File

@ -14,7 +14,8 @@
#include <Path.h> #include <Path.h>
#include <String.h> #include <String.h>
#include "Maps.h" #include <libsupport/KeyMap.h>
#include "Notifier.h" #include "Notifier.h"
#include "UserStatus.h" #include "UserStatus.h"
@ -25,6 +26,9 @@ class ProtocolLooper;
class UserPopUp; class UserPopUp;
typedef KeyMap<BString, Conversation*> ChatMap;
class User : public Notifier { class User : public Notifier {
public: public:
User(BString id, BMessenger msgn); User(BString id, BMessenger msgn);

View File

@ -19,6 +19,7 @@
#include <kernel/fs_attr.h> #include <kernel/fs_attr.h>
#include "ChatOMatic.h"
#include "Utils.h" #include "Utils.h"
@ -150,104 +151,88 @@ AccountPath(const char* signature, const char* subsignature)
} }
BPath const char*
CachePath() CachePath()
{ {
BPath path = SettingsPath(); BPath path(SettingsPath());
path.Append("Cache/"); if (path.InitCheck() != B_OK)
create_directory(path.Path(), 0755); return NULL;
return path;
path.Append("Cache");
if (create_directory(path.Path(), 0755) != B_OK)
return NULL;
return path.Path();
} }
BPath const char*
AccountCachePath(const char* accountName) AccountCachePath(const char* accountName)
{ {
BPath path = CachePath(); BPath path(CachePath());
path.Append("Accounts/"); path.Append("Accounts");
if (path.InitCheck() != B_OK)
return NULL;
path.Append(accountName); path.Append(accountName);
create_directory(path.Path(), 0755); if (create_directory(path.Path(), 0755) != B_OK)
return path; return NULL;
return path.Path();
} }
BPath const char*
RoomsCachePath(const char* accountName) RoomsCachePath(const char* accountName)
{ {
return RoomsCachePath(AccountCachePath(accountName)); BPath path(AccountCachePath(accountName));
if (path.InitCheck() != B_OK)
return NULL;
path.Append("Rooms");
if (create_directory(path.Path(), 0755) != B_OK)
return NULL;
return path.Path();
} }
BPath const char*
RoomsCachePath(BPath accPath)
{
accPath.Append("Rooms/");
create_directory(accPath.Path(), 0755);
return accPath;
}
BPath
RoomCachePath(const char* accountName, const char* roomIdentifier) RoomCachePath(const char* accountName, const char* roomIdentifier)
{ {
return RoomCachePath(AccountCachePath(accountName), roomIdentifier); BPath path(RoomsCachePath(accountName));
} if (path.InitCheck() != B_OK)
return NULL;
BPath
RoomCachePath(BPath accPath, const char* roomIdentifier)
{
BPath path = RoomsCachePath(accPath);
path.Append(roomIdentifier); path.Append(roomIdentifier);
return path; return path.Path();
} }
BPath const char*
UserCachePath(const char* accountName, const char* userIdentifier) UserCachePath(const char* accountName, const char* userIdentifier)
{ {
return UserCachePath(AccountCachePath(accountName), userIdentifier); BPath path(AccountCachePath(accountName));
if (path.InitCheck() != B_OK)
return NULL;
path.Append("Users");
if (create_directory(path.Path(), 0755) != B_OK)
return NULL;
path.Append(userIdentifier);
return path.Path();
} }
BPath const char*
UserCachePath(BPath accPath, const char* userIdentifier)
{
accPath.Append("Users/");
create_directory(accPath.Path(), 0755);
accPath.Append(userIdentifier);
return accPath;
}
BPath
ContactCachePath(const char* accountName, const char* userIdentifier) ContactCachePath(const char* accountName, const char* userIdentifier)
{ {
return ContactCachePath(AccountCachePath(accountName), userIdentifier); BPath path(AccountCachePath(accountName));
} if (path.InitCheck() != B_OK)
return NULL;
path.Append("Contacts");
if (create_directory(path.Path(), 0755) != B_OK)
BPath return NULL;
ContactCachePath(BPath accPath, const char* userIdentifier) path.Append(userIdentifier);
{ return path.Path();
accPath.Append("Contacts/");
create_directory(accPath.Path(), 0755);
accPath.Append(userIdentifier);
return accPath;
}
BPath
AddOnCachePath(const char* signature)
{
BPath path = CachePath();
path.Append("Add-Ons/");
path.Append(signature);
create_directory(path.Path(), 0755);
return path;
} }

View File

@ -14,7 +14,7 @@
#include <Resources.h> #include <Resources.h>
#include "AppConstants.h" #include "AppConstants.h"
#include "UserStatus.h" #include "Server.h"
class BMenu; class BMenu;
@ -36,17 +36,12 @@ const char* SettingsPath();
const char* AccountsPath(); const char* AccountsPath();
const char* AccountPath(const char* signature, const char* subsignature); const char* AccountPath(const char* signature, const char* subsignature);
BPath CachePath(); const char* CachePath();
BPath AccountCachePath(const char* accountName); const char* AccountCachePath(const char* accountName);
BPath RoomsCachePath(const char* accountName); const char* RoomsCachePath(const char* accountName);
BPath RoomsCachePath(BPath accPath); const char* RoomCachePath(const char* accountName, const char* roomIdentifier);
BPath RoomCachePath(const char* accountName, const char* roomIdentifier); const char* UserCachePath(const char* accountName, const char* userIdentifier);
BPath RoomCachePath(BPath accPath, const char* roomIdentifier); const char* ContactCachePath(const char* accountName, const char* userIdentifier);
BPath UserCachePath(const char* accountName, const char* userIdentifier);
BPath UserCachePath(BPath accPath, const char* userIdentifier);
BPath ContactCachePath(const char* accountName, const char* userIdentifier);
BPath ContactCachePath(BPath accPath, const char* userIdentifier);
BPath AddOnCachePath(const char* signature);
rgb_color TintColor(rgb_color color, int severity); rgb_color TintColor(rgb_color color, int severity);
rgb_color ForegroundColor(rgb_color background); rgb_color ForegroundColor(rgb_color background);
@ -60,3 +55,4 @@ extern "C" status_t our_image(image_info& image);
#endif // _APP_UTILS_H #endif // _APP_UTILS_H

View File

@ -6,8 +6,6 @@
#include "AppPreferences.h" #include "AppPreferences.h"
#include <Path.h>
#include "Utils.h" #include "Utils.h"
@ -46,7 +44,6 @@ AppPreferences::Load()
HideDeskbar = settings.GetBool("HideDeskbar", false); HideDeskbar = settings.GetBool("HideDeskbar", false);
DisableReplicant = settings.GetBool("DisableReplicant", true); DisableReplicant = settings.GetBool("DisableReplicant", true);
DisableQuitConfirm = settings.GetBool("DisableQuitConfirm", false); DisableQuitConfirm = settings.GetBool("DisableQuitConfirm", false);
MembershipUpdates = settings.GetBool("MembershipUpdates", true);
IgnoreEmoticons = settings.GetBool("IgnoreEmoticons", true); IgnoreEmoticons = settings.GetBool("IgnoreEmoticons", true);
HideOffline = settings.GetBool("HideOffline", false); HideOffline = settings.GetBool("HideOffline", false);
@ -59,7 +56,6 @@ AppPreferences::Load()
ChatViewVertSendWeight = settings.GetFloat("ChatViewVertSendWeight", 1); ChatViewVertSendWeight = settings.GetFloat("ChatViewVertSendWeight", 1);
MainWindowRect = settings.GetRect("MainWindowRect", BRect(0, 0, 600, 400)); MainWindowRect = settings.GetRect("MainWindowRect", BRect(0, 0, 600, 400));
RoomDirectoryRect = settings.GetRect("RoomDirectoryRect", BRect(0, 0, 630, 330));
} }
@ -82,7 +78,6 @@ AppPreferences::Save()
settings.AddBool("DisableReplicant", DisableReplicant); settings.AddBool("DisableReplicant", DisableReplicant);
settings.AddBool("DisableQuitConfirm", DisableQuitConfirm); settings.AddBool("DisableQuitConfirm", DisableQuitConfirm);
settings.AddBool("IgnoreEmoticons", IgnoreEmoticons); settings.AddBool("IgnoreEmoticons", IgnoreEmoticons);
settings.AddBool("MembershipUpdates", MembershipUpdates);
settings.AddBool("HideOffline", HideOffline); settings.AddBool("HideOffline", HideOffline);
settings.AddFloat("MainWindowListWeight", MainWindowListWeight); settings.AddFloat("MainWindowListWeight", MainWindowListWeight);
@ -94,7 +89,6 @@ AppPreferences::Save()
settings.AddFloat("ChatViewVertSendWeight", ChatViewVertSendWeight); settings.AddFloat("ChatViewVertSendWeight", ChatViewVertSendWeight);
settings.AddRect("MainWindowRect", MainWindowRect); settings.AddRect("MainWindowRect", MainWindowRect);
settings.AddRect("RoomDirectoryRect", RoomDirectoryRect);
if (file.InitCheck() == B_OK) if (file.InitCheck() == B_OK)
settings.Flatten(&file); settings.Flatten(&file);

View File

@ -1,7 +1,7 @@
/* /*
* Copyright 2010, Oliver Ruiz Dorantes. All rights reserved. * Copyright 2010, Oliver Ruiz Dorantes. All rights reserved.
* Copyright 2012, Casalinuovo Dario. All rights reserved. * Copyright 2012, Casalinuovo Dario. All rights reserved.
* Copyright 2021-2022, Jaidyn Levesque <jadedctrl@teknik.io> * Copyright 2021, Jaidyn Levesque <jadedctrl@teknik.io>
* All rights reserved. Distributed under the terms of the MIT license. * All rights reserved. Distributed under the terms of the MIT license.
*/ */
#ifndef _APP_PREFERENCES_H #ifndef _APP_PREFERENCES_H
@ -33,7 +33,6 @@ public:
bool DisableQuitConfirm; bool DisableQuitConfirm;
bool IgnoreEmoticons; bool IgnoreEmoticons;
bool MembershipUpdates;
bool HideOffline; bool HideOffline;
@ -46,7 +45,6 @@ public:
float ChatViewVertSendWeight; float ChatViewVertSendWeight;
BRect MainWindowRect; BRect MainWindowRect;
BRect RoomDirectoryRect;
private: private:
const char* _PreferencesPath(); const char* _PreferencesPath();

View File

@ -1,7 +1,7 @@
/* /*
* Copyright 2010, Oliver Ruiz Dorantes. All rights reserved. * Copyright 2010, Oliver Ruiz Dorantes. All rights reserved.
* Copyright 2012, Dario Casalinuovo. All rights reserved. * Copyright 2012, Dario Casalinuovo. All rights reserved.
* Copyright 2021-2022, Jaidyn Levesque. All rights reserved. * Copyright 2021, Jaidyn Levesque. All rights reserved.
* Distributed under the terms of the MIT License. * Distributed under the terms of the MIT License.
*/ */
@ -21,7 +21,6 @@
const uint32 kIgnoreEmoticons = 'CBhe'; const uint32 kIgnoreEmoticons = 'CBhe';
const uint32 kMembershipUpdates = 'CBmu';
PreferencesChatWindow::PreferencesChatWindow() PreferencesChatWindow::PreferencesChatWindow()
@ -30,9 +29,6 @@ PreferencesChatWindow::PreferencesChatWindow()
BBox* chatBox = new BBox("chatBox"); BBox* chatBox = new BBox("chatBox");
chatBox->SetLabel(B_TRANSLATE("Chat settings")); chatBox->SetLabel(B_TRANSLATE("Chat settings"));
fMembershipUpdates = new BCheckBox("MembershipUpdates",
B_TRANSLATE("Show join/part messages"), new BMessage(kMembershipUpdates));
fIgnoreEmoticons = new BCheckBox("IgnoreEmoticons", fIgnoreEmoticons = new BCheckBox("IgnoreEmoticons",
B_TRANSLATE("Ignore emoticons"), new BMessage(kIgnoreEmoticons)); B_TRANSLATE("Ignore emoticons"), new BMessage(kIgnoreEmoticons));
fIgnoreEmoticons->SetEnabled(false); // No emoticon support currently fIgnoreEmoticons->SetEnabled(false); // No emoticon support currently
@ -42,7 +38,6 @@ PreferencesChatWindow::PreferencesChatWindow()
BLayoutBuilder::Group<>(chatBox, B_VERTICAL) BLayoutBuilder::Group<>(chatBox, B_VERTICAL)
.SetInsets(spacing, spacing * 2, spacing, spacing) .SetInsets(spacing, spacing * 2, spacing, spacing)
.Add(fMembershipUpdates)
.Add(fIgnoreEmoticons) .Add(fIgnoreEmoticons)
.End(); .End();
@ -59,8 +54,6 @@ PreferencesChatWindow::AttachedToWindow()
{ {
fIgnoreEmoticons->SetTarget(this); fIgnoreEmoticons->SetTarget(this);
fIgnoreEmoticons->SetValue(AppPreferences::Get()->IgnoreEmoticons); fIgnoreEmoticons->SetValue(AppPreferences::Get()->IgnoreEmoticons);
fMembershipUpdates->SetTarget(this);
fMembershipUpdates->SetValue(AppPreferences::Get()->MembershipUpdates);
} }
@ -69,10 +62,8 @@ PreferencesChatWindow::MessageReceived(BMessage* message)
{ {
switch (message->what) { switch (message->what) {
case kIgnoreEmoticons: case kIgnoreEmoticons:
AppPreferences::Get()->IgnoreEmoticons = fIgnoreEmoticons->Value(); AppPreferences::Get()->IgnoreEmoticons
break; = fIgnoreEmoticons->Value();
case kMembershipUpdates:
AppPreferences::Get()->MembershipUpdates = fMembershipUpdates->Value();
break; break;
default: default:
BView::MessageReceived(message); BView::MessageReceived(message);

View File

@ -19,7 +19,6 @@ public:
private: private:
BCheckBox* fIgnoreEmoticons; BCheckBox* fIgnoreEmoticons;
BCheckBox* fMembershipUpdates;
}; };
#endif // _PREFERENCES_BEHAVIOR_H #endif // _PREFERENCES_BEHAVIOR_H

View File

@ -14,7 +14,9 @@
#include "AccountMenuItem.h" #include "AccountMenuItem.h"
#include "ImageCache.h" #include "ImageCache.h"
#include "MainWindow.h"
#include "Server.h" #include "Server.h"
#include "TheApp.h"
#undef B_TRANSLATION_CONTEXT #undef B_TRANSLATION_CONTEXT
@ -24,23 +26,33 @@
int64 AccountsMenu::fDefaultSelection = -1; int64 AccountsMenu::fDefaultSelection = -1;
AccountsMenu::AccountsMenu(const char* name, BMessage msg, BMessage* allMsg) AccountsMenu::AccountsMenu(const char* name, BMessage msg, BMessage* allMsg,
Server* server)
: :
BPopUpMenu(name), BPopUpMenu(name),
fAccountMessage(msg), fAccountMessage(msg),
fAllMessage(allMsg) fAllMessage(allMsg),
fServer(server)
{ {
_PopulateMenu(); _PopulateMenu();
SetRadioMode(true); SetRadioMode(true);
SetLabelFromMarked(true); SetLabelFromMarked(true);
Server::Get()->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() AccountsMenu::~AccountsMenu()
{ {
delete fAllMessage; delete fAllMessage;
Server::Get()->UnregisterObserver(this); fServer->UnregisterObserver(this);
} }
@ -68,7 +80,7 @@ AccountsMenu::_PopulateMenu()
icon, 0, 0, false)); icon, 0, 0, false));
} }
AccountInstances accounts = Server::Get()->GetActiveAccounts(); AccountInstances accounts = fServer->GetActiveAccounts();
// Add protocol item if not already in menu // Add protocol item if not already in menu
for (int i = 0; i < accounts.CountItems(); i++) { for (int i = 0; i < accounts.CountItems(); i++) {
@ -86,7 +98,7 @@ AccountsMenu::_PopulateMenu()
if (FindItem(label.String()) != NULL) if (FindItem(label.String()) != NULL)
continue; continue;
ProtocolLooper* looper = Server::Get()->GetProtocolLooper(instance); ProtocolLooper* looper = fServer->GetProtocolLooper(instance);
BBitmap* icon = _EnsureProtocolIcon(label.String(), looper); BBitmap* icon = _EnsureProtocolIcon(label.String(), looper);
BMessage* message = new BMessage(fAccountMessage); BMessage* message = new BMessage(fAccountMessage);

View File

@ -10,10 +10,13 @@
#include "Observer.h" #include "Observer.h"
class ProtocolLooper; class ProtocolLooper;
class Server;
class AccountsMenu : public BPopUpMenu, public Observer { class AccountsMenu : public BPopUpMenu, public Observer {
public: public:
AccountsMenu(const char* name, BMessage msg,
BMessage* allMsg, Server* server);
AccountsMenu(const char* name, BMessage msg, AccountsMenu(const char* name, BMessage msg,
BMessage* allMsg = NULL); BMessage* allMsg = NULL);
~AccountsMenu(); ~AccountsMenu();
@ -21,7 +24,7 @@ public:
virtual void ObserveInteger(int32 what, int32 value); virtual void ObserveInteger(int32 what, int32 value);
void SetDefaultSelection(BMenuItem* item); void SetDefaultSelection(BMenuItem* item);
static int64 GetDefaultSelection() { return fDefaultSelection; } int64 GetDefaultSelection() { return fDefaultSelection; }
private: private:
void _PopulateMenu(); void _PopulateMenu();
@ -34,6 +37,7 @@ private:
BMessage fAccountMessage; BMessage fAccountMessage;
BMessage* fAllMessage; BMessage* fAllMessage;
static int64 fDefaultSelection; static int64 fDefaultSelection;
Server* fServer;
}; };
#endif // _ACCOUNTS_MENU_H #endif // _ACCOUNTS_MENU_H

View File

@ -71,7 +71,7 @@ ConversationItem::ObserveInteger(int32 what, int32 num)
case INT_NEW_MENTION: case INT_NEW_MENTION:
fStatus |= kMentioned; fStatus |= kMentioned;
break; break;
case INT_CONV_VIEW_SELECTED: case INT_WINDOW_FOCUSED:
fStatus = 0; fStatus = 0;
break; break;
} }

View File

@ -15,10 +15,10 @@
#include "Conversation.h" #include "Conversation.h"
#include "ConversationAccountItem.h" #include "ConversationAccountItem.h"
#include "ConversationItem.h" #include "ConversationItem.h"
#include "Flags.h"
#include "MainWindow.h" #include "MainWindow.h"
#include "ProtocolLooper.h" #include "ProtocolLooper.h"
#include "Server.h" #include "Server.h"
#include "TheApp.h"
#undef B_TRANSLATION_CONTEXT #undef B_TRANSLATION_CONTEXT
@ -167,7 +167,8 @@ ConversationListView::RemoveConversation(Conversation* chat)
void void
ConversationListView::AddAccount(int64 instance) ConversationListView::AddAccount(int64 instance)
{ {
ProtocolLooper* looper = Server::Get()->GetProtocolLooper(instance); Server* server = ((TheApp*)be_app)->GetMainWindow()->GetServer();
ProtocolLooper* looper = server->GetProtocolLooper(instance);
if (looper == NULL) if (looper == NULL)
return; return;
AddItem(looper->GetListItem()); AddItem(looper->GetListItem());
@ -189,7 +190,7 @@ ConversationListView::RemoveAccount(int64 instance)
} }
} }
if (CountItems() == 0) if (CountItems() == 0)
((MainWindow*)Window())->SetConversation(NULL); ((TheApp*)be_app)->GetMainWindow()->SetConversation(NULL);
} }
@ -214,6 +215,7 @@ ConversationListView::_ConversationPopUp()
Conversation* chat = item->GetConversation(); Conversation* chat = item->GetConversation();
ProtocolLooper* looper = chat->GetProtocolLooper(); ProtocolLooper* looper = chat->GetProtocolLooper();
Server* server = ((TheApp*)be_app)->GetMainWindow()->GetServer();
_AddDefaultItems(menu, chat); _AddDefaultItems(menu, chat);
BObjectList<BMessage> items = looper->Protocol()->ChatPopUpItems(); BObjectList<BMessage> items = looper->Protocol()->ChatPopUpItems();
@ -245,10 +247,10 @@ ConversationListView::_ConversationPopUp()
msg->AddString("chat_id", id); \ msg->AddString("chat_id", id); \
msg->AddInt64("instance", instance); \ msg->AddInt64("instance", instance); \
msg->AddInt32("flag", flag); \ msg->AddInt32("flag", flag); \
\ \
item = new BMenuItem(name, msg); \ item = new BMenuItem(name, msg); \
item->SetTarget(Window()); \ item->SetTarget(Window()); \
\ \
if (!(chat->DisallowedFlags() &flag)) { \ if (!(chat->DisallowedFlags() &flag)) { \
if (chat->GetFlags() & flag) \ if (chat->GetFlags() & flag) \
item->SetMarked(true); \ item->SetMarked(true); \
@ -300,7 +302,7 @@ ConversationListView::_BlankPopUp()
{ {
bool enabled = false; bool enabled = false;
Server* server = Server::Get(); Server* server = ((TheApp*)be_app)->GetMainWindow()->GetServer();
if (server != NULL && server->GetAccounts().CountItems() > 0) if (server != NULL && server->GetAccounts().CountItems() > 0)
enabled = true; enabled = true;

View File

@ -1,6 +1,6 @@
/* /*
* Copyright 2009-2011, Andrea Anzani. All rights reserved. * Copyright 2009-2011, Andrea Anzani. All rights reserved.
* Copyright 2021-2022, Jaidyn Levesque. All rights reserved. * Copyright 2021, Jaidyn Levesque. All rights reserved.
* Distributed under the terms of the MIT License. * Distributed under the terms of the MIT License.
* *
* Authors: * Authors:
@ -23,11 +23,10 @@
#include "AppMessages.h" #include "AppMessages.h"
#include "AppPreferences.h" #include "AppPreferences.h"
#include "ChatOMatic.h"
#include "ChatProtocolMessages.h" #include "ChatProtocolMessages.h"
#include "Contact.h"
#include "Conversation.h" #include "Conversation.h"
#include "NotifyMessage.h" #include "NotifyMessage.h"
#include "ProtocolLooper.h"
#include "ProtocolManager.h" #include "ProtocolManager.h"
#include "RenderView.h" #include "RenderView.h"
#include "SendTextView.h" #include "SendTextView.h"
@ -69,15 +68,7 @@ ConversationView::AttachedToWindow()
if (fSubjectTextView->Text() != fConversation->GetSubject()) if (fSubjectTextView->Text() != fConversation->GetSubject())
fSubjectTextView->SetText(fConversation->GetSubject()); fSubjectTextView->SetText(fConversation->GetSubject());
} }
} NotifyInteger(INT_WINDOW_FOCUSED, 0);
void
ConversationView::Show()
{
BView::Show();
NotifyInteger(INT_CONV_VIEW_SELECTED, 0);
fSendView->MakeFocus(true); fSendView->MakeFocus(true);
fSendView->Invalidate(); fSendView->Invalidate();
} }
@ -134,7 +125,7 @@ ConversationView::ImMessage(BMessage* msg)
case IM_MESSAGE_RECEIVED: case IM_MESSAGE_RECEIVED:
{ {
_AppendOrEnqueueMessage(msg); _AppendOrEnqueueMessage(msg);
_ScrollToBottom(); fReceiveView->ScrollToBottom();
break; break;
} }
case IM_MESSAGE_SENT: case IM_MESSAGE_SENT:
@ -142,12 +133,25 @@ ConversationView::ImMessage(BMessage* msg)
{ {
_AppendOrEnqueueMessage(msg); _AppendOrEnqueueMessage(msg);
if (im_what == IM_MESSAGE_SENT) if (im_what == IM_MESSAGE_SENT)
_ScrollToBottom(); fReceiveView->ScrollToBottom();
break; break;
} }
case IM_ROOM_JOINED:
{
BMessage msg;
msg.AddString("body", B_TRANSLATE("** You joined the room.\n"));
_AppendOrEnqueueMessage(&msg);
fReceiveView->ScrollToBottom();
}
case IM_ROOM_CREATED:
{
BMessage msg;
msg.AddString("body", B_TRANSLATE("** You created the room.\n"));
_AppendOrEnqueueMessage(&msg);
fReceiveView->ScrollToBottom();
}
case IM_ROOM_PARTICIPANT_JOINED: case IM_ROOM_PARTICIPANT_JOINED:
{ {
if (AppPreferences::Get()->MembershipUpdates == true)
_UserMessage(B_TRANSLATE("%user% has joined the room.\n"), _UserMessage(B_TRANSLATE("%user% has joined the room.\n"),
B_TRANSLATE("%user% has joined the room (%body%).\n"), B_TRANSLATE("%user% has joined the room (%body%).\n"),
msg); msg);
@ -155,7 +159,6 @@ ConversationView::ImMessage(BMessage* msg)
} }
case IM_ROOM_PARTICIPANT_LEFT: case IM_ROOM_PARTICIPANT_LEFT:
{ {
if (AppPreferences::Get()->MembershipUpdates == true)
_UserMessage(B_TRANSLATE("%user% has left the room.\n"), _UserMessage(B_TRANSLATE("%user% has left the room.\n"),
B_TRANSLATE("%user% has left the room (%body%).\n"), B_TRANSLATE("%user% has left the room (%body%).\n"),
msg); msg);
@ -306,10 +309,10 @@ void
ConversationView::GetWeights(float* horizChat, float* horizList, ConversationView::GetWeights(float* horizChat, float* horizList,
float* vertChat, float* vertSend) float* vertChat, float* vertSend)
{ {
*horizChat = fHorizSplit->ItemWeight((int32)0); *horizChat = fHorizSplit->ItemWeight(0);
*horizList = fHorizSplit->ItemWeight((int32)1); *horizList = fHorizSplit->ItemWeight(1);
*vertChat = fVertSplit->ItemWeight((int32)0); *vertChat = fVertSplit->ItemWeight(0);
*vertSend = fVertSplit->ItemWeight((int32)1); *vertSend = fVertSplit->ItemWeight(1);
} }
@ -384,27 +387,10 @@ ConversationView::_InitInterface()
bool bool
ConversationView::_AppendOrEnqueueMessage(BMessage* msg) ConversationView::_AppendOrEnqueueMessage(BMessage* msg)
{ {
// Fill the message with user information not provided by protocol
BString user_id = msg->FindString("user_id");
if (msg->FindString("user_id", &user_id) == B_OK) {
User* user = NULL;
if (fConversation != NULL)
user = fConversation->UserById(user_id);
if (user != NULL) {
if (msg->HasString("user_name") == false)
if (user->GetName().IsEmpty() == false)
msg->AddString("user_name", user->GetName());
msg->AddColor("user_color", user->fItemColor);
}
if (msg->HasString("user_name") == false)
msg->AddString("user_name", user_id);
}
// Fill the message with receive time if not provided
if (msg->HasInt64("when") == false) if (msg->HasInt64("when") == false)
msg->AddInt64("when", (int64)time(NULL)); msg->AddInt64("when", (int64)time(NULL));
// If not attached to a chat window, then re-handle this message // If not attached to the chat window, then re-handle this message
// later [AttachedToWindow()], since you can't edit an unattached // later [AttachedToWindow()], since you can't edit an unattached
// RenderView. // RenderView.
if (Window() == NULL) { if (Window() == NULL) {
@ -437,16 +423,31 @@ ConversationView::_AppendMessage(BMessage* msg)
} }
// Otherwise, it's message time! // Otherwise, it's message time!
int64 timeInt = msg->GetInt64("when", time(NULL)); int64 timeInt;
BString user_id;
BString user_name = msg->FindString("user_name"); BString user_name = msg->FindString("user_name");
rgb_color userColor = msg->GetColor("user_color", ui_color(B_PANEL_TEXT_COLOR));
BString body; BString body;
rgb_color userColor = ui_color(B_PANEL_TEXT_COLOR);
if (msg->FindString("body", &body) != B_OK) if (msg->FindString("body", &body) != B_OK)
return; return;
if (msg->FindInt64("when", &timeInt) != B_OK)
timeInt = (int64)time(NULL);
if (msg->FindString("user_id", &user_id) == B_OK) {
User* user = NULL;
if (fConversation != NULL
&& (user = fConversation->UserById(user_id)) != NULL) {
user_name = user->GetName();
userColor = user->fItemColor;
}
else if (user_name.IsEmpty() == true)
user_name = user_id;
}
if (user_name.IsEmpty() == true) { if (user_name.IsEmpty() == true) {
fReceiveView->AppendGeneric(body, timeInt); fReceiveView->AppendGeneric(body);
return; return;
} }
@ -454,7 +455,7 @@ ConversationView::_AppendMessage(BMessage* msg)
BString meMsg = "** "; BString meMsg = "** ";
meMsg << user_name.String() << " "; meMsg << user_name.String() << " ";
meMsg << body.RemoveFirst("/me "); meMsg << body.RemoveFirst("/me ");
fReceiveView->AppendGeneric(meMsg.String(), timeInt); fReceiveView->AppendGeneric(meMsg.String());
return; return;
} }
@ -515,14 +516,6 @@ ConversationView::_AppendMessage(BMessage* msg)
} }
void
ConversationView::_ScrollToBottom()
{
if (IsHidden() == false)
fReceiveView->ScrollToBottom();
}
void void
ConversationView::_EnableStartingFaces(BMessage* msg, int32 index, uint16* face, ConversationView::_EnableStartingFaces(BMessage* msg, int32 index, uint16* face,
UInt16IntMap* indices, int32* next) UInt16IntMap* indices, int32* next)
@ -627,7 +620,7 @@ ConversationView::_UserMessage(const char* format, const char* bodyFormat,
BMessage newMsg; BMessage newMsg;
newMsg.AddString("body", newBody); newMsg.AddString("body", newBody);
_AppendOrEnqueueMessage(&newMsg); _AppendOrEnqueueMessage(&newMsg);
_ScrollToBottom(); fReceiveView->ScrollToBottom();
} }

View File

@ -1,6 +1,6 @@
/* /*
* Copyright 2009-2011, Andrea Anzani. All rights reserved. * Copyright 2009-2011, Andrea Anzani. All rights reserved.
* Copyright 2021-2022, Jaidyn Levesque. All rights reserved. * Copyright 2021, Jaidyn Levesque. All rights reserved.
* Distributed under the terms of the MIT License. * Distributed under the terms of the MIT License.
*/ */
#ifndef _CHAT_VIEW_H #ifndef _CHAT_VIEW_H
@ -26,13 +26,14 @@ class UserListView;
const uint32 kClearText = 'CVct'; const uint32 kClearText = 'CVct';
typedef KeyMap<uint16, int32> UInt16IntMap;
class ConversationView : public BGroupView, public Observer, public Notifier { class ConversationView : public BGroupView, public Observer, public Notifier {
public: public:
ConversationView(Conversation* chat = NULL); ConversationView(Conversation* chat = NULL);
virtual void AttachedToWindow(); virtual void AttachedToWindow();
void Show();
virtual void MessageReceived(BMessage* message); virtual void MessageReceived(BMessage* message);
void ImMessage(BMessage* msg); void ImMessage(BMessage* msg);
@ -52,15 +53,11 @@ public:
float vertChat, float vertSend); float vertChat, float vertSend);
private: private:
typedef KeyMap<uint16, int32> UInt16IntMap;
void _InitInterface(); void _InitInterface();
bool _AppendOrEnqueueMessage(BMessage* msg); bool _AppendOrEnqueueMessage(BMessage* msg);
void _AppendMessage(BMessage* msg); void _AppendMessage(BMessage* msg);
void _ScrollToBottom();
// Helper functions for _AppendFormattedMessage() // Helper functions for _AppendFormattedMessage()
void _EnableStartingFaces(BMessage* msg, int32 index, void _EnableStartingFaces(BMessage* msg, int32 index,
uint16* face, UInt16IntMap* indices, int32* next); uint16* face, UInt16IntMap* indices, int32* next);

View File

@ -18,10 +18,10 @@ RenderView::RenderView(const char* name)
void void
RenderView::AppendGeneric(const char* message, int64 when) RenderView::AppendGeneric(const char* message)
{ {
if (BString(message).IsEmpty() == true) return; if (BString(message).IsEmpty() == true) return;
AppendTimestamp(when); AppendTimestamp(time(NULL));
Append(message, ui_color(B_PANEL_TEXT_COLOR), B_BOLD_FACE); Append(message, ui_color(B_PANEL_TEXT_COLOR), B_BOLD_FACE);
if (BString(message).EndsWith("\n") == false) Append("\n"); if (BString(message).EndsWith("\n") == false) Append("\n");
} }

View File

@ -12,7 +12,7 @@ class RenderView : public RunView {
public: public:
RenderView(const char* name); RenderView(const char* name);
void AppendGeneric(const char* message, int64 when); void AppendGeneric(const char* message);
void AppendUserstamp(const char* nick, rgb_color nameColor); void AppendUserstamp(const char* nick, rgb_color nameColor);
void AppendTimestamp(time_t time = 0); void AppendTimestamp(time_t time = 0);

View File

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

View File

@ -1,35 +0,0 @@
/*
* Copyright 2021, Jaidyn Levesque <jadedctrl@teknik.io>
* All rights reserved. Distributed under the terms of the MIT license.
*/
#include "RoomListRow.h"
#include <ColumnTypes.h>
RoomListRow::RoomListRow(BMessage* msg)
:
BRow(),
fMessage(new BMessage(*msg)),
fInstance(-1)
{
int64 proto = msg->FindInt64("instance");
BString id = msg->FindString("chat_id");
BString name = msg->GetString("chat_name", id);
BString desc = msg->FindString("subject");
BString category = msg->FindString("category");
int32 user_n = msg->GetInt32("user_count", -1);
SetField(new BStringField(name), kNameColumn);
SetField(new BStringField(desc), kDescColumn);
SetField(new BStringField(category), kCatColumn);
if (user_n > -1)
SetField(new BIntegerField(user_n), kUserColumn);
}
RoomListRow::~RoomListRow()
{
delete fMessage;
}

View File

@ -1,32 +0,0 @@
/*
* Copyright 2021, Jaidyn Levesque <jadedctrl@teknik.io>
* All rights reserved. Distributed under the terms of the MIT license.
*/
#ifndef _ROOM_LIST_ROW_H
#define _ROOM_LIST_ROW_H
#include <ColumnListView.h>
enum {
kNameColumn,
kDescColumn,
kCatColumn,
kUserColumn
};
class RoomListRow : public BRow {
public:
RoomListRow(BMessage* msg);
~RoomListRow();
BMessage* Message() { return fMessage; }
int64 Instance() { return fInstance; }
private:
int64 fInstance;
BMessage* fMessage;
};
#endif // _ROOM_LIST_ROW_H

View File

@ -20,10 +20,10 @@
#include "AppMessages.h" #include "AppMessages.h"
#include "AppPreferences.h" #include "AppPreferences.h"
#include "ChatOMatic.h"
#include "ChatProtocolMessages.h" #include "ChatProtocolMessages.h"
#include "RosterItem.h" #include "RosterItem.h"
#include "RosterListView.h" #include "RosterListView.h"
#include "Server.h"
#undef B_TRANSLATION_CONTEXT #undef B_TRANSLATION_CONTEXT
@ -33,10 +33,11 @@
const uint32 kSearchContact = 'RWSC'; const uint32 kSearchContact = 'RWSC';
RosterView::RosterView(const char* title, bigtime_t account) RosterView::RosterView(const char* title, Server* server, bigtime_t account)
: :
BGroupView(title, B_VERTICAL, B_USE_DEFAULT_SPACING), BGroupView(title, B_VERTICAL, B_USE_DEFAULT_SPACING),
fAccount(-1), fAccount(-1),
fServer(server),
fManualItem(new BStringItem("")), fManualItem(new BStringItem("")),
fManualStr("Select user %user%" B_UTF8_ELLIPSIS) fManualStr("Select user %user%" B_UTF8_ELLIPSIS)
{ {
@ -121,7 +122,7 @@ RosterView::ImMessage(BMessage* msg)
|| user_id.IsEmpty() == true) || user_id.IsEmpty() == true)
return; return;
Contact* contact = Server::Get()->ContactById(user_id, instance); Contact* contact = fServer->ContactById(user_id, instance);
if (contact == NULL) if (contact == NULL)
return; return;
@ -189,7 +190,7 @@ RosterView::ImMessage(BMessage* msg)
|| msg->FindInt64("instance", &instance) != B_OK || msg->FindInt64("instance", &instance) != B_OK
|| user_id.IsEmpty() == true) || user_id.IsEmpty() == true)
return; return;
Contact* contact = Server::Get()->ContactById(user_id, instance); Contact* contact = fServer->ContactById(user_id, instance);
if (contact == NULL) if (contact == NULL)
return; return;
RosterItem* rosterItem = contact->GetRosterItem(); RosterItem* rosterItem = contact->GetRosterItem();
@ -208,7 +209,7 @@ RosterView::ImMessage(BMessage* msg)
|| user_id.IsEmpty() == true) || user_id.IsEmpty() == true)
return; return;
Contact* contact = Server::Get()->ContactById(user_id, instance); Contact* contact = fServer->ContactById(user_id, instance);
if (contact == NULL) if (contact == NULL)
return; return;
@ -268,9 +269,9 @@ RosterView::_RosterMap()
{ {
RosterMap contacts; RosterMap contacts;
if (fAccount < 0) if (fAccount < 0)
contacts = Server::Get()->Contacts(); contacts = fServer->Contacts();
else { else {
ProtocolLooper* looper = Server::Get()->GetProtocolLooper(fAccount); ProtocolLooper* looper = fServer->GetProtocolLooper(fAccount);
contacts = looper->Contacts(); contacts = looper->Contacts();
} }
return contacts; return contacts;

View File

@ -14,17 +14,18 @@
#include <GroupView.h> #include <GroupView.h>
#include "Maps.h" #include "Server.h"
class BStringItem; class BStringItem;
class BTextControl; class BTextControl;
class RosterItem; class RosterItem;
class RosterListView; class RosterListView;
class Server;
class RosterView : public BGroupView { class RosterView : public BGroupView {
public: public:
RosterView(const char* title, bigtime_t account = -1); RosterView(const char* title, Server* server, bigtime_t account = -1);
void MessageReceived(BMessage* message); void MessageReceived(BMessage* message);
void ImMessage(BMessage* msg); void ImMessage(BMessage* msg);
@ -45,6 +46,7 @@ public:
private: private:
RosterMap _RosterMap(); RosterMap _RosterMap();
Server* fServer;
RosterListView* fListView; RosterListView* fListView;
BTextControl* fSearchBox; BTextControl* fSearchBox;
bigtime_t fAccount; bigtime_t fAccount;

View File

@ -1,3 +1,4 @@
#include <iostream>
/* /*
* Copyright 2021, Jaidyn Levesque <jadedctrl@teknik.io> * Copyright 2021, Jaidyn Levesque <jadedctrl@teknik.io>
* All rights reserved. Distributed under the terms of the MIT license. * All rights reserved. Distributed under the terms of the MIT license.
@ -9,7 +10,9 @@
#include <Window.h> #include <Window.h>
#include "AppMessages.h" #include "AppMessages.h"
#include "MainWindow.h"
#include "Server.h" #include "Server.h"
#include "TheApp.h"
SendTextView::SendTextView(const char* name, ConversationView* convView) SendTextView::SendTextView(const char* name, ConversationView* convView)
@ -35,27 +38,22 @@ SendTextView::KeyDown(const char* bytes, int32 numBytes)
fCurrentIndex = 0; fCurrentIndex = 0;
fCurrentWord.SetTo(""); fCurrentWord.SetTo("");
for (int i = 0; i < numBytes; i++) { if ((bytes[0] == B_UP_ARROW) && (modifiers == 0)) {
if ((bytes[i] == B_UP_ARROW) && (modifiers == 0)) {
_UpHistory(); _UpHistory();
return; return;
} }
else if ((bytes[i] == B_DOWN_ARROW) && (modifiers == 0)) { else if ((bytes[0] == B_DOWN_ARROW) && (modifiers == 0)) {
_DownHistory(); _DownHistory();
return; return;
} }
if ((bytes[i] == B_ENTER) if ((bytes[0] == B_ENTER) && (modifiers & B_COMMAND_KEY))
&& ((modifiers & B_COMMAND_KEY) || (modifiers & B_SHIFT_KEY))) {
Insert("\n"); Insert("\n");
return; else if ((bytes[0] == B_ENTER) && (modifiers == 0)) {
}
else if (bytes[i] == B_ENTER) {
_AppendHistory(); _AppendHistory();
fChatView->MessageReceived(new BMessage(APP_CHAT)); fChatView->MessageReceived(new BMessage(APP_CHAT));
return;
}
} }
else
BTextView::KeyDown(bytes, numBytes); BTextView::KeyDown(bytes, numBytes);
} }
@ -124,7 +122,8 @@ SendTextView::_CommandNames()
if (fCurrentIndex == 0) { if (fCurrentIndex == 0) {
int64 instance = fChatView->GetConversation()->GetProtocolLooper()->GetInstance(); int64 instance = fChatView->GetConversation()->GetProtocolLooper()->GetInstance();
BStringList cmdNames; BStringList cmdNames;
CommandMap cmds = Server::Get()->Commands(instance); CommandMap cmds =
((TheApp*)be_app)->GetMainWindow()->GetServer()->Commands(instance);
for (int i = 0; i < cmds.CountItems(); i++) for (int i = 0; i < cmds.CountItems(); i++)
cmdNames.Add(cmds.KeyAt(i)); cmdNames.Add(cmds.KeyAt(i));

View File

@ -36,9 +36,10 @@ const int32 kSelectAccount = 'SVsa';
const int32 kSetNick = 'SVsn'; const int32 kSetNick = 'SVsn';
StatusView::StatusView(const char* name) StatusView::StatusView(const char* name, Server* server)
: :
BView(name, B_WILL_DRAW), BView(name, B_WILL_DRAW),
fServer(server),
fAccount(-1) fAccount(-1)
{ {
// Nick name // Nick name
@ -84,7 +85,7 @@ StatusView::StatusView(const char* name)
// Changing the account used // Changing the account used
fAccountsMenu = new AccountsMenu("statusAccountsMenu", fAccountsMenu = new AccountsMenu("statusAccountsMenu",
BMessage(kSelectAccount), new BMessage(kSelectAccount)); BMessage(kSelectAccount), new BMessage(kSelectAccount), fServer);
fAccountsButton = new MenuButton("statusAccountsButton", "", new BMessage()); fAccountsButton = new MenuButton("statusAccountsButton", "", new BMessage());
fAccountsButton->SetMenu(fAccountsMenu); fAccountsButton->SetMenu(fAccountsMenu);
@ -194,9 +195,9 @@ StatusView::_SetToAccount()
{ {
int64 instance = fAccount; int64 instance = fAccount;
if (instance == -1) if (instance == -1)
instance = Server::Get()->GetActiveAccounts().ValueAt(0); instance = fServer->GetActiveAccounts().ValueAt(0);
ProtocolLooper* looper = Server::Get()->GetProtocolLooper(instance); ProtocolLooper* looper = fServer->GetProtocolLooper(instance);
if (looper == NULL || looper->GetOwnContact() == NULL) if (looper == NULL || looper->GetOwnContact() == NULL)
return; return;
Contact* contact = looper->GetOwnContact(); Contact* contact = looper->GetOwnContact();

View File

@ -17,10 +17,11 @@ class AccountsMenu;
class BitmapView; class BitmapView;
class EnterTextView; class EnterTextView;
class MenuButton; class MenuButton;
class Server;
class StatusView : public BView, public Observer { class StatusView : public BView, public Observer {
public: public:
StatusView(const char* name); StatusView(const char* name, Server* server);
virtual void AttachedToWindow(); virtual void AttachedToWindow();
virtual void MessageReceived(BMessage* msg); virtual void MessageReceived(BMessage* msg);
@ -44,6 +45,8 @@ private:
MenuButton* fAccountsButton; MenuButton* fAccountsButton;
AccountsMenu* fAccountsMenu; AccountsMenu* fAccountsMenu;
int64 fAccount; int64 fAccount;
Server* fServer;
}; };
#endif // _STATUS_VIEW_H #endif // _STATUS_VIEW_H

View File

@ -13,9 +13,11 @@
#include "AppMessages.h" #include "AppMessages.h"
#include "ChatProtocolMessages.h" #include "ChatProtocolMessages.h"
#include "Conversation.h" #include "Conversation.h"
#include "MainWindow.h"
#include "ProtocolLooper.h" #include "ProtocolLooper.h"
#include "Role.h" #include "Role.h"
#include "Server.h" #include "Server.h"
#include "TheApp.h"
#include "User.h" #include "User.h"
#include "UserInfoWindow.h" #include "UserInfoWindow.h"
#include "UserItem.h" #include "UserItem.h"
@ -106,7 +108,8 @@ UserListView::_UserPopUp()
Role* selected_role = fChat->GetRole(selected_user->GetId()); Role* selected_role = fChat->GetRole(selected_user->GetId());
BObjectList<BMessage> items = Server::Get()->UserPopUpItems(); Server* server = ((TheApp*)be_app)->GetMainWindow()->GetServer();
BObjectList<BMessage> items = server->UserPopUpItems();
BObjectList<BMessage> protoItems = fChat->GetProtocolLooper()->Protocol()->UserPopUpItems(); BObjectList<BMessage> protoItems = fChat->GetProtocolLooper()->Protocol()->UserPopUpItems();
items.AddList(&protoItems); items.AddList(&protoItems);

View File

@ -0,0 +1,69 @@
/*
* Copyright 2010-2011, Pier Luigi Fiorini. All rights reserved.
* Copyright 2007-2009, Haiku, Inc. All rights reserved.
* Distributed under the terms of the MIT License.
*
* Authors:
* Pier Luigi Fiorini, pierluigi.fiorini@gmail.com
* Ryan Leavengood, leavengood@gmail.com
*/
#include <Alert.h>
#include <Catalog.h>
#include <Font.h>
#include <String.h>
#include <TextView.h>
#include "AboutWindow.h"
#undef B_TRANSLATION_CONTEXT
#define B_TRANSLATION_CONTEXT "About window"
AboutWindow::AboutWindow(const char* appName, const char** holders,
const char** authors, const char* extraInfo)
{
fAppName = new BString(appName);
// Build the text to display
int32 i;
BString text(appName);
text << "\n\n";
for (i = 0; holders[i]; i++)
text << B_TRANSLATE("Copyright " B_UTF8_COPYRIGHT " ") << holders[i]
<< "\n";
text << B_TRANSLATE("\nWritten by:\n");
for (int32 i = 0; authors[i]; i++) {
text << " " << authors[i] << "\n";
}
// The extra information is optional
if (extraInfo != NULL)
text << "\n" << extraInfo << "\n";
fText = new BString(text);
}
AboutWindow::~AboutWindow()
{
delete fText;
delete fAppName;
}
void
AboutWindow::Show()
{
BAlert* alert = new BAlert(B_TRANSLATE("About" B_UTF8_ELLIPSIS),
fText->String(), B_TRANSLATE("Close"));
BTextView* view = alert->TextView();
BFont font;
view->SetStylable(true);
view->GetFont(&font);
font.SetFace(B_BOLD_FACE);
font.SetSize(font.Size() * 1.7f);
view->SetFontAndColor(0, fAppName->Length(), &font);
alert->Go();
}

View File

@ -0,0 +1,24 @@
/*
* Copyright 2010-2011, Pier Luigi Fiorini. All rights reserved.
* Copyright 2007-2009, Haiku, Inc. All rights reserved.
* Distributed under the terms of the MIT License.
*/
#ifndef _ABOUT_WINDOW_H
#define _ABOUT_WINDOW_H
#include <String.h>
class AboutWindow {
public:
AboutWindow(const char* appName, const char** holders,
const char** authors, const char* extraInfo = NULL);
virtual ~AboutWindow();
void Show();
private:
BString* fAppName;
BString* fText;
};
#endif // _ABOUT_WINDOW_H

View File

@ -27,7 +27,9 @@
#include "ChatProtocolMessages.h" #include "ChatProtocolMessages.h"
#include "ProtocolManager.h" #include "ProtocolManager.h"
#include "ProtocolSettings.h" #include "ProtocolSettings.h"
#include "MainWindow.h"
#include "Server.h" #include "Server.h"
#include "TheApp.h"
#undef B_TRANSLATION_CONTEXT #undef B_TRANSLATION_CONTEXT
@ -286,7 +288,8 @@ int64
AccountsWindow::_AccountInstance(const char* account) AccountsWindow::_AccountInstance(const char* account)
{ {
bool found = false; bool found = false;
AccountInstances accs = Server::Get()->GetAccounts(); AccountInstances accs =
((TheApp*)be_app)->GetMainWindow()->GetServer()->GetAccounts();
int64 instance = accs.ValueFor(BString(account), &found); int64 instance = accs.ValueFor(BString(account), &found);
if (found == false) if (found == false)

View File

@ -1,34 +1,29 @@
/* /*
* Copyright 2009-2011, Andrea Anzani. All rights reserved. * Copyright 2009-2011, Andrea Anzani. All rights reserved.
* Copyright 2009-2011, Pier Luigi Fiorini. All rights reserved. * Copyright 2009-2011, Pier Luigi Fiorini. All rights reserved.
* Copyright 2021-2022, Jaidyn Levesque. All rights reserved. * Copyright 2021, Jaidyn Levesque. All rights reserved.
* Distributed under the terms of the MIT License. * Distributed under the terms of the MIT License.
* *
* Authors: * Authors:
* Andrea Anzani, andrea.anzani@gmail.com * Andrea Anzani, andrea.anzani@gmail.com
* Pier Luigi Fiorini, pierluigi.fiorini@gmail.com * Pier Luigi Fiorini, pierluigi.fiorini@gmail.com
* Jaidyn Levesque, jadedctrl@teknik.io * Jaidyn Levesque, jadedctrl@teknik.io
* Humdinger, humdingerb@gmail.com
*/ */
#include <Application.h> #include <Application.h>
#include <Alert.h> #include <Alert.h>
#include <Beep.h> #include <Beep.h>
#include <CardLayout.h>
#include <Catalog.h> #include <Catalog.h>
#include <LayoutBuilder.h> #include <LayoutBuilder.h>
#include <MenuBar.h> #include <MenuBar.h>
#include <PathFinder.h>
#include <Roster.h>
#include <ScrollView.h> #include <ScrollView.h>
#include <TranslationUtils.h> #include <TranslationUtils.h>
#include <stdio.h>
#include "AccountDialog.h" #include "AccountDialog.h"
#include "AccountsWindow.h" #include "AccountsWindow.h"
#include "AppMessages.h" #include "AppMessages.h"
#include "AppPreferences.h" #include "AppPreferences.h"
#include "ChatOMatic.h"
#include "ChatProtocolAddOn.h" #include "ChatProtocolAddOn.h"
#include "ChatProtocolMessages.h" #include "ChatProtocolMessages.h"
#include "ConversationItem.h" #include "ConversationItem.h"
@ -40,10 +35,8 @@
#include "ProtocolManager.h" #include "ProtocolManager.h"
#include "ProtocolSettings.h" #include "ProtocolSettings.h"
#include "ReplicantStatusView.h" #include "ReplicantStatusView.h"
#include "RoomListWindow.h"
#include "RosterEditWindow.h" #include "RosterEditWindow.h"
#include "RosterWindow.h" #include "RosterWindow.h"
#include "Server.h"
#include "StatusManager.h" #include "StatusManager.h"
#include "StatusView.h" #include "StatusView.h"
#include "TemplateWindow.h" #include "TemplateWindow.h"
@ -62,10 +55,12 @@ MainWindow::MainWindow()
B_TRANSLATE_SYSTEM_NAME(APP_NAME), B_TITLED_WINDOW, 0), B_TRANSLATE_SYSTEM_NAME(APP_NAME), B_TITLED_WINDOW, 0),
fWorkspaceChanged(false), fWorkspaceChanged(false),
fConversation(NULL), fConversation(NULL),
fRosterWindow(NULL) fRosterWindow(NULL),
fServer(NULL)
{ {
// Filter messages using Server // Filter messages using Server
AddFilter(Server::Get()); fServer = new Server();
AddFilter(fServer);
_InitInterface(); _InitInterface();
@ -85,16 +80,7 @@ MainWindow::Start()
MessageReceived(new BMessage(APP_SHOW_ACCOUNTS)); MessageReceived(new BMessage(APP_SHOW_ACCOUNTS));
// Login all accounts // Login all accounts
Server::Get()->LoginAll(); fServer->LoginAll();
}
void
MainWindow::Show()
{
if (fChatLayout->CountItems() == 0)
SetConversation(NULL);
BWindow::Show();
} }
@ -112,20 +98,12 @@ MainWindow::QuitRequested()
button_index = alert->Go(); button_index = alert->Go();
} }
AppPreferences::Get()->MainWindowListWeight = fSplitView->ItemWeight(0);
AppPreferences::Get()->MainWindowChatWeight = fSplitView->ItemWeight(1);
AppPreferences::Get()->MainWindowRect = Frame(); AppPreferences::Get()->MainWindowRect = Frame();
_SaveWeights();
if (button_index == 0) {
Server::Get()->Quit();
// ConversationViews will be removed by Server's deletion of Conversations,
// but some special views (protocol logs, the blank ConversationView)
// must be done manually
for (int i = fChatLayout->CountItems() - 1; i >= 0; i--)
fChatLayout->RemoveItem(i);
fChatLayout->RemoveSelf();
delete fChatLayout;
if(button_index == 0) {
fServer->Quit();
AppPreferences::Get()->Save(); AppPreferences::Get()->Save();
ReplicantStatusView::RemoveReplicant(); ReplicantStatusView::RemoveReplicant();
be_app->PostMessage(B_QUIT_REQUESTED); be_app->PostMessage(B_QUIT_REQUESTED);
@ -182,7 +160,7 @@ MainWindow::MessageReceived(BMessage* message)
newMsg->AddInt32("im_what", IM_CREATE_CHAT); newMsg->AddInt32("im_what", IM_CREATE_CHAT);
fRosterWindow = new RosterWindow(B_TRANSLATE("Invite contact to " fRosterWindow = new RosterWindow(B_TRANSLATE("Invite contact to "
"chat" B_UTF8_ELLIPSIS), newMsg, new BMessenger(this)); "chat" B_UTF8_ELLIPSIS), newMsg, new BMessenger(this), fServer);
fRosterWindow->Show(); fRosterWindow->Show();
break; break;
} }
@ -192,7 +170,7 @@ MainWindow::MessageReceived(BMessage* message)
createMsg->AddInt32("im_what", IM_CREATE_ROOM); createMsg->AddInt32("im_what", IM_CREATE_ROOM);
TemplateWindow* win = new TemplateWindow(B_TRANSLATE("Create room"), TemplateWindow* win = new TemplateWindow(B_TRANSLATE("Create room"),
"create_room", createMsg); "create_room", createMsg, fServer);
win->Show(); win->Show();
break; break;
} }
@ -202,7 +180,7 @@ MainWindow::MessageReceived(BMessage* message)
joinMsg->AddInt32("im_what", IM_JOIN_ROOM); joinMsg->AddInt32("im_what", IM_JOIN_ROOM);
TemplateWindow* win = new TemplateWindow(B_TRANSLATE("Join a room"), TemplateWindow* win = new TemplateWindow(B_TRANSLATE("Join a room"),
"join_room", joinMsg); "join_room", joinMsg, fServer);
win->Show(); win->Show();
break; break;
} }
@ -219,35 +197,15 @@ MainWindow::MessageReceived(BMessage* message)
ProtocolLooper* plooper = fConversation->GetProtocolLooper(); ProtocolLooper* plooper = fConversation->GetProtocolLooper();
BLooper* looper = (BLooper*)plooper; BLooper* looper = (BLooper*)plooper;
fRosterWindow = new RosterWindow(B_TRANSLATE("Invite contact to " fRosterWindow = new RosterWindow(B_TRANSLATE("Invite contact to "
"chat" B_UTF8_ELLIPSIS), invite, new BMessenger(looper), "chat" B_UTF8_ELLIPSIS), invite, new BMessenger(looper), fServer,
plooper->GetInstance()); plooper->GetInstance());
fRosterWindow->Show(); fRosterWindow->Show();
break; break;
} }
case APP_ROOM_DIRECTORY:
{
RoomListWindow::Get()->Show();
break;
}
case APP_ROOM_SEARCH:
{
if (fConversation != NULL) {
entry_ref ref;
BEntry entry(fConversation->CachePath().Path());
if (entry.GetRef(&ref) != B_OK)
break;
BMessage msg(B_REFS_RECEIVED);
msg.AddRef("refs", &ref);
BRoster roster;
roster.Launch("application/x-vnd.Haiku.TextSearch", &msg);
}
break;
}
case APP_EDIT_ROSTER: case APP_EDIT_ROSTER:
{ {
RosterEditWindow::Get()->Show(); RosterEditWindow::Get(fServer)->Show();
break; break;
} }
case APP_MOVE_UP: case APP_MOVE_UP:
@ -297,29 +255,6 @@ MainWindow::MessageReceived(BMessage* message)
fListView->RemoveAccount(message->GetInt64("instance", -1)); fListView->RemoveAccount(message->GetInt64("instance", -1));
break; break;
} }
case APP_SHOW_HELP:
{
// Borrowed from HaikuArchives/Calendar's _ShowHelp()
BPathFinder pathFinder;
BStringList paths;
BPath path;
BEntry entry;
status_t error = pathFinder.FindPaths(B_FIND_PATH_DOCUMENTATION_DIRECTORY,
"packages/chat_o_matic", paths);
for (int i = 0; i < paths.CountStrings(); ++i) {
if (error == B_OK && path.SetTo(paths.StringAt(i)) == B_OK
&& path.Append("Documentation.html") == B_OK)
{
entry = path.Path();
entry_ref ref;
entry.GetRef(&ref);
be_roster->Launch(&ref);
}
}
break;
}
case IM_MESSAGE: case IM_MESSAGE:
ImMessage(message); ImMessage(message);
break; break;
@ -341,7 +276,7 @@ MainWindow::ImMessage(BMessage* msg)
{ {
int64 instance; int64 instance;
if (msg->FindInt64("instance", &instance) == B_OK) { if (msg->FindInt64("instance", &instance) == B_OK) {
ProtocolLooper* looper = Server::Get()->GetProtocolLooper(instance); ProtocolLooper* looper = fServer->GetProtocolLooper(instance);
if (looper != NULL) { if (looper != NULL) {
Contact* contact = looper->GetOwnContact(); Contact* contact = looper->GetOwnContact();
contact->RegisterObserver(fStatusView); contact->RegisterObserver(fStatusView);
@ -376,7 +311,7 @@ MainWindow::ImMessage(BMessage* msg)
if (fRosterWindow != NULL) if (fRosterWindow != NULL)
fRosterWindow->PostMessage(msg); fRosterWindow->PostMessage(msg);
if (RosterEditWindow::Check() == true) if (RosterEditWindow::Check() == true)
RosterEditWindow::Get()->PostMessage(msg); RosterEditWindow::Get(fServer)->PostMessage(msg);
break; break;
} }
case IM_PROTOCOL_READY: { case IM_PROTOCOL_READY: {
@ -388,10 +323,6 @@ MainWindow::ImMessage(BMessage* msg)
fListView->AddAccount(msg->GetInt64("instance", -1)); fListView->AddAccount(msg->GetInt64("instance", -1));
break; break;
} }
case IM_ROOM_DIRECTORY:
if (RoomListWindow::Check() == true)
RoomListWindow::Get()->PostMessage(msg);
break;
case IM_PROTOCOL_DISABLE: case IM_PROTOCOL_DISABLE:
fStatusView->MessageReceived(msg); fStatusView->MessageReceived(msg);
break; break;
@ -412,52 +343,79 @@ MainWindow::WorkspaceActivated(int32 workspace, bool active)
void void
MainWindow::SetConversation(Conversation* chat) MainWindow::SetConversation(Conversation* chat)
{ {
if (chat == NULL) { fConversation = chat;
SetTitle(APP_NAME); if (chat != NULL) {
SetConversationView(fBackupChatView); SetConversationView(chat->GetView());
return;
}
_EnsureConversationView(chat);
bool found = false;
BLayoutItem* item = fChatList.ValueFor(chat, &found);
if (found == false)
return;
BString title(chat->GetName()); BString title(chat->GetName());
title << "" << APP_NAME; title << "" << APP_NAME;
SetTitle(title.String()); SetTitle(title.String());
}
// Remove "Protocol" menu else {
BMenuItem* chatMenuItem = fMenuBar->FindItem(B_TRANSLATE("Chat")); SetConversationView(fBackupChatView);
BMenuItem* protocolMenuItem = fMenuBar->FindItem(B_TRANSLATE("Protocol")); SetTitle(APP_NAME);
if (protocolMenuItem != NULL) }
fMenuBar->RemoveItem(protocolMenuItem);
// Populate new "Protocol" menu if need be
BMenu* protocolMenu = _CreateProtocolMenu();
if (protocolMenu != NULL)
fMenuBar->AddItem(protocolMenu, fMenuBar->IndexOf(chatMenuItem) + 1);
_SaveWeights();
fConversation = chat;
fChatLayout->SetVisibleItem(item);
_ApplyWeights();
} }
void void
MainWindow::SetConversationView(ConversationView* view) MainWindow::SetConversationView(ConversationView* chatView)
{ {
int32 index = fChatLayout->IndexOfView(view); // Save split weights
if (index < 0) { float weightChat = fRightView->ItemWeight((int32)0);
BLayoutItem* item = fChatLayout->AddView(view); float weightSend = fRightView->ItemWeight((int32)1);
fChatLayout->SetVisibleItem(item); float horizChat, horizList, vertChat, vertSend;
} else fChatView->GetWeights(&horizChat, &horizList, &vertChat, &vertSend);
fChatLayout->SetVisibleItem(index);
_ApplyWeights(); fRightView->RemoveChild(fRightView->FindView("chatView"));
fChatView = chatView;
fRightView->AddChild(fChatView, 9);
// Remove "Protocol" menu
BMenuItem* chatMenuItem = fMenuBar->FindItem("Protocol");
BMenu* chatMenu;
if (chatMenuItem != NULL && (chatMenu = chatMenuItem->Submenu()) != NULL)
fMenuBar->RemoveItem(chatMenu);
// Add and populate "Protocol" menu, if appropriate
if (fConversation != NULL) {
ProtocolLooper* looper = fConversation->GetProtocolLooper();
BObjectList<BMessage> menuItems = looper->Protocol()->MenuBarItems();
for (int i = 0; i < menuItems.CountItems(); i++) {
BMessage* itemMsg = menuItems.ItemAt(i);
BMessage* msg = new BMessage(*itemMsg);
BMessage toSend;
msg->FindMessage("_msg", &toSend);
toSend.AddString("chat_id", fConversation->GetId());
toSend.AddInt64("instance", looper->GetInstance());
msg->ReplaceMessage("_msg", &toSend);
BMenuItem* item = new BMenuItem(msg);
if (item == NULL)
continue;
if (msg->GetBool("x_to_protocol", true) == true)
item->SetTarget(looper);
else
item->SetTarget(this);
chatMenu->AddItem(item);
}
}
// Apply saved weights
fSplitView->SetItemWeight(0, AppPreferences::Get()->MainWindowListWeight, true);
fSplitView->SetItemWeight(1, AppPreferences::Get()->MainWindowChatWeight, true);
fChatView->SetWeights(horizChat, horizList, vertChat, vertSend);
if (weightChat * weightSend != 0) {
fRightView->SetItemWeight(0, weightChat, true);
fRightView->SetItemWeight(1, weightSend, true);
}
// Save ChatView weights to settings
AppPreferences::Get()->ChatViewHorizChatWeight = horizChat;
AppPreferences::Get()->ChatViewHorizListWeight = horizList;
AppPreferences::Get()->ChatViewVertChatWeight = vertChat;
AppPreferences::Get()->ChatViewVertSendWeight = vertSend;
} }
@ -466,13 +424,6 @@ MainWindow::RemoveConversation(Conversation* chat)
{ {
SetConversation(NULL); SetConversation(NULL);
bool found = false;
BLayoutItem* item = fChatList.ValueFor(chat, &found);
if (item != NULL)
item->RemoveSelf();
if (found == true)
fChatList.RemoveItemFor(chat);
int32 index = fListView->IndexOf(chat->GetListItem()); int32 index = fListView->IndexOf(chat->GetListItem());
if (index > 0) if (index > 0)
index--; index--;
@ -497,15 +448,24 @@ MainWindow::_InitInterface()
{ {
// Left side of window, Roomlist + Status // Left side of window, Roomlist + Status
fListView = new ConversationListView("roomList"); fListView = new ConversationListView("roomList");
fStatusView = new StatusView("statusView"); fStatusView = new StatusView("statusView", fServer);
fSplitView = new BSplitView(B_HORIZONTAL, 0); fSplitView = new BSplitView(B_HORIZONTAL, 0);
BScrollView* listScroll = new BScrollView("roomListScroll", fListView, BScrollView* listScroll = new BScrollView("roomListScroll", fListView,
true, false, B_NO_BORDER); true, false, B_NO_BORDER);
// Right-side of window, Chat + Textbox // Right-side of window, Chat + Textbox
fChatLayout = new BCardLayout(); fRightView = new BSplitView(B_VERTICAL, 0);
fBackupChatView = new ConversationView(); fBackupChatView = new ConversationView();
fChatView = fBackupChatView;
// Load weights from settings
float horizChat, horizList, vertChat, vertSend;
horizChat = AppPreferences::Get()->ChatViewHorizChatWeight;
horizList = AppPreferences::Get()->ChatViewHorizListWeight;
vertChat = AppPreferences::Get()->ChatViewVertChatWeight;
vertSend = AppPreferences::Get()->ChatViewVertSendWeight;
fChatView->SetWeights(horizChat, horizList, vertChat, vertSend);
BLayoutBuilder::Group<>(this, B_VERTICAL) BLayoutBuilder::Group<>(this, B_VERTICAL)
.Add((fMenuBar = _CreateMenuBar())) .Add((fMenuBar = _CreateMenuBar()))
@ -516,11 +476,12 @@ MainWindow::_InitInterface()
.Add(listScroll, 1) .Add(listScroll, 1)
.Add(fStatusView) .Add(fStatusView)
.End() .End()
.Add(fChatLayout, 5) .Add(fRightView, 5)
.End() .End()
.End() .End()
.End(); .End();
SetConversation(NULL);
_ToggleMenuItems(); _ToggleMenuItems();
} }
@ -534,8 +495,6 @@ MainWindow::_CreateMenuBar()
BMenu* programMenu = new BMenu(B_TRANSLATE("Program")); BMenu* programMenu = new BMenu(B_TRANSLATE("Program"));
programMenu->AddItem(new BMenuItem(B_TRANSLATE("About" B_UTF8_ELLIPSIS), programMenu->AddItem(new BMenuItem(B_TRANSLATE("About" B_UTF8_ELLIPSIS),
new BMessage(B_ABOUT_REQUESTED))); new BMessage(B_ABOUT_REQUESTED)));
programMenu->AddItem(new BMenuItem(B_TRANSLATE("Help" B_UTF8_ELLIPSIS),
new BMessage(APP_SHOW_HELP)));
programMenu->AddItem(new BMenuItem(B_TRANSLATE("Preferences" B_UTF8_ELLIPSIS), programMenu->AddItem(new BMenuItem(B_TRANSLATE("Preferences" B_UTF8_ELLIPSIS),
new BMessage(APP_SHOW_SETTINGS), ',', B_COMMAND_KEY)); new BMessage(APP_SHOW_SETTINGS), ',', B_COMMAND_KEY));
programMenu->AddItem(new BSeparatorItem()); programMenu->AddItem(new BSeparatorItem());
@ -547,17 +506,12 @@ MainWindow::_CreateMenuBar()
BMenu* chatMenu = new BMenu(B_TRANSLATE("Chat")); BMenu* chatMenu = new BMenu(B_TRANSLATE("Chat"));
chatMenu->AddItem(new BMenuItem(B_TRANSLATE("Join room" B_UTF8_ELLIPSIS), chatMenu->AddItem(new BMenuItem(B_TRANSLATE("Join room" B_UTF8_ELLIPSIS),
new BMessage(APP_JOIN_ROOM), 'J', B_COMMAND_KEY)); new BMessage(APP_JOIN_ROOM), 'J', B_COMMAND_KEY));
chatMenu->AddItem(new BMenuItem(B_TRANSLATE("Room directory" B_UTF8_ELLIPSIS),
new BMessage(APP_ROOM_DIRECTORY)));
chatMenu->SetTargetForItems(this);
chatMenu->AddSeparatorItem(); chatMenu->AddSeparatorItem();
chatMenu->AddItem(new BMenuItem(B_TRANSLATE("New room" B_UTF8_ELLIPSIS), chatMenu->AddItem(new BMenuItem(B_TRANSLATE("New room" B_UTF8_ELLIPSIS),
new BMessage(APP_NEW_ROOM), 'N', B_COMMAND_KEY)); new BMessage(APP_NEW_ROOM), 'N', B_COMMAND_KEY));
chatMenu->AddItem(new BMenuItem(B_TRANSLATE("New chat" B_UTF8_ELLIPSIS), chatMenu->AddItem(new BMenuItem(B_TRANSLATE("New chat" B_UTF8_ELLIPSIS),
new BMessage(APP_NEW_CHAT), 'M', B_COMMAND_KEY)); new BMessage(APP_NEW_CHAT), 'M', B_COMMAND_KEY));
chatMenu->AddSeparatorItem(); chatMenu->SetTargetForItems(this);
chatMenu->AddItem(new BMenuItem(B_TRANSLATE("Find" B_UTF8_ELLIPSIS),
new BMessage(APP_ROOM_SEARCH), 'F', B_COMMAND_KEY));
// Roster // Roster
BMenu* rosterMenu = new BMenu(B_TRANSLATE("Roster")); BMenu* rosterMenu = new BMenu(B_TRANSLATE("Roster"));
@ -618,40 +572,6 @@ MainWindow::_RefreshAccountsMenu()
} }
BMenu*
MainWindow::_CreateProtocolMenu()
{
if (fConversation == NULL)
return NULL;
ProtocolLooper* looper = fConversation->GetProtocolLooper();
BObjectList<BMessage> menuItems = looper->Protocol()->MenuBarItems();
if (menuItems.CountItems() == 0)
return NULL;
BMenu* menu = new BMenu(B_TRANSLATE("Protocol"));
for (int i = 0; i < menuItems.CountItems(); i++) {
BMessage* itemMsg = menuItems.ItemAt(i);
BMessage* msg = new BMessage(*itemMsg);
BMessage toSend;
msg->FindMessage("_msg", &toSend);
toSend.AddString("chat_id", fConversation->GetId());
toSend.AddInt64("instance", looper->GetInstance());
msg->ReplaceMessage("_msg", &toSend);
BMenuItem* item = new BMenuItem(msg);
if (item == NULL)
continue;
if (msg->GetBool("x_to_protocol", true) == true)
item->SetTarget(looper);
else
item->SetTarget(this);
menu->AddItem(item);
}
return menu;
}
void void
MainWindow::_ToggleMenuItems() MainWindow::_ToggleMenuItems()
{ {
@ -663,8 +583,7 @@ MainWindow::_ToggleMenuItems()
if (chatMenu == NULL || rosterMenu == NULL) if (chatMenu == NULL || rosterMenu == NULL)
return; return;
Server* server = Server::Get(); bool enabled = (fServer != NULL && fServer->GetAccounts().CountItems() > 0);
bool enabled = (server != NULL && server->GetAccounts().CountItems() > 0);
for (int i = 0; i < chatMenu->CountItems(); i++) for (int i = 0; i < chatMenu->CountItems(); i++)
chatMenu->ItemAt(i)->SetEnabled(enabled); chatMenu->ItemAt(i)->SetEnabled(enabled);
@ -684,19 +603,13 @@ MainWindow::_ToggleMenuItems()
ConversationItem* ConversationItem*
MainWindow::_EnsureConversationItem(BMessage* msg) MainWindow::_EnsureConversationItem(BMessage* msg)
{ {
ChatMap chats = fServer->Conversations();
BString chat_id = msg->FindString("chat_id"); BString chat_id = msg->FindString("chat_id");
int64 conversation_id = msg->FindInt64("instance"); Conversation* chat = fServer->ConversationById(chat_id, msg->FindInt64("instance"));
Conversation* chat = Server::Get()->ConversationById(chat_id, conversation_id); ConversationItem* item = chat->GetListItem();
if (chat == NULL) {
printf("error: Conversation %" B_PRId64 " in '%s' not found!\n", conversation_id, chat_id);
return NULL;
}
_EnsureConversationView(chat); if (chat != NULL) {
// Add conversation item if necessary, return it
ConversationItem* item;
if (chat != NULL && (item = chat->GetListItem()) != NULL) {
if (fListView->HasItem(item)) if (fListView->HasItem(item))
fListView->InvalidateItem(fListView->IndexOf(item)); fListView->InvalidateItem(fListView->IndexOf(item));
else if (item != NULL) { else if (item != NULL) {
@ -712,62 +625,6 @@ MainWindow::_EnsureConversationItem(BMessage* msg)
} }
void
MainWindow::_EnsureConversationView(Conversation* chat)
{
// Add conversation's view if necessary
bool added = false;
fChatList.ValueFor(chat, &added);
if (added == false) {
BLayoutItem* item = fChatLayout->AddView(chat->GetView());
if (item != NULL)
fChatList.AddItem(chat, item);
}
}
void
MainWindow::_ApplyWeights()
{
// Chat-list and chat-view splitter
fSplitView->SetItemWeight(0, AppPreferences::Get()->MainWindowListWeight, true);
fSplitView->SetItemWeight(1, AppPreferences::Get()->MainWindowChatWeight, true);
// Chat-view's weights
float horizChat, horizList, vertChat, vertSend;
horizChat = AppPreferences::Get()->ChatViewHorizChatWeight;
horizList = AppPreferences::Get()->ChatViewHorizListWeight;
vertChat = AppPreferences::Get()->ChatViewVertChatWeight;
vertSend = AppPreferences::Get()->ChatViewVertSendWeight;
BLayoutItem* item = fChatLayout->VisibleItem();
if (item != NULL)
((ConversationView*)item->View())->SetWeights(horizChat, horizList, vertChat, vertSend);
}
void
MainWindow::_SaveWeights()
{
// Chat-list and chat-view splitter
AppPreferences::Get()->MainWindowListWeight = fSplitView->ItemWeight((int32)0);
AppPreferences::Get()->MainWindowChatWeight = fSplitView->ItemWeight((int32)1);
// ChatView's weights
float horizChat, horizList, vertChat, vertSend;
BLayoutItem* item = fChatLayout->VisibleItem();
if (item == NULL)
return;
((ConversationView*)item->View())->GetWeights(&horizChat, &horizList, &vertChat, &vertSend);
AppPreferences::Get()->ChatViewHorizChatWeight = horizChat;
AppPreferences::Get()->ChatViewHorizListWeight = horizList;
AppPreferences::Get()->ChatViewVertChatWeight = vertChat;
AppPreferences::Get()->ChatViewVertSendWeight = vertSend;
}
bool bool
MainWindow::_PopulateWithAccounts(BMenu* menu, ProtocolSettings* settings) MainWindow::_PopulateWithAccounts(BMenu* menu, ProtocolSettings* settings)
{ {
@ -782,7 +639,7 @@ MainWindow::_PopulateWithAccounts(BMenu* menu, ProtocolSettings* settings)
BString toggleLabel = B_TRANSLATE("Enable"); BString toggleLabel = B_TRANSLATE("Enable");
bool isActive = false; bool isActive = false;
int64 instance = Server::Get()->GetActiveAccounts().ValueFor(*account, &isActive); int64 instance = fServer->GetActiveAccounts().ValueFor(*account, &isActive);
if (isActive == true) if (isActive == true)
toggleLabel = B_TRANSLATE("Disable"); toggleLabel = B_TRANSLATE("Disable");

View File

@ -1,7 +1,7 @@
/* /*
* Copyright 2021, Jaidyn Levesque. All rights reserved.
* Copyright 2009-2011, Andrea Anzani. All rights reserved. * Copyright 2009-2011, Andrea Anzani. All rights reserved.
* Copyright 2009-2011, Pier Luigi Fiorini. All rights reserved. * Copyright 2009-2011, Pier Luigi Fiorini. All rights reserved.
* Copyright 2021-2022, Jaidyn Levesque. All rights reserved.
* Distributed under the terms of the MIT License. * Distributed under the terms of the MIT License.
*/ */
#ifndef _MAIN_WINDOW_H #ifndef _MAIN_WINDOW_H
@ -9,10 +9,8 @@
#include <Window.h> #include <Window.h>
#include "libsupport/KeyMap.h" #include "Server.h"
class BCardLayout;
class BLayoutItem;
class BMenu; class BMenu;
class BSplitView; class BSplitView;
class BTextView; class BTextView;
@ -23,7 +21,9 @@ class ConversationListView;
class ConversationView; class ConversationView;
class ProtocolSettings; class ProtocolSettings;
class RosterItem; class RosterItem;
class RosterEditWindow;
class RosterWindow; class RosterWindow;
class Server;
class StatusView; class StatusView;
@ -32,7 +32,6 @@ public:
MainWindow(); MainWindow();
void Start(); void Start();
void Show();
virtual bool QuitRequested(); virtual bool QuitRequested();
virtual void MessageReceived(BMessage* message); virtual void MessageReceived(BMessage* message);
@ -42,45 +41,43 @@ public:
bool active); bool active);
void SetConversation(Conversation* chat); void SetConversation(Conversation* chat);
void SetConversationView(ConversationView* view); void SetConversationView(ConversationView* chatView);
void RemoveConversation(Conversation* chat); void RemoveConversation(Conversation* chat);
void SortConversation(Conversation* chat); void SortConversation(Conversation* chat);
Server* GetServer() const { return fServer; }
private: private:
void _InitInterface(); void _InitInterface();
BMenuBar* _CreateMenuBar(); BMenuBar* _CreateMenuBar();
BMenu* _CreateAccountsMenu(); BMenu* _CreateAccountsMenu();
void _RefreshAccountsMenu(); void _RefreshAccountsMenu();
BMenu* _CreateProtocolMenu();
void _ToggleMenuItems(); void _ToggleMenuItems();
ConversationItem* ConversationItem*
_EnsureConversationItem(BMessage* msg); _EnsureConversationItem(BMessage* msg);
void _EnsureConversationView(Conversation* chat);
void _ApplyWeights();
void _SaveWeights();
bool _PopulateWithAccounts(BMenu* menu, bool _PopulateWithAccounts(BMenu* menu,
ProtocolSettings* settings); ProtocolSettings* settings);
void _ReplaceMenu(const char* name, BMenu* newMenu); void _ReplaceMenu(const char* name, BMenu* newMenu);
Server* fServer;
RosterWindow* fRosterWindow; RosterWindow* fRosterWindow;
RosterEditWindow* fRosterEditWindow;
bool fWorkspaceChanged; bool fWorkspaceChanged;
BMenuBar* fMenuBar; BMenuBar* fMenuBar;
KeyMap<Conversation*, BLayoutItem*> fChatList;
// Left panel, chat list // Left panel, chat list
ConversationListView* fListView; ConversationListView* fListView;
StatusView* fStatusView; StatusView* fStatusView;
BSplitView* fSplitView; BSplitView* fSplitView;
// Right panel, chat // Right panel, chat
BCardLayout* fChatLayout; BSplitView* fRightView;
Conversation* fConversation; Conversation* fConversation;
ConversationView* fChatView;
ConversationView* fBackupChatView; ConversationView* fBackupChatView;
}; };

View File

@ -1,207 +0,0 @@
/*
* Copyright 2021, Jaidyn Levesque <jadedctrl@teknik.io>
* All rights reserved. Distributed under the terms of the MIT license.
*/
#include "RoomListWindow.h"
#include <Button.h>
#include <Catalog.h>
#include <ColumnListView.h>
#include <ColumnTypes.h>
#include <LayoutBuilder.h>
#include <StringList.h>
#include "AccountsMenu.h"
#include "AppPreferences.h"
#include "ChatProtocolMessages.h"
#include "RoomListRow.h"
#include "Server.h"
#undef B_TRANSLATION_CONTEXT
#define B_TRANSLATION_CONTEXT "Room directory"
const uint32 kSelectAcc = 'rlse';
const uint32 kSelectAll = 'rlsa';
const uint32 kJoinRoom = 'join';
RoomListWindow* RoomListWindow::fInstance = NULL;
RoomListWindow::RoomListWindow()
:
BWindow(AppPreferences::Get()->RoomDirectoryRect,
B_TRANSLATE("Room directory"), B_FLOATING_WINDOW,
B_NOT_ZOOMABLE | B_AUTO_UPDATE_SIZE_LIMITS),
fAccount(-1)
{
_InitInterface();
CenterOnScreen();
BMessage* request = new BMessage(IM_MESSAGE);
request->AddInt32("im_what", IM_GET_ROOM_DIRECTORY);
Server::Get()->SendAllProtocolMessage(request);
}
RoomListWindow::~RoomListWindow()
{
fInstance = NULL;
AppPreferences::Get()->RoomDirectoryRect = Bounds();
_EmptyList();
for (int i = 0; i < fRows.CountItems(); i++) {
BObjectList<RoomListRow>* list = fRows.ValueAt(i);
if (list != NULL)
delete list;
}
}
RoomListWindow*
RoomListWindow::Get()
{
if (fInstance == NULL)
fInstance = new RoomListWindow();
return fInstance;
}
bool
RoomListWindow::Check()
{
return (fInstance != NULL);
}
void
RoomListWindow::MessageReceived(BMessage* msg)
{
switch (msg->what) {
case IM_MESSAGE:
{
if (msg->GetInt32("im_what", -1) != IM_ROOM_DIRECTORY)
break;
int64 instance;
BString id;
if (msg->FindInt64("instance", &instance) == B_OK
&& msg->FindString("chat_id", &id) == B_OK) {
RoomListRow* row = new RoomListRow(msg);
bool fnd = false;
BObjectList<RoomListRow>* list = fRows.ValueFor(instance, &fnd);
if (fnd == false || list == NULL) {
list = new BObjectList<RoomListRow>(20, true);
fRows.AddItem(instance, list);
}
list->AddItem(row);
if (fAccount == -1 || instance == fAccount)
fListView->AddRow(row);
}
break;
}
case kSelectAll:
{
_EmptyList();
for (int i = 0; i < fRows.CountItems(); i++) {
BObjectList<RoomListRow>* list = fRows.ValueAt(i);
if (list != NULL)
for (int j = 0; j < list->CountItems(); j++) {
RoomListRow* row = list->ItemAt(j);
if (row != NULL)
fListView->AddRow(row);
}
}
fAccount = -1;
break;
}
case kSelectAcc:
{
msg->PrintToStream();
int64 instance;
if (msg->FindInt64("instance", &instance) == B_OK) {
bool fnd = false;
BObjectList<RoomListRow>* list = fRows.ValueFor(instance, &fnd);
if (fnd == false || list == NULL)
break;
_EmptyList();
for (int i = 0; i < list->CountItems(); i++) {
RoomListRow* row = list->ItemAt(i);
if (row != NULL)
fListView->AddRow(row);
}
fAccount = instance;
}
break;
}
case kJoinRoom:
{
RoomListRow* row =
(RoomListRow*)fListView->CurrentSelection();
if (row != NULL) {
BMessage* joinMsg = row->Message();
joinMsg->ReplaceInt32("im_what", IM_JOIN_ROOM);
Server::Get()->SendProtocolMessage(joinMsg);
Quit();
}
break;
}
default:
BWindow::MessageReceived(msg);
}
}
void
RoomListWindow::_InitInterface()
{
float size = BFont().Size();
BStringColumn* name = new BStringColumn(B_TRANSLATE("Name"), 130, 50, 300,
B_TRUNCATE_END);
BStringColumn* desc = new BStringColumn(B_TRANSLATE("Description"), 270,
50, 5000, B_TRUNCATE_END);
BStringColumn* category = new BStringColumn("Category", 90, 50, 300,
B_TRUNCATE_END);
BIntegerColumn* users = new BIntegerColumn("Users", 70, 10, 300);
fListView = new BColumnListView("roomList", B_NAVIGABLE, B_PLAIN_BORDER);
fListView->SetInvocationMessage(new BMessage(kJoinRoom));
fListView->SetSelectionMode(B_SINGLE_SELECTION_LIST);
fListView->AddColumn(name, kNameColumn);
fListView->AddColumn(desc, kDescColumn);
fListView->AddColumn(category, kCatColumn);
fListView->AddColumn(users, kUserColumn);
AccountsMenu* accsMenu = new AccountsMenu("accounts", BMessage(kSelectAcc),
new BMessage(kSelectAll));
BMenuField* accsField = new BMenuField(NULL, accsMenu);
fJoinButton = new BButton("joinRoom", B_TRANSLATE("Join"),
new BMessage(kJoinRoom));
BLayoutBuilder::Group<>(this, B_VERTICAL)
.SetInsets(B_USE_DEFAULT_SPACING)
.Add(fListView)
.AddGroup(B_HORIZONTAL)
.Add(accsField)
.AddGlue()
.Add(fJoinButton)
.End()
.End();
}
void
RoomListWindow::_EmptyList()
{
BRow* row = fListView->RowAt((int32)0, NULL);
while (row != NULL) {
fListView->RemoveRow(row);
row = fListView->RowAt((int32)0, NULL);
}
}

View File

@ -1,45 +0,0 @@
/*
* Copyright 2021, Jaidyn Levesque <jadedctrl@teknik.io>
* All rights reserved. Distributed under the terms of the MIT license.
*/
#ifndef _ROOM_LIST_WINDOW_H
#define _ROOM_LIST_WINDOW_H
#include <ObjectList.h>
#include <Window.h>
#include <libsupport/KeyMap.h>
class BButton;
class BColumnListView;
class RoomListRow;
typedef KeyMap<int64, BObjectList<RoomListRow>*> RowMap;
class RoomListWindow : public BWindow {
public:
RoomListWindow();
~RoomListWindow();
static RoomListWindow* Get();
static bool Check();
virtual void MessageReceived(BMessage* msg);
private:
void _InitInterface();
void _EmptyList();
BButton* fJoinButton;
BColumnListView* fListView;
RowMap fRows;
int64 fAccount;
static RoomListWindow* fInstance;
};
#endif // _ROOM_LIST_WINDOW_H

View File

@ -24,12 +24,9 @@
#include "AppMessages.h" #include "AppMessages.h"
#include "AppPreferences.h" #include "AppPreferences.h"
#include "ChatProtocolMessages.h" #include "ChatProtocolMessages.h"
#include "Maps.h"
#include "ProtocolLooper.h"
#include "RosterItem.h" #include "RosterItem.h"
#include "RosterListView.h" #include "RosterListView.h"
#include "RosterView.h" #include "RosterView.h"
#include "Server.h"
#include "TemplateWindow.h" #include "TemplateWindow.h"
@ -50,13 +47,14 @@ const char* kEditTitle = B_TRANSLATE("Editing contact");
RosterEditWindow* RosterEditWindow::fInstance = NULL; RosterEditWindow* RosterEditWindow::fInstance = NULL;
RosterEditWindow::RosterEditWindow() RosterEditWindow::RosterEditWindow(Server* server)
: :
BWindow(BRect(0, 0, 300, 400), B_TRANSLATE("Roster"), B_FLOATING_WINDOW, BWindow(BRect(0, 0, 300, 400), B_TRANSLATE("Roster"), B_FLOATING_WINDOW,
B_AUTO_UPDATE_SIZE_LIMITS), B_AUTO_UPDATE_SIZE_LIMITS),
fServer(server),
fEditingWindow(NULL) fEditingWindow(NULL)
{ {
fRosterView = new RosterView("buddyView"); fRosterView = new RosterView("buddyView", server);
fRosterView->SetInvocationMessage(new BMessage(kEditMember)); fRosterView->SetInvocationMessage(new BMessage(kEditMember));
fRosterView->SetManualString(BString("Add %user% as contact" fRosterView->SetManualString(BString("Add %user% as contact"
B_UTF8_ELLIPSIS)); B_UTF8_ELLIPSIS));
@ -106,10 +104,10 @@ RosterEditWindow::~RosterEditWindow()
RosterEditWindow* RosterEditWindow*
RosterEditWindow::Get() RosterEditWindow::Get(Server* server)
{ {
if (fInstance == NULL) { if (fInstance == NULL) {
fInstance = new RosterEditWindow(); fInstance = new RosterEditWindow(server);
} }
return fInstance; return fInstance;
} }
@ -174,7 +172,7 @@ RosterEditWindow::MessageReceived(BMessage* message)
fEditingWindow = fEditingWindow =
new TemplateWindow(title, "roster", new TemplateWindow(title, "roster",
edit, instance); edit, fServer, instance);
fEditingWindow->Show(); fEditingWindow->Show();
if (ritem == NULL) { if (ritem == NULL) {
@ -190,7 +188,7 @@ RosterEditWindow::MessageReceived(BMessage* message)
add->AddInt32("im_what", IM_ROSTER_ADD_CONTACT); add->AddInt32("im_what", IM_ROSTER_ADD_CONTACT);
TemplateWindow* win = TemplateWindow* win =
new TemplateWindow(B_TRANSLATE(kAddTitle), "roster", new TemplateWindow(B_TRANSLATE(kAddTitle), "roster",
add); add, fServer);
win->Show(); win->Show();
break; break;
} }
@ -218,7 +216,7 @@ RosterEditWindow::MessageReceived(BMessage* message)
} }
case kSelAccount: case kSelAccount:
{ {
AccountInstances accounts = Server::Get()->GetActiveAccounts(); AccountInstances accounts = fServer->GetActiveAccounts();
int index = message->FindInt32("index") - 1; int index = message->FindInt32("index") - 1;
if (index < 0 || index > (accounts.CountItems() - 1)) if (index < 0 || index > (accounts.CountItems() - 1))

View File

@ -14,6 +14,8 @@
#include <Window.h> #include <Window.h>
#include "Server.h"
class BMenuField; class BMenuField;
class RosterItem; class RosterItem;
class RosterView; class RosterView;
@ -24,9 +26,9 @@ class TemplateWindow;
the server with contact info, once a contact is selected. */ the server with contact info, once a contact is selected. */
class RosterEditWindow : public BWindow { class RosterEditWindow : public BWindow {
public: public:
RosterEditWindow(); RosterEditWindow(Server* server);
~RosterEditWindow(); ~RosterEditWindow();
static RosterEditWindow* Get(); static RosterEditWindow* Get(Server* server);
static bool Check(); static bool Check();
void MessageReceived(BMessage* message); void MessageReceived(BMessage* message);
@ -38,6 +40,7 @@ private:
BString fEditingUser; BString fEditingUser;
TemplateWindow* fEditingWindow; TemplateWindow* fEditingWindow;
Server* fServer;
RosterView* fRosterView; RosterView* fRosterView;
static RosterEditWindow* fInstance; static RosterEditWindow* fInstance;

View File

@ -25,7 +25,6 @@
#include "RosterItem.h" #include "RosterItem.h"
#include "RosterListView.h" #include "RosterListView.h"
#include "RosterView.h" #include "RosterView.h"
#include "Server.h"
const uint32 kSendMessage = 'RWSM'; const uint32 kSendMessage = 'RWSM';
@ -34,19 +33,20 @@ const uint32 kSelNoAccount = 'RWNA';
RosterWindow::RosterWindow(const char* title, BMessage* selectMsg, RosterWindow::RosterWindow(const char* title, BMessage* selectMsg,
BMessenger* messenger, bigtime_t instance) BMessenger* messenger, Server* server, bigtime_t instance)
: :
BWindow(BRect(0, 0, 300, 400), title, B_FLOATING_WINDOW, BWindow(BRect(0, 0, 300, 400), title, B_FLOATING_WINDOW,
B_AUTO_UPDATE_SIZE_LIMITS), B_AUTO_UPDATE_SIZE_LIMITS),
fTarget(messenger), fTarget(messenger),
fMessage(selectMsg) fMessage(selectMsg),
fServer(server)
{ {
fRosterView = new RosterView("buddyView", instance); fRosterView = new RosterView("buddyView", server, instance),
fRosterView->SetInvocationMessage(new BMessage(kSendMessage)); fRosterView->SetInvocationMessage(new BMessage(kSendMessage));
fOkButton = new BButton("OK", new BMessage(kSendMessage)); fOkButton = new BButton("OK", new BMessage(kSendMessage));
AccountInstances accounts = Server::Get()->GetActiveAccounts(); 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 // In fact, don't even bother populating with them
@ -119,7 +119,7 @@ RosterWindow::MessageReceived(BMessage* message)
} }
case kSelAccount: case kSelAccount:
{ {
AccountInstances accounts = Server::Get()->GetActiveAccounts(); AccountInstances accounts = fServer->GetActiveAccounts();
int index = message->FindInt32("index") - 1; int index = message->FindInt32("index") - 1;
if (index < 0 || index > (accounts.CountItems() - 1)) if (index < 0 || index > (accounts.CountItems() - 1))

View File

@ -14,6 +14,8 @@
#include <Window.h> #include <Window.h>
#include "Server.h"
class BMenuField; class BMenuField;
class RosterItem; class RosterItem;
class RosterView; class RosterView;
@ -24,7 +26,7 @@ class RosterView;
class RosterWindow : public BWindow { class RosterWindow : public BWindow {
public: public:
RosterWindow(const char* title, BMessage* selectMsg, BMessenger* messenger, RosterWindow(const char* title, BMessage* selectMsg, BMessenger* messenger,
bigtime_t instance = -1); Server* server, bigtime_t instance = -1);
void MessageReceived(BMessage* message); void MessageReceived(BMessage* message);
@ -34,6 +36,8 @@ private:
BButton* fOkButton; BButton* fOkButton;
BMenuField* fAccountField; BMenuField* fAccountField;
Server* fServer;
RosterView* fRosterView; RosterView* fRosterView;
BMessenger* fTarget; BMessenger* fTarget;
BMessage* fMessage; BMessage* fMessage;

View File

@ -20,7 +20,6 @@
#include "AccountsMenu.h" #include "AccountsMenu.h"
#include "ChatProtocolMessages.h" #include "ChatProtocolMessages.h"
#include "Server.h"
#include "TemplateView.h" #include "TemplateView.h"
@ -34,10 +33,11 @@ const uint32 kAccSelected = 'JWas';
TemplateWindow::TemplateWindow(const char* title, const char* templateType, TemplateWindow::TemplateWindow(const char* title, const char* templateType,
BMessage* msg, bigtime_t instance) BMessage* msg, Server* server, bigtime_t instance)
: :
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),
fSelectedAcc(instance), fSelectedAcc(instance),
fTemplate(NULL), fTemplate(NULL),
fTemplateType(templateType), fTemplateType(templateType),
@ -51,10 +51,11 @@ TemplateWindow::TemplateWindow(const char* title, const char* templateType,
TemplateWindow::TemplateWindow(const char* title, ProtocolTemplate* temp, TemplateWindow::TemplateWindow(const char* title, ProtocolTemplate* temp,
BMessage* msg, bigtime_t instance) BMessage* msg, Server* server, bigtime_t instance)
: :
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),
fSelectedAcc(-1), fSelectedAcc(-1),
fTemplate(temp), fTemplate(temp),
fMessage(msg) fMessage(msg)
@ -98,7 +99,7 @@ TemplateWindow::MessageReceived(BMessage* msg)
break; break;
} }
ProtocolLooper* looper = Server::Get()->GetProtocolLooper(fSelectedAcc); ProtocolLooper* looper = fServer->GetProtocolLooper(fSelectedAcc);
if (looper == NULL) if (looper == NULL)
break; break;
looper->PostMessage(settings); looper->PostMessage(settings);
@ -130,7 +131,7 @@ void
TemplateWindow::_InitInterface(bigtime_t instance) TemplateWindow::_InitInterface(bigtime_t instance)
{ {
fTemplateView = new TemplateView("template"); fTemplateView = new TemplateView("template");
AccountInstances accounts = Server::Get()->GetActiveAccounts(); AccountInstances accounts = fServer->GetActiveAccounts();
if (instance > -1) { if (instance > -1) {
BMenu* accountMenu = new BMenu("accountMenu"); BMenu* accountMenu = new BMenu("accountMenu");
@ -184,7 +185,7 @@ TemplateWindow::_LoadTemplate()
if (fTemplateType.IsEmpty() == true) if (fTemplateType.IsEmpty() == true)
return; return;
ProtocolLooper* looper = Server::Get()->GetProtocolLooper(fSelectedAcc); ProtocolLooper* looper = fServer->GetProtocolLooper(fSelectedAcc);
if (looper == NULL) if (looper == NULL)
return; return;

View File

@ -10,6 +10,7 @@
#include <Window.h> #include <Window.h>
#include "ProtocolTemplate.h" #include "ProtocolTemplate.h"
#include "Server.h"
class BAlert; class BAlert;
class BMenu; class BMenu;
@ -25,12 +26,12 @@ public:
* via ChatProtocol::SettingsTemplate() */ * via ChatProtocol::SettingsTemplate() */
TemplateWindow(const char* title, TemplateWindow(const char* title,
const char* templateType, BMessage* msg, const char* templateType, BMessage* msg,
bigtime_t instance = -1); Server* server, bigtime_t instance = -1);
/*! Use only the given template. */ /*! Use only the given template. */
TemplateWindow(const char* title, TemplateWindow(const char* title,
ProtocolTemplate* temp, BMessage* msg, ProtocolTemplate* temp, BMessage* msg,
bigtime_t instance = -1); Server* server, bigtime_t instance = -1);
virtual void MessageReceived(BMessage* msg); virtual void MessageReceived(BMessage* msg);
@ -40,6 +41,7 @@ private:
void _InitInterface(bigtime_t instance); void _InitInterface(bigtime_t instance);
void _LoadTemplate(); void _LoadTemplate();
Server* fServer;
int64 fSelectedAcc; int64 fSelectedAcc;
BMenuField* fMenuField; BMenuField* fMenuField;

Binary file not shown.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.1 KiB

After

Width:  |  Height:  |  Size: 1.5 KiB

View File

@ -1,16 +1,19 @@
resource vector_icon array { resource vector_icon array {
$"6E636966040500020106033D835C3C19B2BA8B0B3C20794769624A510E00FFFF" $"6E6369660E05000200060237E670B8880E39469D39AE144A52234B0D2500C6D7"
$"FFB4FFE405FFFFA405020106023D835C3C19B2BA8B0B3C20794769624A510E00" $"F5FF6B94DD03EC6666020006023B2B47BB18653D0FA53D225148297046CA1900"
$"FFE405FFFFA405020106033D429E3C5148BB5ADA3C5C1B4A23AA46EC1800FFFF" $"FFEC4BFFF0A506020006023B3049396B0ABA90833C646E4A101543299500FFFF"
$"FFB47FE583FF04B10C0902093F404644383C273F2E3A244122482245224D2755" $"FFFFFFF289020006023C71E33A0C78BA15E43C7D2149055549455700E3EDFFFF"
$"245126572256245725582A5828592C5A315C2F5B345D3C5E385E425E4957475C" $"9EC2FF03FFACAC020006023A1DA6393F04BBB5BC3C6B074AEA3648091100F99B"
$"4D4E02043F4044433D3FBC95BE953B3D333D3D493844424E4A5148534A4A0403" $"05FFFCB23D03003CB00200060230B31E3A09B9BB024238A12F4BAB534AFF0B00"
$"3B2F4E2F4E2D4E2A4D2F532D522F530003334F334F364F345337533755325636" $"A3043CFFFFDCE603CD4D4D030D296402000602BD498B3E1159BF219BBE7D2F4B"
$"59325602085645C8FEC3AFCA30C0E55E3A5E405EBA4D52B58359B71B4AB38537" $"E71F4AB31300C13E3EFFE27A7A0401740D0A06322E323E42464C3C4C2C3D260A"
$"B51D3EB31FBA16B69933353130363E4A4641444D475346C657C27B554BCB01C6" $"04322E323E424642350A04322E42354C2C3D260A04423542464C3C4C2C0A0338"
$"35584F5A4F080239BA0539BA6B0802BD1CBC1DBD2FBCA908023E37423904032E" $"423C4D3C440A08335C395C41544F5C555C6051594D3E510A0422422252325A32"
$"4535473C4739473F4540070A000100123FFFFE2FDACEAFDACE3FFFFE3AB6A5B8" $"490A04224232493C402D3A0A043249325A3C503C400A043E42C35DC27AC751BE"
$"4CC101178400040A010100000A020101000A000202031001178210040A000104" $"F3493A0A04C35DC27A4E495840C751BEF30A05424BC08BC7B74E5A4E49C35DC2"
$"1001178400040A030104000A000407050608100117821004" $"7A0A053E423E52C08BC7B7424BC35DC27A100A0D0105000A0001003010340117"
$"8400040A0101012010340A0801032010340A0B01042020210A010107000A0001"
$"00302C3401178400040A02010B000A0A010C000A090103202C340A06010A000A"
$"0C0109000A0001001001178400040A030101000A040102000A07010300"
}; };

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.1 KiB

View File

@ -1,25 +0,0 @@
resource vector_icon {
$"6E63696601050003020E2040204020C400206020C840216023602260B54C6026"
$"CC3C26CC7926CC05B491CBF1B548CBFBB449CBEDB3BBCBE7B402CBEAB3BBC7DA"
$"B3BB40B3BBC3CDB3BBBBB3B3BBB399B3BBB7A6B402B395B491B38EB449B392B5"
$"48B38426B34426B37A26B3062320B54C2022202020212020B740204020BB8020"
$"40204020402040020E5AB3445AB3445AB37ACAF2B38ECA37B384CB38B392CBC5"
$"B399CB7EB395CBC5B7A6CBC540CBC5BBB3CBC5C3CDCBC5CBE7CBC5C7DACB7ECB"
$"EACAF2CBF1CB38CBEDCA37CBFB5ACC3C5ACC055ACC795D60CA33605E6060605F"
$"6060C840604060C40060BB80602060B7405F205D205E20CA33205AB3445AB306"
$"5AB3445AB3445AB3445AB3440222BC52BB80BC52BB80BBF3BBB9BB7937BB8DBC"
$"04BB35BC93BB1ABBD5BB1ABC7BBB1ABBA2BB1ABB3CBB1ABB6FBAB9BB3CB9F9BB"
$"3CBA59BB3CB998BB3CB8D8BB3CB938BB3CB8D8BCC3B8D8BFD1B8D8BE4AB8D844"
$"B8D8C466B8D8C2DFB943C466BA1BC466B9AFC466BA86C46635C466BAF2C46635"
$"C35D35C14D35C25535BE7DBB9EBDD6BB64BE32BBFABD4EBD1BBD18BC60BD1BBE"
$"68BD18BE8AC1A6BE8ABD7EBE8BC2913DC469BE8CC37DBEF7C466BFCAC45FBF60"
$"C462C032C45BC103C455C09AC458C108C34AC114C136C10EC240C11EBF0FC151"
$"BDCCC132BDFFC198BD4EC2BDBD18C205BD18C34BBD184ABD69C37BBD29C42CBD"
$"E4C444C1A6C4403DC444C291C444C469C444C37DC4ADC466C580C45FC516C462"
$"C5E8C45BC6B9C455C650C458C6BCC361C6C3C17AC6BFC26DC6CDBE09C62ABC3E"
$"C6AEBCFCC59EBB7CC3A7BB20C4F1BB2EC26EBB13C114BC0BC1D9BB49C0EFBC2F"
$"C0A7BC78C0CBBC53C089BC52C04EBC08C06CBC2DBFD1BB68BDF5BB1ABF12BB1A"
$"BD29BB1ABC52BB80BCEBBB2BBC52BB80BC52BB80BC52BB80BC52BB80030A0001"
$"00000A000101000A00010200"
};

View File

@ -1,301 +0,0 @@
<!DOCTYPE HTML>
<html lang="en">
<head>
<meta charset="UTF-8"/>
<title>Chat-O-Matic Documentation</title>
<link href='style.css' rel='stylesheet' type='text/css'>
</head>
<body>
<div align="center">
<h1>
<img width=32px src="img/AppIcon.png" />
Chat-O-Matic Documentation
</h1>
</div>
<p>Chat-O-Matic is a multi-protocol chat program based on
<a href="https://github.com/Numerio/Caya">Caya</a>, which has its own roots in the
<a href="http://www.eiman.tv/imkit/">IM kit</a> project. Several protocols are supported,
including <abbr title="Internet Relay Chat">IRC</abbr>,
<abbr title="Extensible Messaging and Presence Protocol">XMPP</abbr>, and more through
libpurple.
<nav>
<b>Contents</b>
<ul>
<li><a href="#window">Main window</a></li>
<ul>
<li><a href="#room_list">Room list</a></li>
<ul>
<li><a href="#room_flags">Room options</a></li>
</ul>
<li><a href="#room_header">Room header</a></li>
<li><a href="#user_list">User list</a></li>
<ul>
<li><a href="#moderation">Moderation</a></li>
</ul>
<li><a href="#chat_input">Chat input</a></li>
<ul>
<li><a href="#commands">Commands</a></li>
</ul>
<li><a href="#status">Status area</a></li>
<li><a href="#menu_bar">Menu-bar</a></li>
</ul>
<li><a href="#preferences">Preferences window</a></li>
<li><a href="#roster">Roster windows</a></li>
<li><a href="#rooms">Room creation/join windows</a></li>
<li><a href="#room_dir">Room directory</a></li>
</ul>
</nav>
<section id="window">
<h2>Main window</h2>
<img src="img/window.png" />
<section id="room_list">
<h3>Room list</h3>
<img src="img/chat-list.png" />
<p>Lists all joined chats that are attached to the current window, ordered by account.
Clicking a chat will select it, changing the text buffer,
<a href="#user_list">user-list</a>, and <a href="#room_header">room header</a>. If you
click on an <i>account's</i> list item, then that account's logs will be shown instead: This
might include anything from <abbr title="Message of the Day">MOTDs</abbr> to error messages,
depending on the protocol.</p>
<section id="room_flags">
<h4>Room options</h4>
<p>If you right-click on a room's list item, you can toggle several per-room options,
including:</p>
<table>
<tr><th>Flag</th><th>Description</th><th>Default</th></tr>
<tr><td>Auto-join</td>
<td>If the room will be joined after every start-up</td><td></td>
</tr>
<tr><td>Log messages</td>
<td>Whether or not messages will be logged to disk</td><td></td>
</tr>
<tr><td>Notify on every message</td>
<td>Notify if any message is sent to the room</td><td></td></tr>
<tr><td>Notify on direct-messages</td>
<td>Notify if the user is mentioned, or if message received in one-on-one
chat</td><td></td></tr>
</table>
</section>
</section>
<section id="room_header">
<h3>Room header</h3>
<img src="img/chat-header.png" />
<p>This little section displays a room's name, topic, and icon.</p>
<p>If you have permission to, you can also change a room's topic by clicking on the topic
text, typing what you'd like it to be, and hitting <span class="key">ENTER</span>. After
hitting <span class="key">ENTER</span>, the text will change back to the previous topic,
pending the protocol or server— after which it will update to the new topic.</p>
<p>Here, the room name is “#haiku” and the topic “Open-source operating system […].”</p>
</section>
<section>
<h3 id="user_list">User list</h3>
<img src="img/user-list.png" />
<p>This area has a calm, undemanding job— show a list of users in the room. On
right-clicking a user item, you'll see a pop-up menu with at least <i>User info…</i>.
<section>
<h4 id="moderation">Moderation</h4>
<p>Depending on your user's permissions, you might see more than <i>User info…</i> in the
user-list pop-up menus: <i>Ban user</i>, <i>Kick user</i>, <i>Mute user</i>,
<i>Deafen user</i>, and their reciprocals (<i>Unmute user</i>, <i>Undeafen user</i>).</p>
<p>By moderating through this right-click menu, though, you can't attach a message—
sometimes, for example, it's useful to give the victim a reason that you've kicked them
in the shins. For that, you can moderate through <a href="#commands">commands</a> as well.</p>
</section>
<section>
<h3 id="chat_input">Chat input</h3>
<img src="img/chat-input.png" />
<p>With the text-box, you can send messages and run commands. Type what you like, and hit
<span class="key">ENTER</span> to send. If you're typing someone's username or nickname,
hitting <span class="key">TAB</span> can auto-complete it.</p>
<p>Messages don't necessarily have to be only one line long— hence why you can resize the
text-box. <span class="key">ALT</span><span class="key">ENTER</span> starts a new line. If
you get lost, <span class="key">Page↑</span> and <span class="key">Page↓</span> are your
friends.</p>
<section>
<h4 id="commands">Commands</h4>
<p><i>Commands</i> let you perform some special action— they vary by protocol, but there are
some standard ones you can expect to work:</p>
<table>
<tr><th>Command</th><th>Description</th></tr>
<tr><td>/help</td><td>List all commands for the current protocol</td>
<tr><td>/invite <i>USER</i></td><td>Invite a user to the current room</td>
<tr><td>/kick <i>USER MESSAGE</i></td><td>Disconnect a user from the current room</td>
<tr><td>/ban <i>USER MESSAGE</i></td><td>Disconnect a user and prevent them from re-joining</td>
<tr><td>/unban <i>USER</i></td><td>Undo a user's ban</td>
<tr><td>/deafen <i>USER</i></td><td>Prevent a user from receiving any messages</td>
<tr><td>/undeafen <i>USER</i></td><td>Undo a user's deafening</td>
<tr><td>/mute <i>USER</i></td><td>Prevent a user from sending messages</td>
<tr><td>/unmute <i>USER</i></td><td>Undo a user's muting</td>
</table>
<p>As you might be able to tell, most of these are just aliases for
<a href="#moderation">moderation</a> through the <a href="#user_list">user list</a>.</p>
</section>
</section>
<section>
<h3 id="status">Status area</h3>
<img src="img/status-area.png" />
<p>In the status area, you can see your avatar (how cute!), change your nickname, and update
your current status.</p>
<p>Clicking on the nickname text-box (here it's “jaidedim”), you can then edit your nickname,
hitting <span class="key">ENTER</span> to update. After hitting
<span class="key">ENTER</span>, the text will change back to your previous nickname, pending
the protocol or server— after which it will update to the new nickname.</p>
<p>The status drop-down menu lets you change the status for the currently selected account
(here it's “Available”).</p>
<p>There is, next to the status menu, an account menu. By default “All” (the asterisk) is
selected, meaning that any changes to status or nickname will apply to all accounts. If
you'd like to change the nick or status of only a single account, you can select it from
this menu.</p>
</section>
<section>
<h3 id="menu_bar">Menu-bar</h3>
<img src="img/menu-bar.png" />
<p>In the <i>Program</i> menu, you'll find:
<ul>
<li>About…</li>
<li><a href="#preferences">Preferences…</a></li>
<li>Quit</li>
</ul>
</p>
<p>In the <i>Accounts</i> menu, you'll find a list of your accounts for
easy management. Through this menu, you can also select the <i>Accounts→Manage accounts…</i>
item to see the account management window, which lets you add and remove accounts.</p>
<p>In the <i>Chat</i> menu, you'll find:
<ul>
<li>Join room…</li>
<li><a href="#room_dir">Room directory…</a></li>
<li>New room…</li>
<li>New chat…</li>
<li>Find…</li>
</ul>
<i>Chat→Find…</i> (<span class="key">ALT</span><span class="key">F</span>) will open a
<b>TextSearch</b> window for searching the current room's logs (so long as logging
<a href="#room_flags">is enabled</a>). The other items are related to
<a href="#rooms">room creation/joining</a>.
</p>
<p>In the <i>Roster</i> menu, you'll find:
<ul>
<li>Edit roster…</li>
<li>Invite user…</li>
</ul>
<p>In the <i>Window</i> menu, you'll find two items that make switching between rooms
faster— <i>Window→Up</i> (<span class="key">ALT</span><span class="key"></span>) and
<i>Window→Down</i> (<span class="key">ALT</span><span class="key"></span>).</p>
</section>
</section>
<section>
<h2 id="preferences">Preferences window</h4>
<img src="img/pref-notifications.png" />
<p>Selecting <i>Program→Preferences</i> through the menu-bar (<span class="key">ALT</span>
<span class="key">,</span>), you'll see the Preferences window. Most of the options should
be self-explanatory, but there a couple that are noteworthy:<p>
<p>The <i>Notifications</i> tab lets you toggle whether or not you receive message-related
notifications and whether or not you'll be notified on a connection/disconnection.</p>
<p>You can also attach specific sounds to notifications through Haiku's <b>Sounds</b>
preferences, brought up through the <i>Edit sounds…</i> button. The beeps configurable
through <b>Sounds</b> are <i>Chat-O-Matic mention</i> and <i>Chat-O-Matic message</i>.</p>
</section>
<section>
<h2 id="roster">Roster/user windows</h2>
<img src="img/select-user.png" />
<p>Roster and user-selection windows (as in <i>Roster→Edit roster…</i>,
<i>Roster→Invite user…</i> and <i>Chat→New chat…</i> from the
<a href="#menu_bar">menu-bar</a>) display a list of your contacts,
allowing you to select one.</p>
<p>Through the account drop-down menu in the
bottom-left corner, you can filter the list, showing only contacts
of a specific account. In this example, “jaidedim-xmpp“, an XMPP
account, is selected.</p>
<p>By typing into the text-box at the top of the window, you can search
through the shown contacts— here, all contacts matching “Ash” are
shown. If you have an account selected, you can also use this text-box
to manually type in a username for selection. In this window, since
a specific account is selected, “Select user Ash…” is an item in the
list.</p>
</section>
<section>
<h2 id="rooms">Room creation/join windows</h2>
<img src="img/room-creation.png" />
<p>With <i>Chat→Join room…</i> and <i>Chat→New room…</i> in the
<a href="#menu_bar">menu-bar</a> (<span class="key">ALT</span><span class="key">J</span> and
<span class="key">ALT</span><span class="key">N</span>, respectively), you'll see a window
like the one above. For each protocol, the options and text-boxes shown will differ— for
<abbr title="Internet Relay Chat">IRC</abbr>, as in this image, the only option is the
channel-name.</p>
<p>You can select the account to join/create from through the account drop-down menu in the
bottom-left corner. Here, the account “oftc-irc” is selected, an
<abbr title="Internet Relay Chat">IRC</abbr> account.</p>
<p><i>Chat→Create chat…</i> (<span class="key">ALT</span><span class="key">M</span>), in
contrast, is used for creating one-on-one chats, and opens a
<a href="#roster">user-selection window</a> instead.</p>
</section>
<section>
<h2 id="room_dir">Room directory</h2>
<img src="img/room-directory.png" />
<p>The room directory (accessible though <i>Chat→Room directory…</i> in the
<a href="#menu_bar">menu-bar</a>) lets you browse and join publically listed chatrooms— a
feature used extensively for <abbr title="Internet Relay Chat">IRC</abbr>,
<abbr title="Extensible Messaging and Presence Protocol">XMPP</abbr>, and some libpurple
add-ons.</p>
<p>Like other dialogues in Chat-O-Matic, you can select a specific account to act on though
the bottom-left account dropdown menu. In this image, “All” accounts is selected, so rooms
available to all the user's accounts are shown.</p>
</section>
</body>
</html>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 27 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 135 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 27 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 136 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 83 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 30 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 23 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 71 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 38 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 32 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 33 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 202 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 36 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 144 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 144 KiB

View File

@ -1,22 +0,0 @@
/* SPCSS theme by Susam Pal, under the MIT license
* https://github.com/susam/spcss */
body{color:#333;font-family:helvetica,arial,sans-serif;line-height:1.5;margin:0 auto;max-width:40em;padding:0 1em}h1,h2,h3,h4,h5,h6{margin:1.25em 0 .5em;line-height:1.2}a:link{color:#00e}a:visited{color:#518}a:focus,a:hover{color:#03f}a:active{color:#e00}h1 a:empty:before,h2 a:empty:before,h3 a:empty:before,h4 a:empty:before,h5 a:empty:before,h6 a:empty:before{content:"#"}h1 a:empty,h2 a:empty,h3 a:empty,h4 a:empty,h5 a:empty,h6 a:empty{visibility:hidden;padding-left:.25em}h1:hover a:empty,h2:hover a:empty,h3:hover a:empty,h4:hover a:empty,h5:hover a:empty,h6:hover a:empty{visibility:visible}img{max-width:100%}figure{margin:1em 0;text-align:center}figcaption{font-size:small}code,kbd,pre,samp{color:#009;font-family:monospace,monospace}pre kbd{color:#060}blockquote,pre{background:#eee;padding:.5em}pre{overflow:auto}blockquote{border-left:medium solid #ccc;margin:1em 0}blockquote :first-child{margin-top:0}blockquote :last-child{margin-bottom:0}table{border-collapse:collapse}td,th{border:thin solid #999;padding:.3em .4em;text-align:left}@media (prefers-color-scheme:dark){body{background:#111;color:#bbb}a:link{color:#9bf}a:visited{color:#caf}a:focus,a:hover{color:#9cf}a:active{color:#faa}code,kbd,pre,samp{color:#6cf}pre kbd{color:#9c6}blockquote,pre{background:#000}blockquote{border-color:#333}td,th{border-color:#666}}
/*
* Copyright 2008-2017, Haiku. All rights reserved.
* Distributed under the terms of the MIT License.
*/
.key { /* Shortcut (separate with */
-webkit-border-radius: 3px;
-khtml-border-radius: 3px;
-moz-border-radius: 3px;
border-radius: 3px;
border-color: #c7c7c7;
border-style: solid;
border-width: 1px;
padding: 0px 2px 0px 2px;
background-color: #e8e8e8;
font-family: serif;
font-variant: small-caps;
font-size: 0.8em;
}

View File

@ -1,5 +1,3 @@
include Make.pre
# Haiku Generic Makefile v2.6 ## # Haiku Generic Makefile v2.6 ##
## Fill in this file to specify the project being created, and the referenced ## Fill in this file to specify the project being created, and the referenced
@ -142,4 +140,4 @@ DEVEL_DIRECTORY := \
$(shell findpaths -r "makefile_engine" B_FIND_PATH_DEVELOP_DIRECTORY) $(shell findpaths -r "makefile_engine" B_FIND_PATH_DEVELOP_DIRECTORY)
include $(DEVEL_DIRECTORY)/etc/makefile-engine include $(DEVEL_DIRECTORY)/etc/makefile-engine
include Make.post include Makefile.common

View File

@ -1,5 +1,3 @@
include Make.pre
## Haiku Generic Makefile v2.6 ## ## Haiku Generic Makefile v2.6 ##
## Fill in this file to specify the project being created, and the referenced ## Fill in this file to specify the project being created, and the referenced
@ -136,4 +134,4 @@ DEVEL_DIRECTORY := \
$(shell findpaths -r "makefile_engine" B_FIND_PATH_DEVELOP_DIRECTORY) $(shell findpaths -r "makefile_engine" B_FIND_PATH_DEVELOP_DIRECTORY)
include $(DEVEL_DIRECTORY)/etc/makefile-engine include $(DEVEL_DIRECTORY)/etc/makefile-engine
include Make.post include Makefile.common

View File

@ -17,7 +17,6 @@ public:
void AddItem(KEY k, TYPE t); void AddItem(KEY k, TYPE t);
TYPE ValueFor(KEY, bool* found = NULL) const; TYPE ValueFor(KEY, bool* found = NULL) const;
KEY KeyFor(TYPE, bool* found = NULL) const;
TYPE RemoveItemAt(int32 position); TYPE RemoveItemAt(int32 position);
TYPE RemoveItemFor(KEY); TYPE RemoveItemFor(KEY);
@ -64,22 +63,8 @@ KeyMap<KEY, TYPE>::ValueFor(KEY k, bool* found) const
} }
if (i == fMap.end()) if (i == fMap.end())
return 0;
return i->second;
}
template<class KEY, class TYPE>
inline KEY
KeyMap<KEY, TYPE>::KeyFor(TYPE v, bool* found) const
{
*found = false;
for (int32 i = 0; i < CountItems(); i++)
if (ValueAt(i) == v) {
*found = true;
return KeyAt(i);
}
return NULL; return NULL;
return i->second;
} }

View File

@ -1,5 +1,3 @@
include Make.pre
## Haiku Generic Makefile v2.6 ## ## Haiku Generic Makefile v2.6 ##
## Fill in this file to specify the project being created, and the referenced ## Fill in this file to specify the project being created, and the referenced
@ -136,4 +134,4 @@ DEVEL_DIRECTORY := \
$(shell findpaths -r "makefile_engine" B_FIND_PATH_DEVELOP_DIRECTORY) $(shell findpaths -r "makefile_engine" B_FIND_PATH_DEVELOP_DIRECTORY)
include $(DEVEL_DIRECTORY)/etc/makefile-engine include $(DEVEL_DIRECTORY)/etc/makefile-engine
include Make.post include Makefile.common

View File

@ -1,133 +1,108 @@
1 English application/x-vnd.chat-o-matic 244317784 1 English application/x-vnd.cardie 1762272810
No accounts enabled, no joy. ConversationView ― Startup messages No accounts enabled, no joy. Disable deskbar replicant PreferencesReplicant Disable deskbar replicant
Description Room directory Description
%user% is now offline! Server %user% is now offline!
New mention Conversation ― Notifications New mention New mention Conversation ― Notifications New mention
{0, plural,=1{One lonely user}=2{Two partners}other{# members}} ConversationInfoWindow {0, plural,=1{One lonely user}=2{Two partners}other{# members}}
Enable contact status notifications PreferencesNotifications Enable contact status notifications
Edit sounds… PreferencesNotifications Edit sounds…
Auto-raise when a message is received PreferencesBehavior Auto-raise when a message is received Auto-raise when a message is received PreferencesBehavior Auto-raise when a message is received
On incoming… PreferencesBehavior On incoming… On incoming… PreferencesBehavior On incoming…
Account name: AccountDialog Account name: Account name: AccountDialog Account name:
Connected Server Connected Connected Server Connected
User information UserInfoWindow User information User information UserInfoWindow User information
Account now online! Server Account now online!
Del AccountsWindow Short for 'delete' Del
%name% is offline! RosterView %name% is offline! %name% is offline! RosterView %name% is offline!
Preferences… MainWindow Preferences… Preferences… MainWindow Preferences…
Room directory Room directory Room directory ** You created the room.\n ConversationView ** You created the room.\n
Adding contact RosterEditWindow Adding contact Adding contact RosterEditWindow Adding contact
It looks like you don't have any accounts enabled. ConversationView ― Startup messages It looks like you don't have any accounts enabled. Deskbar replicant PreferencesReplicant Deskbar replicant
Add account PreferencesAccounts Add account
Start a chat RosterListView Start a chat Start a chat RosterListView Start a chat
Log messages ConversationListView Log messages Enable PreferencesAccounts Enable
Edit… AccountsWindow Edit… %app% is released under the GNU GPL License.\nSome parts of %app% are available under MIT license.\nBuilt: %buildDate% TheApp %app% is released under the GNU GPL License.\nSome parts of %app% are available under MIT license.\nBuilt: %buildDate%
%app% setup ConversationView ― Startup messages %app% setup
Manage accounts… MainWindow Manage accounts…
Create room MainWindow Create room Create room MainWindow Create room
** The subject is now: %subject% ConversationView ** The subject is now: %subject%
New chat… ConversationListView New chat… New chat… ConversationListView New chat…
Add AccountsWindow Add
Chat view PreferencesChatWindow Chat view Chat view PreferencesChatWindow Chat view
Hide field in Deskbar PreferencesReplicant Hide field in Deskbar
Edit roster… MainWindow Edit roster… Edit roster… MainWindow Edit roster…
Room information ConversationInfoWindow Room information
Ouch! TheApp Ouch! Ouch! TheApp Ouch!
Notifications PreferencesNotifications Notifications
Disconnected Server Disconnected
Join a room MainWindow Join a room Join a room MainWindow Join a room
Room info… ConversationListView Room info…
OK PreferencesWindow OK OK PreferencesWindow OK
Accounts ConversationView ― Startup messages Accounts Enable protocol status notifications PreferencesBehavior Enable protocol status notifications
Send a file… RosterListView Send a file… Send a file… RosterListView Send a file…
Are you sure you want to quit? MainWindow Are you sure you want to quit? Are you sure you want to quit? MainWindow Are you sure you want to quit?
Manage accounts through the %menu% menu to get started. ConversationView ― Startup messages Manage accounts through the %menu% menu to get started. Del PreferencesAccounts Short for 'delete' Del
%name% is available! RosterView %name% is available! %name% is available! RosterView %name% is available!
New message Conversation ― Notifications New message New message Conversation ― Notifications New message
Some items are empty. Please make sure to fill out every item. TemplateWindow Some items are empty. Please make sure to fill out every item. Some items are empty. Please make sure to fill out every item. TemplateWindow Some items are empty. Please make sure to fill out every item.
Enable message notifications PreferencesBehavior Enable message notifications
Program MainWindow Program Program MainWindow Program
Cancel AccountDialog Cancel Cancel AccountDialog Cancel
Leave room ConversationListView Leave room
Behavior PreferencesBehavior Behavior Behavior PreferencesBehavior Behavior
Find… MainWindow Find… Replicant PreferencesReplicant Replicant
Enable MainWindow Enable Play sound event PreferencesBehavior Play sound event
You've been summoned from %source%. Conversation ― Notifications You've been summoned from %source%. You've been summoned from %source%. Conversation ― Notifications You've been summoned from %source%.
Notify on every message ConversationListView Notify on every message
Disabled Server Disabled Disabled Server Disabled
That isn't a valid command. Try /help for a list. Conversation ― Command info That isn't a valid command. Try /help for a list. That isn't a valid command. Try /help for a list. Conversation ― Command info That isn't a valid command. Try /help for a list.
** You joined the room.\n ConversationView ** You joined the room.\n
-- That command doesn't exist. Try '/help' for a list.\n Server -- That command doesn't exist. Try '/help' for a list.\n -- That command doesn't exist. Try '/help' for a list.\n Server -- That command doesn't exist. Try '/help' for a list.\n
OK TemplateWindow OK OK TemplateWindow OK
Reject InviteDialogue Reject Reject InviteDialogue Reject
\nWritten by:\n About window \nWritten by:\n \nWritten by:\n About window \nWritten by:\n
Disable PreferencesAccounts Disable
All AccountsMenu All All AccountsMenu All
Offline Utils ― Status names Offline Offline Utils ― Status names Offline
%user% has been disabled! Server %user% has been disabled! %user% has been disabled! Server %user% has been disabled!
You've been invited to %room%. Server You've been invited to %room%. You've been invited to %room%. Server You've been invited to %room%.
Invite user… UserListView Invite user… Invite user… UserListView Invite user…
Sound when mentioned PreferencesNotifications Sound when mentioned Add PreferencesAccounts Add
Preferences PreferencesWindow Preferences Preferences PreferencesWindow Preferences
Connecting Server Connecting Deskbar notifications PreferencesBehavior Deskbar notifications
Name Room directory Name
General PreferencesBehavior General General PreferencesBehavior General
%user% is readying… Server %user% is readying…
Enable protocol status notifications PreferencesNotifications Enable protocol status notifications
Presence RosterView Presence Presence RosterView Presence
Cancel TemplateWindow Cancel Cancel TemplateWindow Cancel
Hide offline contacts PreferencesBehavior Hide offline contacts
%user% has joined the room.\n ConversationView %user% has joined the room.\n %user% has joined the room.\n ConversationView %user% has joined the room.\n
Busy Utils ― Status names Busy Busy Utils ― Status names Busy
Roster RosterEditWindow Roster Roster RosterEditWindow Roster
Auto-join room ConversationListView Auto-join room
** %old% has changed their nick to %new%. Conversation ― Command info ** %old% has changed their nick to %new%.
Don't ask confirmation at Quit PreferencesBehavior Don't ask confirmation at Quit Don't ask confirmation at Quit PreferencesBehavior Don't ask confirmation at Quit
Closing MainWindow Closing Closing MainWindow Closing
Sound on message received PreferencesNotifications Sound on message received
Available Utils ― Status names Available Available Utils ― Status names Available
Up MainWindow Up Up MainWindow Up
Invite user… MainWindow Invite user… Invite user… MainWindow Invite user…
Room directory… MainWindow Room directory…
Custom Status Utils ― Status names Custom Status Custom Status Utils ― Status names Custom Status
Can't find smileys settings in:\n\n%path% TheApp Can't find smileys settings in:\n\n%path% Can't find smileys settings in:\n\n%path% TheApp Can't find smileys settings in:\n\n%path%
Connection failed Server Connection failed
Mark unread window chat PreferencesBehavior Mark unread window chat Mark unread window chat PreferencesBehavior Mark unread window chat
%user% has left the room.\n ConversationView %user% has left the room.\n %user% has left the room.\n ConversationView %user% has left the room.\n
Join Room directory Join
Join room… MainWindow Join room… Join room… MainWindow Join room…
Edit account AccountsWindow Edit account
Preferences ReplicantStatusView Preferences Preferences ReplicantStatusView Preferences
Quit MainWindow Quit Quit MainWindow Quit
Chat MainWindow Chat Chat MainWindow Chat
No MainWindow No No MainWindow No
Chat settings PreferencesChatWindow Chat settings Chat settings PreferencesChatWindow Chat settings
Cancel InviteDialogue Cancel Cancel InviteDialogue Cancel
Sounds PreferencesNotifications Sounds Mark unread the Deskbar Replicant PreferencesBehavior Mark unread the Deskbar Replicant
Add account AccountsWindow Add account
OK Server OK OK Server OK
Enable AccountsWindow Enable
Exit ReplicantStatusView Exit Exit ReplicantStatusView Exit
Disable AccountsWindow Disable
User info… RosterListView User info… User info… RosterListView User info…
Move window to current workspace PreferencesBehavior Move window to current workspace Move window to current workspace PreferencesBehavior Move window to current workspace
Away Utils ― Status names Away Away Utils ― Status names Away
OK AccountDialog OK OK AccountDialog OK
Notify on direct-messages ConversationListView Notify on direct-messages
Accounts MainWindow Accounts
%user% has been banned.\n ConversationView %user% has been banned.\n %user% has been banned.\n ConversationView %user% has been banned.\n
Editing contact RosterEditWindow Editing contact Editing contact RosterEditWindow Editing contact
%user% isn't a member of this room. ChatCommand %user% isn't a member of this room. %user% isn't a member of this room. ChatCommand %user% isn't a member of this room.
Account now offline and disconnected. Server Account now offline and disconnected. Edit account PreferencesAccounts Edit account
Down MainWindow Down Down MainWindow Down
** Commands: Server ** Commands: ** Commands: Server ** Commands:
I'm rearing to go! Conversation ― Command info I'm rearing to go! Cardie System name Cardie
About… About window About… About… About window About…
Enable message notifications PreferencesNotifications Enable message notifications
Invitation received Server Invitation received
Ignore emoticons PreferencesChatWindow Ignore emoticons Ignore emoticons PreferencesChatWindow Ignore emoticons
Invitation received Server Invitation received
Enable contact status notifications PreferencesBehavior Enable contact status notifications
Auto-raise when user is typing PreferencesBehavior Auto-raise when user is typing
Error Server Error Error Server Error
Modify account… MainWindow Modify account…
Copyright © About window Copyright © Copyright © About window Copyright ©
Roster MainWindow Roster Roster MainWindow Roster
Accept InviteDialogue Accept Accept InviteDialogue Accept
%user% was kicked (%body%).\n ConversationView %user% was kicked (%body%).\n %user% was kicked (%body%).\n ConversationView %user% was kicked (%body%).\n
An error is occurred renaming the account to %name%! AccountDialog An error is occurred renaming the account to %name%! An error is occurred renaming the account to %name%! AccountDialog An error is occurred renaming the account to %name%!
%user% has invited you to %room%. Server %user% has invited you to %room%. %user% has invited you to %room%. Server %user% has invited you to %room%.
Permanent deskbar replicant PreferencesReplicant Permanent deskbar replicant
Default User role Default Default User role Default
%user% has been banned (%body%).\n ConversationView %user% has been banned (%body%).\n %user% has been banned (%body%).\n ConversationView %user% has been banned (%body%).\n
Invite contact to chat… MainWindow Invite contact to chat… Invite contact to chat… MainWindow Invite contact to chat…
@ -135,22 +110,14 @@ Invite contact to chat… MainWindow Invite contact to chat…
Window MainWindow Window Window MainWindow Window
Invisible Utils ― Status names Invisible Invisible Utils ― Status names Invisible
{0, plural,=1{You've got a new message from %source%.}other{You've got # new messages from %source%.}} Conversation ― Notifications {0, plural,=1{You've got a new message from %source%.}other{You've got # new messages from %source%.}} {0, plural,=1{You've got a new message from %source%.}other{You've got # new messages from %source%.}} Conversation ― Notifications {0, plural,=1{You've got a new message from %source%.}other{You've got # new messages from %source%.}}
Afterward, you can join a room or start a chat through the %menu% menu. :-) ConversationView ― Startup messages Afterward, you can join a room or start a chat through the %menu% menu. :-)
%user% has joined the room (%body%).\n ConversationView %user% has joined the room (%body%).\n %user% has joined the room (%body%).\n ConversationView %user% has joined the room (%body%).\n
%app% is released under the MIT License.\nAdd-on and library licenses may vary.\nBuilt: %buildDate% TheApp %app% is released under the MIT License.\nAdd-on and library licenses may vary.\nBuilt: %buildDate%
Chat-O-Matic System name Chat-O-Matic
Yes MainWindow Yes Yes MainWindow Yes
An error has occured saving the settings.\nCheck if your disk has enough space. AccountDialog An error has occured saving the settings.\nCheck if your disk has enough space. An error has occured saving the settings.\nCheck if your disk has enough space. AccountDialog An error has occured saving the settings.\nCheck if your disk has enough space.
%user% has been temporarily disabled. Server %user% has been temporarily disabled.
Disable MainWindow Disable
Close About window Close Close About window Close
No protocols found!\nPlease make sure %app% was installed correctly. TheApp No protocols found!\nPlease make sure %app% was installed correctly.
Accounts AccountsWindow Accounts
%user% has left the room (%body%).\n ConversationView %user% has left the room (%body%).\n %user% has left the room (%body%).\n ConversationView %user% has left the room (%body%).\n
New chat… MainWindow New chat… New chat… MainWindow New chat…
New room… MainWindow New room… New room… MainWindow New room…
About… MainWindow About… About… MainWindow About…
Master Foo ConversationView ― Startup messages Master Foo Edit… PreferencesAccounts Edit…
Chat ConversationView ― Startup messages Chat
%user% was kicked.\n ConversationView %user% was kicked.\n %user% was kicked.\n ConversationView %user% was kicked.\n
You aren't contacts with and have no chats in common with %user%. Shame. ChatCommand You aren't contacts with and have no chats in common with %user%. Shame. You aren't contacts with and have no chats in common with %user%. Shame. ChatCommand You aren't contacts with and have no chats in common with %user%. Shame.

View File

@ -1,4 +1,4 @@
1 English application/x-vnd.chat-o-matic.purple 3277859582 1 English application/x-vnd.cardie.purple 2993124882
Connection error PurpleApp ― Connection errors Connection error Connection error PurpleApp ― Connection errors Connection error
** You can't undo what was once done… at least with this protocol.\n PurpleApp ― Room moderation ** You can't undo what was once done… at least with this protocol.\n ** You can't undo what was once done… at least with this protocol.\n PurpleApp ― Room moderation ** You can't undo what was once done… at least with this protocol.\n
** Command isn't useful in this chat %err%\n PurpleApp ― Command errors ** Command isn't useful in this chat %err%\n ** Command isn't useful in this chat %err%\n PurpleApp ― Command errors ** Command isn't useful in this chat %err%\n
@ -6,8 +6,8 @@ Self-signed certificate PurpleApp ― Connection errors Self-signed certificate
Username: PurpleApp ― Account template Username: Username: PurpleApp ― Account template Username:
No SSL certificate provided PurpleApp ― Connection errors No SSL certificate provided No SSL certificate provided PurpleApp ― Connection errors No SSL certificate provided
SSL unsupported PurpleApp ― Connection errors SSL unsupported SSL unsupported PurpleApp ― Connection errors SSL unsupported
Authentication failed PurpleApp ― Connection errors Authentication failed
** Command error %err%\n PurpleApp ― Command errors ** Command error %err%\n ** Command error %err%\n PurpleApp ― Command errors ** Command error %err%\n
Authentication failed PurpleApp ― Connection errors Authentication failed
You can't friend someone without a nick. PurpleProtocol ― Roster template You can't friend someone without a nick. You can't friend someone without a nick. PurpleProtocol ― Roster template You can't friend someone without a nick.
** Command failed %err%\n PurpleApp ― Command errors ** Command failed %err%\n ** Command failed %err%\n PurpleApp ― Command errors ** Command failed %err%\n
Certificate error PurpleApp ― Connection errors Certificate error Certificate error PurpleApp ― Connection errors Certificate error
@ -20,12 +20,10 @@ Certifcate and fingerprint conflict PurpleApp ― Connection errors Certifcate
Password: PurpleApp ― Account template Password: Password: PurpleApp ― Account template Password:
Invalid username PurpleApp ― Connection errors Invalid username Invalid username PurpleApp ― Connection errors Invalid username
Username in use PurpleApp ― Connection errors Username in use Username in use PurpleApp ― Connection errors Username in use
User changed name to %nick% PurpleApp ― Room template User changed name to %nick%
Encryption error PurpleApp ― Connection errors Encryption error Encryption error PurpleApp ― Connection errors Encryption error
A username needs to be specified! PurpleApp ― Account template A username needs to be specified! A username needs to be specified! PurpleApp ― Account template A username needs to be specified!
Settings invalid PurpleApp ― Connection errors Settings invalid Settings invalid PurpleApp ― Connection errors Settings invalid
Moderator PurpleApp ― User roles Moderator Moderator PurpleApp ― User roles Moderator
OK PurpleApp ― Room template OK
Alias: PurpleProtocol ― Roster template Alias: Alias: PurpleProtocol ― Roster template Alias:
Untrusted SSL certificate PurpleApp ― Connection errors Untrusted SSL certificate Untrusted SSL certificate PurpleApp ― Connection errors Untrusted SSL certificate
Operator PurpleApp ― User roles Operator Operator PurpleApp ― User roles Operator
@ -35,12 +33,10 @@ Founder PurpleApp ― User roles Founder
Certificate and hostname conflict PurpleApp ― Connection errors Certificate and hostname conflict Certificate and hostname conflict PurpleApp ― Connection errors Certificate and hostname conflict
** Invalid arguments to command %err%\n PurpleApp ― Command errors ** Invalid arguments to command %err%\n ** Invalid arguments to command %err%\n PurpleApp ― Command errors ** Invalid arguments to command %err%\n
** Command not found %err%\n PurpleApp ― Command errors ** Command not found %err%\n ** Command not found %err%\n PurpleApp ― Command errors ** Command not found %err%\n
Couldn't set your nick:\n%error% PurpleApp ― Room template Couldn't set your nick:\n%error%
Expired SSL certificate PurpleApp ― Connection errors Expired SSL certificate Expired SSL certificate PurpleApp ― Connection errors Expired SSL certificate
** Banning won't work with this protocol. Try being mean instead.\n PurpleApp ― Room moderation ** Banning won't work with this protocol. Try being mean instead.\n ** Banning won't work with this protocol. Try being mean instead.\n PurpleApp ― Room moderation ** Banning won't work with this protocol. Try being mean instead.\n
Room ID PurpleApp ― Room template Room ID Room ID PurpleApp ― Room template Room ID
** This protocol is particularly self-concious, and prefers that this person not see its chats.\n PurpleApp ― Room moderation ** This protocol is particularly self-concious, and prefers that this person not see its chats.\n ** This protocol is particularly self-concious, and prefers that this person not see its chats.\n PurpleApp ― Room moderation ** This protocol is particularly self-concious, and prefers that this person not see its chats.\n
Failed to set nickname PurpleApp ― Room template Failed to set nickname
Authentication impossible PurpleApp ― Connection errors Authentication impossible Authentication impossible PurpleApp ― Connection errors Authentication impossible
Username: PurpleProtocol ― Roster template Username: Username: PurpleProtocol ― Roster template Username:
** This protocol doesn't support deafening, but spamming the chat should be a good substitute. :^)\n PurpleApp ― Room moderation ** This protocol doesn't support deafening, but spamming the chat should be a good substitute. :^)\n ** This protocol doesn't support deafening, but spamming the chat should be a good substitute. :^)\n PurpleApp ― Room moderation ** This protocol doesn't support deafening, but spamming the chat should be a good substitute. :^)\n

Some files were not shown because too many files have changed in this diff Show More