/* ============================================================================== This file is part of the JUCE library. Copyright (c) 2015 - ROLI Ltd. Permission is granted to use this software under the terms of either: a) the GPL v2 (or any later version) b) the Affero GPL v3 Details of these licenses can be found at: www.gnu.org/licenses JUCE is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. ------------------------------------------------------------------------------ To release a closed-source product which uses JUCE, commercial licenses are available: visit www.juce.com for more information. ============================================================================== */ class ApplicationCommandTarget::CommandMessage : public MessageManager::MessageBase { public: CommandMessage (ApplicationCommandTarget* const target, const InvocationInfo& inf) : owner (target), info (inf) { } void messageCallback() override { if (ApplicationCommandTarget* const target = owner) target->tryToInvoke (info, false); } private: WeakReference owner; const InvocationInfo info; JUCE_DECLARE_NON_COPYABLE (CommandMessage) }; //============================================================================== ApplicationCommandTarget::ApplicationCommandTarget() { } ApplicationCommandTarget::~ApplicationCommandTarget() { masterReference.clear(); } //============================================================================== bool ApplicationCommandTarget::tryToInvoke (const InvocationInfo& info, const bool async) { if (isCommandActive (info.commandID)) { if (async) { (new CommandMessage (this, info))->post(); return true; } if (perform (info)) return true; // Hmm.. your target claimed that it could perform this command, but failed to do so. // If it can't do it at the moment for some reason, it should clear the 'isActive' flag // when it returns the command's info. jassertfalse; } return false; } ApplicationCommandTarget* ApplicationCommandTarget::findFirstTargetParentComponent() { if (Component* const c = dynamic_cast (this)) return c->findParentComponentOfClass(); return nullptr; } ApplicationCommandTarget* ApplicationCommandTarget::getTargetForCommand (const CommandID commandID) { ApplicationCommandTarget* target = this; int depth = 0; while (target != nullptr) { Array commandIDs; target->getAllCommands (commandIDs); if (commandIDs.contains (commandID)) return target; target = target->getNextCommandTarget(); ++depth; jassert (depth < 100); // could be a recursive command chain?? jassert (target != this); // definitely a recursive command chain! if (depth > 100 || target == this) break; } if (target == nullptr) { target = JUCEApplication::getInstance(); if (target != nullptr) { Array commandIDs; target->getAllCommands (commandIDs); if (commandIDs.contains (commandID)) return target; } } return nullptr; } bool ApplicationCommandTarget::isCommandActive (const CommandID commandID) { ApplicationCommandInfo info (commandID); info.flags = ApplicationCommandInfo::isDisabled; getCommandInfo (commandID, info); return (info.flags & ApplicationCommandInfo::isDisabled) == 0; } //============================================================================== bool ApplicationCommandTarget::invoke (const InvocationInfo& info, const bool async) { ApplicationCommandTarget* target = this; int depth = 0; while (target != nullptr) { if (target->tryToInvoke (info, async)) return true; target = target->getNextCommandTarget(); ++depth; jassert (depth < 100); // could be a recursive command chain?? jassert (target != this); // definitely a recursive command chain! if (depth > 100 || target == this) break; } if (target == nullptr) { target = JUCEApplication::getInstance(); if (target != nullptr) return target->tryToInvoke (info, async); } return false; } bool ApplicationCommandTarget::invokeDirectly (const CommandID commandID, const bool asynchronously) { ApplicationCommandTarget::InvocationInfo info (commandID); info.invocationMethod = ApplicationCommandTarget::InvocationInfo::direct; return invoke (info, asynchronously); } //============================================================================== ApplicationCommandTarget::InvocationInfo::InvocationInfo (const CommandID command) : commandID (command), commandFlags (0), invocationMethod (direct), originatingComponent (nullptr), isKeyDown (false), millisecsSinceKeyPressed (0) { }