The JUCE cross-platform C++ framework, with DISTRHO/KXStudio specific changes
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

189 lines
5.7KB

  1. /*
  2. ==============================================================================
  3. This file is part of the JUCE library - "Jules' Utility Class Extensions"
  4. Copyright 2004-11 by Raw Material Software Ltd.
  5. ------------------------------------------------------------------------------
  6. JUCE can be redistributed and/or modified under the terms of the GNU General
  7. Public License (Version 2), as published by the Free Software Foundation.
  8. A copy of the license is included in the JUCE distribution, or can be found
  9. online at www.gnu.org/licenses.
  10. JUCE is distributed in the hope that it will be useful, but WITHOUT ANY
  11. WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
  12. A PARTICULAR PURPOSE. See the GNU General Public License for more details.
  13. ------------------------------------------------------------------------------
  14. To release a closed-source product which uses JUCE, commercial licenses are
  15. available: visit www.rawmaterialsoftware.com/juce for more information.
  16. ==============================================================================
  17. */
  18. class ApplicationCommandTarget::CommandMessage : public MessageManager::MessageBase
  19. {
  20. public:
  21. CommandMessage (ApplicationCommandTarget* const target, const InvocationInfo& inf)
  22. : owner (target), info (inf)
  23. {
  24. }
  25. void messageCallback()
  26. {
  27. if (ApplicationCommandTarget* const target = owner)
  28. target->tryToInvoke (info, false);
  29. }
  30. private:
  31. WeakReference<ApplicationCommandTarget> owner;
  32. const InvocationInfo info;
  33. JUCE_DECLARE_NON_COPYABLE (CommandMessage);
  34. };
  35. //==============================================================================
  36. ApplicationCommandTarget::ApplicationCommandTarget()
  37. {
  38. }
  39. ApplicationCommandTarget::~ApplicationCommandTarget()
  40. {
  41. masterReference.clear();
  42. }
  43. //==============================================================================
  44. bool ApplicationCommandTarget::tryToInvoke (const InvocationInfo& info, const bool async)
  45. {
  46. if (isCommandActive (info.commandID))
  47. {
  48. if (async)
  49. {
  50. (new CommandMessage (this, info))->post();
  51. return true;
  52. }
  53. else
  54. {
  55. const bool success = perform (info);
  56. jassert (success); // Hmm.. your target claimed that it could perform this command, but failed to do so.
  57. // If it can't do it at the moment for some reason, it should clear the 'isActive' flag
  58. // when it returns the command's info.
  59. return success;
  60. }
  61. }
  62. return false;
  63. }
  64. ApplicationCommandTarget* ApplicationCommandTarget::findFirstTargetParentComponent()
  65. {
  66. if (Component* const c = dynamic_cast <Component*> (this))
  67. return c->findParentComponentOfClass<ApplicationCommandTarget>();
  68. return nullptr;
  69. }
  70. ApplicationCommandTarget* ApplicationCommandTarget::getTargetForCommand (const CommandID commandID)
  71. {
  72. ApplicationCommandTarget* target = this;
  73. int depth = 0;
  74. while (target != nullptr)
  75. {
  76. Array <CommandID> commandIDs;
  77. target->getAllCommands (commandIDs);
  78. if (commandIDs.contains (commandID))
  79. return target;
  80. target = target->getNextCommandTarget();
  81. ++depth;
  82. jassert (depth < 100); // could be a recursive command chain??
  83. jassert (target != this); // definitely a recursive command chain!
  84. if (depth > 100 || target == this)
  85. break;
  86. }
  87. if (target == nullptr)
  88. {
  89. target = JUCEApplication::getInstance();
  90. if (target != nullptr)
  91. {
  92. Array <CommandID> commandIDs;
  93. target->getAllCommands (commandIDs);
  94. if (commandIDs.contains (commandID))
  95. return target;
  96. }
  97. }
  98. return nullptr;
  99. }
  100. bool ApplicationCommandTarget::isCommandActive (const CommandID commandID)
  101. {
  102. ApplicationCommandInfo info (commandID);
  103. info.flags = ApplicationCommandInfo::isDisabled;
  104. getCommandInfo (commandID, info);
  105. return (info.flags & ApplicationCommandInfo::isDisabled) == 0;
  106. }
  107. //==============================================================================
  108. bool ApplicationCommandTarget::invoke (const InvocationInfo& info, const bool async)
  109. {
  110. ApplicationCommandTarget* target = this;
  111. int depth = 0;
  112. while (target != nullptr)
  113. {
  114. if (target->tryToInvoke (info, async))
  115. return true;
  116. target = target->getNextCommandTarget();
  117. ++depth;
  118. jassert (depth < 100); // could be a recursive command chain??
  119. jassert (target != this); // definitely a recursive command chain!
  120. if (depth > 100 || target == this)
  121. break;
  122. }
  123. if (target == nullptr)
  124. {
  125. target = JUCEApplication::getInstance();
  126. if (target != nullptr)
  127. return target->tryToInvoke (info, async);
  128. }
  129. return false;
  130. }
  131. bool ApplicationCommandTarget::invokeDirectly (const CommandID commandID, const bool asynchronously)
  132. {
  133. ApplicationCommandTarget::InvocationInfo info (commandID);
  134. info.invocationMethod = ApplicationCommandTarget::InvocationInfo::direct;
  135. return invoke (info, asynchronously);
  136. }
  137. //==============================================================================
  138. ApplicationCommandTarget::InvocationInfo::InvocationInfo (const CommandID command)
  139. : commandID (command),
  140. commandFlags (0),
  141. invocationMethod (direct),
  142. originatingComponent (nullptr),
  143. isKeyDown (false),
  144. millisecsSinceKeyPressed (0)
  145. {
  146. }