1
0
Fork 0
mirror of https://github.com/juce-framework/JUCE.git synced 2026-01-10 23:44:24 +00:00
JUCE/extras/Projucer/Source/LiveBuildEngine/jucer_ClientServerMessages.h

288 lines
11 KiB
C++

/*
==============================================================================
This file is part of the JUCE 6 technical preview.
Copyright (c) 2017 - ROLI Ltd.
You may use this code under the terms of the GPL v3
(see www.gnu.org/licenses).
For this technical preview, this file is not subject to commercial licensing.
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
DISCLAIMED.
==============================================================================
*/
#pragma once
//==============================================================================
struct MessageHandler
{
virtual ~MessageHandler() {}
virtual bool sendMessage (const ValueTree&) = 0;
static MemoryBlock convertMessage (const ValueTree& tree)
{
MemoryOutputStream out;
tree.writeToStream (out);
return out.getMemoryBlock();
}
static ValueTree convertMessage (const MemoryBlock& rawData)
{
return ValueTree::readFromData (rawData.getData(), rawData.getSize());
}
};
//==============================================================================
static inline Rectangle<int> varToRect (const var& v)
{
if (const Array<var>* obj = v.getArray())
{
if (obj->size() == 4)
{
int intArray[4];
for (int i = 0; i < 4; ++i)
{
const var& p = obj->getReference (i);
if (p.isInt() || p.isDouble() || p.isInt64())
intArray[i] = static_cast<int> (p);
else
return Rectangle<int>();
}
return Rectangle<int> (intArray[0], intArray[1], intArray[2], intArray[3]);
}
}
return Rectangle<int>();
}
static inline var rectToVar (const Rectangle<int>& rect)
{
Array<var> retval;
retval.add (var (rect.getX()));
retval.add (var (rect.getY()));
retval.add (var (rect.getWidth()));
retval.add (var (rect.getHeight()));
return var (retval);
}
//==============================================================================
namespace MessageTypes
{
inline bool send (MessageHandler& target, const ValueTree& v)
{
bool result = target.sendMessage (v);
if (! result)
Logger::outputDebugString ("*** Message failed: " + v.getType().toString());
return result;
}
inline bool sendPing (MessageHandler& target)
{
return send (target, ValueTree (PING));
}
//==============================================================================
// client -> server
inline void sendOpenPreview (MessageHandler& target, const ClassDatabase::Class& comp, Rectangle<int> mainWindowRect)
{
ValueTree v (OPEN_PREVIEW);
v.setProperty (Ids::name, comp.getName(), nullptr);
v.setProperty (Ids::bounds, rectToVar (mainWindowRect), nullptr);
send (target, v);
}
inline void sendReinstantiate (MessageHandler& target)
{
send (target, ValueTree (RELOAD));
}
inline void sendFileChanges (MessageHandler& target, const Array<CodeChange>& changes, const File& file)
{
ValueTree changesMessage (MessageTypes::LIVE_FILE_CHANGES);
changesMessage.setProperty (Ids::file, file.getFullPathName(), nullptr);
for (const CodeChange& change : changes)
{
ValueTree v (CHANGE);
v.setProperty (Ids::start, change.range.getStart(), nullptr);
v.setProperty (Ids::end, change.range.getEnd(), nullptr);
v.setProperty (Ids::text, change.text, nullptr);
changesMessage.appendChild (v, nullptr);
}
send (target, changesMessage);
}
inline Array<CodeChange> getChangeArray (const ValueTree& changes)
{
Array<CodeChange> result;
for (int i = 0; i < changes.getNumChildren(); ++i)
{
const ValueTree& v = changes.getChild (i);
result.add (CodeChange (Range<int> (v[Ids::start], v[Ids::end]), v[Ids::text]));
}
return result;
}
inline void sendFileContentFullUpdate (MessageHandler& target, const File& file, const String& text)
{
ValueTree v (LIVE_FILE_UPDATE);
v.setProperty (Ids::file, file.getFullPathName(), nullptr);
v.setProperty (Ids::text, text, nullptr);
send (target, v);
}
inline void sendHandleFileReset (MessageHandler& target, const File& file)
{
ValueTree v (LIVE_FILE_RESET);
v.setProperty (Ids::file, file.getFullPathName(), nullptr);
send (target, v);
}
inline void sendNewBuild (MessageHandler& target, const ProjectBuildInfo& build)
{
send (target, build.tree);
}
inline void sendCleanAll (MessageHandler& target)
{
send (target, ValueTree (CLEAN_ALL));
}
inline void sendNewDiagnosticList (MessageHandler& target, const ValueTree& list)
{
send (target, list);
}
inline void sendEmptyDiagnosticList (MessageHandler& target)
{
send (target, ValueTree (MessageTypes::DIAGNOSTIC_LIST));
}
inline void sendProcessActivationState (MessageHandler& target, bool isNowActive)
{
ValueTree v (FOREGROUND);
v.setProperty (Ids::parentActive, isNowActive, nullptr);
send (target, v);
}
inline void sendLaunchApp (MessageHandler& target) { send (target, ValueTree (LAUNCH_APP)); }
inline void sendQuit (MessageHandler& target) { send (target, ValueTree (QUIT_SERVER)); }
inline void sendShouldCloseIDE (MessageHandler& target) { send (target, ValueTree (QUIT_IDE)); }
//==============================================================================
// server -> client
inline void sendNewClassList (MessageHandler& target, const ClassDatabase::ClassList& classes)
{
send (target, classes.toValueTree());
}
inline void sendCrash (MessageHandler& target, const String& message)
{
ValueTree v (CRASH);
v.setProperty (Ids::message, message, nullptr);
send (target, v);
}
inline void sendSystemHeadersMissing (MessageHandler& target)
{
send (target, ValueTree (MISSING_SYSTEM_HEADERS));
}
inline void sendBuildFailed (MessageHandler& target)
{
send (target, ValueTree (BUILD_FAILED));
}
inline void sendNewActivityList (MessageHandler& target, const StringArray& list)
{
ValueTree v (ACTIVITY_LIST);
v.setProperty (Ids::list, concatenateListOfStrings (list), nullptr);
send (target, v);
}
inline void sendChangeCode (MessageHandler& target, const String& location, const String& newText)
{
if (location.isNotEmpty())
{
ValueTree v (CHANGE_CODE);
v.setProperty (Ids::position, location, nullptr);
v.setProperty (Ids::text, newText, nullptr);
send (target, v);
}
}
inline void sendHighlightCode (MessageHandler& target, const String& location)
{
if (location.isNotEmpty())
{
ValueTree v (HIGHLIGHT_CODE);
v.setProperty (Ids::position, location, nullptr);
send (target, v);
}
}
inline void sendAppLaunched (MessageHandler& target) { send (target, ValueTree (LAUNCHED)); }
inline void sendAppQuit (MessageHandler& target) { send (target, ValueTree (APPQUIT)); }
inline void sendKeyPress (MessageHandler& target, const String& className, const String& keyDesc)
{
ValueTree v (KEY);
v.setProperty (Ids::class_, className, nullptr);
v.setProperty (Ids::key, keyDesc, nullptr);
send (target, v);
}
//==============================================================================
template <class MessageHandlerType>
static void dispatchToClient (MessageHandlerType& target, const ValueTree& v)
{
if (v.hasType (DIAGNOSTIC_LIST)) target.handleNewDiagnosticList (v);
else if (v.hasType (ACTIVITY_LIST)) target.handleActivityListChanged (separateJoinedStrings (v [Ids::list]));
else if (v.hasType (Ids::CLASSLIST)) target.handleClassListChanged (v);
else if (v.hasType (BUILD_FAILED)) target.handleBuildFailed();
else if (v.hasType (CHANGE_CODE)) target.handleChangeCode (v [Ids::position].toString(), v [Ids::text]);
else if (v.hasType (HIGHLIGHT_CODE)) target.handleHighlightCode (v [Ids::position].toString());
else if (v.hasType (LAUNCHED)) target.handleAppLaunched();
else if (v.hasType (APPQUIT)) target.handleAppQuit();
else if (v.hasType (PING)) target.handlePing();
else if (v.hasType (CRASH)) target.handleCrash (v [Ids::message]);
else if (v.hasType (KEY)) target.handleKeyPress (v[Ids::class_], KeyPress::createFromDescription (v[Ids::key]));
else if (v.hasType (QUIT_IDE)) target.handleCloseIDE();
else if (v.hasType (MISSING_SYSTEM_HEADERS)) target.handleMissingSystemHeaders();
else jassertfalse;
}
template <class MessageHandlerType>
static void dispatchToServer (MessageHandlerType& target, const ValueTree& v)
{
if (v.hasType (CLEAN_ALL)) target.handleCleanAll();
else if (v.hasType (BUILDINFO)) target.handleNewBuildSettings (ProjectBuildInfo (v));
else if (v.hasType (OPEN_PREVIEW)) target.handleOpenPreview (v[Ids::name], varToRect (v[Ids::bounds]));
else if (v.hasType (RELOAD)) target.handleReinstantiatePreviews();
else if (v.hasType (LAUNCH_APP)) target.handleLaunchApp();
else if (v.hasType (LIVE_FILE_CHANGES)) target.handleLiveFileChanges (v[Ids::file].toString(), getChangeArray (v));
else if (v.hasType (LIVE_FILE_UPDATE)) target.handleLiveFileFullUpdate (v[Ids::file].toString(), v[Ids::text]);
else if (v.hasType (LIVE_FILE_RESET)) target.handleResetLiveFileContent (v[Ids::file].toString());
else if (v.hasType (FOREGROUND)) target.handleProcessActivationState (v[Ids::parentActive]);
else if (v.hasType (PING)) target.handlePing();
else jassertfalse;
}
}