diff --git a/extras/Introjucer/Source/Application/jucer_Application.h b/extras/Introjucer/Source/Application/jucer_Application.h index abe5a8aae5..0ad33cda59 100644 --- a/extras/Introjucer/Source/Application/jucer_Application.h +++ b/extras/Introjucer/Source/Application/jucer_Application.h @@ -72,6 +72,12 @@ public: commandManager = new ApplicationCommandManager(); commandManager->registerAllCommandsForTarget (this); + { + CodeDocument doc; + CodeEditorComponent ed (doc, nullptr); + commandManager->registerAllCommandsForTarget (&ed); + } + menuModel = new MainMenuModel(); doExtraInitialisation(); @@ -262,13 +268,10 @@ public: menu.addCommandItem (commandManager, StandardApplicationCommandIDs::selectAll); menu.addCommandItem (commandManager, StandardApplicationCommandIDs::deselectAll); menu.addSeparator(); - menu.addCommandItem (commandManager, CommandIDs::toFront); - menu.addCommandItem (commandManager, CommandIDs::toBack); - menu.addSeparator(); - menu.addCommandItem (commandManager, CommandIDs::group); - menu.addCommandItem (commandManager, CommandIDs::ungroup); - menu.addSeparator(); - menu.addCommandItem (commandManager, CommandIDs::bringBackLostItems); + menu.addCommandItem (commandManager, CommandIDs::showFindPanel); + menu.addCommandItem (commandManager, CommandIDs::findSelection); + menu.addCommandItem (commandManager, CommandIDs::findNext); + menu.addCommandItem (commandManager, CommandIDs::findPrevious); } virtual void createViewMenu (PopupMenu& menu) @@ -331,7 +334,6 @@ public: const CommandID ids[] = { CommandIDs::newProject, CommandIDs::open, - CommandIDs::showPrefs, CommandIDs::closeAllDocuments, CommandIDs::saveAll, CommandIDs::updateModules, @@ -355,11 +357,6 @@ public: result.defaultKeypresses.add (KeyPress ('o', ModifierKeys::commandModifier, 0)); break; - case CommandIDs::showPrefs: - result.setInfo ("Preferences...", "Shows the preferences panel.", CommandCategories::general, 0); - result.defaultKeypresses.add (KeyPress (',', ModifierKeys::commandModifier, 0)); - break; - case CommandIDs::showAppearanceSettings: result.setInfo ("Fonts and Colours...", "Shows the appearance settings window.", CommandCategories::general, 0); break; @@ -394,7 +391,6 @@ public: { case CommandIDs::newProject: createNewProject(); break; case CommandIDs::open: askUserToOpenFile(); break; - case CommandIDs::showPrefs: showPrefsPanel(); break; case CommandIDs::saveAll: openDocumentManager.saveAll(); break; case CommandIDs::closeAllDocuments: closeAllDocuments (true); break; case CommandIDs::showUTF8Tool: showUTF8ToolWindow (utf8Window); break; @@ -407,11 +403,6 @@ public: } //============================================================================== - void showPrefsPanel() - { - jassertfalse; - } - void createNewProject() { if (makeSureUserHasSelectedModuleFolder()) @@ -504,8 +495,7 @@ private: stopTimer(); delete this; - JUCEApplication* app = JUCEApplication::getInstance(); - if (app != nullptr) + if (JUCEApplication* app = JUCEApplication::getInstance()) app->systemRequestedQuit(); } diff --git a/extras/Introjucer/Source/Application/jucer_CommandIDs.h b/extras/Introjucer/Source/Application/jucer_CommandIDs.h index 0e38ae410d..33d0934f1b 100644 --- a/extras/Introjucer/Source/Application/jucer_CommandIDs.h +++ b/extras/Introjucer/Source/Application/jucer_CommandIDs.h @@ -37,53 +37,27 @@ namespace CommandIDs closeProject = 0x200051, saveProject = 0x200060, + saveAll = 0x200080, openInIDE = 0x200072, saveAndOpenInIDE = 0x200073, + updateModules = 0x200075, showUTF8Tool = 0x200076, showAppearanceSettings = 0x200077, showConfigPanel = 0x200074, showFilePanel = 0x200078, - saveAll = 0x200080, - closeWindow = 0x201001, closeAllDocuments = 0x201000, goToPreviousDoc = 0x201002, goToNextDoc = 0x201003, goToCounterpart = 0x201004, + deleteSelectedItem = 0x201005, - toFront = 0x2020a0, - toBack = 0x2030a1, - showOrHideProperties = 0x2030b0, - showOrHideTree = 0x2030b1, - showOrHideMarkers = 0x2030b2, - toggleSnapping = 0x2030b3, - - makeLineSegment = 0x2030c0, - makeCubicSegment = 0x2030c1, - breakSegment = 0x2030c2, - pointModeCorner = 0x2030c3, - pointModeRounded = 0x2030c4, - pointModeSymmetric = 0x2030c5, - - group = 0x202170, - ungroup = 0x202180, - - showPrefs = 0x2020c0, - useTabbedWindows = 0x2020d0, - - showGrid = 0x2020e0, - enableSnapToGrid = 0x2020f0, - zoomIn = 0x202130, - zoomOut = 0x202140, - zoomNormal = 0x202150, - spaceBarDrag = 0x202160, - bringBackLostItems = 0x202120, - - newDocumentBase = 0x322010, - newComponentBase = 0x302010, - newElementBase = 0x312010 + showFindPanel = 0x2010a0, + findSelection = 0x2010a1, + findNext = 0x2010a2, + findPrevious = 0x2010a3 }; } diff --git a/extras/Introjucer/Source/Application/jucer_MainWindow.cpp b/extras/Introjucer/Source/Application/jucer_MainWindow.cpp index 73b98a8d0e..b4035d91b5 100644 --- a/extras/Introjucer/Source/Application/jucer_MainWindow.cpp +++ b/extras/Introjucer/Source/Application/jucer_MainWindow.cpp @@ -259,7 +259,7 @@ void MainWindow::showNewProjectWizard() //============================================================================== ApplicationCommandTarget* MainWindow::getNextCommandTarget() { - return 0; + return nullptr; } void MainWindow::getAllCommands (Array & commands) diff --git a/extras/Introjucer/Source/Code Editor/jucer_SourceCodeEditor.cpp b/extras/Introjucer/Source/Code Editor/jucer_SourceCodeEditor.cpp index afa4a73e9d..6933ff7e57 100644 --- a/extras/Introjucer/Source/Code Editor/jucer_SourceCodeEditor.cpp +++ b/extras/Introjucer/Source/Code Editor/jucer_SourceCodeEditor.cpp @@ -106,9 +106,7 @@ SourceCodeEditor::~SourceCodeEditor() { getAppSettings().appearance.settings.removeListener (this); - SourceCodeDocument* doc = dynamic_cast (getDocument()); - - if (doc != nullptr) + if (SourceCodeDocument* doc = dynamic_cast (getDocument())) doc->updateLastState (*editor); } @@ -176,6 +174,7 @@ static CPlusPlusCodeTokeniser cppTokeniser; CppCodeEditorComponent::CppCodeEditorComponent (const File& f, CodeDocument& codeDocument) : CodeEditorComponent (codeDocument, &cppTokeniser), file (f) { + setCommandManager (commandManager); } void CppCodeEditorComponent::handleReturnKey() diff --git a/extras/Introjucer/Source/Project/jucer_ProjectContentComponent.cpp b/extras/Introjucer/Source/Project/jucer_ProjectContentComponent.cpp index a43c49a46f..7b55e53cce 100644 --- a/extras/Introjucer/Source/Project/jucer_ProjectContentComponent.cpp +++ b/extras/Introjucer/Source/Project/jucer_ProjectContentComponent.cpp @@ -535,7 +535,7 @@ void ProjectContentComponent::getAllCommands (Array & commands) CommandIDs::goToPreviousDoc, CommandIDs::goToNextDoc, CommandIDs::goToCounterpart, - StandardApplicationCommandIDs::del }; + CommandIDs::deleteSelectedItem }; commands.addArray (ids, numElementsInArray (ids)); } @@ -655,7 +655,7 @@ void ProjectContentComponent::getCommandInfo (const CommandID commandID, Applica result.defaultKeypresses.add (KeyPress ('i', ModifierKeys::commandModifier, 0)); break; - case StandardApplicationCommandIDs::del: + case CommandIDs::deleteSelectedItem: result.setInfo ("Delete Selected File", String::empty, CommandCategories::general, 0); result.defaultKeypresses.add (KeyPress (KeyPress::deleteKey, 0, 0)); result.defaultKeypresses.add (KeyPress (KeyPress::backspaceKey, 0, 0)); @@ -712,7 +712,7 @@ bool ProjectContentComponent::perform (const InvocationInfo& info) case CommandIDs::openInIDE: openInIDE(); break; - case StandardApplicationCommandIDs::del: deleteSelectedTreeItems(); break; + case CommandIDs::deleteSelectedItem: deleteSelectedTreeItems(); break; case CommandIDs::saveAndOpenInIDE: if (saveProject()) diff --git a/extras/Introjucer/Source/Project/jucer_TreeViewTypes.cpp b/extras/Introjucer/Source/Project/jucer_TreeViewTypes.cpp index e74fb446e0..05c8adb9a6 100644 --- a/extras/Introjucer/Source/Project/jucer_TreeViewTypes.cpp +++ b/extras/Introjucer/Source/Project/jucer_TreeViewTypes.cpp @@ -75,12 +75,8 @@ void GroupTreeViewItem::moveSelectedItemsTo (OwnedArray & selecte void GroupTreeViewItem::checkFileStatus() { for (int i = 0; i < getNumSubItems(); ++i) - { - ProjectTreeViewBase* p = dynamic_cast (getSubItem(i)); - - if (p != nullptr) + if (ProjectTreeViewBase* p = dynamic_cast (getSubItem(i))) p->checkFileStatus(); - } } ProjectTreeViewBase* GroupTreeViewItem::createSubItem (const Project::Item& child) @@ -97,9 +93,7 @@ ProjectTreeViewBase* GroupTreeViewItem::createSubItem (const Project::Item& chil void GroupTreeViewItem::showDocument() { - ProjectContentComponent* pcc = getProjectContentComponent(); - - if (pcc != nullptr) + if (ProjectContentComponent* pcc = getProjectContentComponent()) pcc->setEditorComponent (new GroupInformationComponent (item), nullptr); } @@ -243,8 +237,7 @@ void SourceFileTreeViewItem::showPopupMenu() { PopupMenu m; - GroupTreeViewItem* parentGroup = dynamic_cast (getParentProjectItem()); - if (parentGroup != nullptr) + if (GroupTreeViewItem* parentGroup = dynamic_cast (getParentProjectItem())) { parentGroup->addCreateFileMenuItems (m); m.addSeparator(); @@ -267,8 +260,6 @@ void SourceFileTreeViewItem::showPopupMenu() void SourceFileTreeViewItem::handlePopupMenuResult (int resultCode) { - GroupTreeViewItem* parentGroup = dynamic_cast (getParentProjectItem()); - switch (resultCode) { case 1: getFile().startAsProcess(); break; @@ -277,7 +268,7 @@ void SourceFileTreeViewItem::handlePopupMenuResult (int resultCode) case 4: triggerAsyncRename (item); break; default: - if (parentGroup != nullptr) + if (GroupTreeViewItem* parentGroup = dynamic_cast (getParentProjectItem())) parentGroup->processCreateFileMenuItem (resultCode); break; diff --git a/modules/juce_audio_plugin_client/utility/juce_FakeMouseMoveGenerator.h b/modules/juce_audio_plugin_client/utility/juce_FakeMouseMoveGenerator.h index c5549b2845..f1ecea87aa 100644 --- a/modules/juce_audio_plugin_client/utility/juce_FakeMouseMoveGenerator.h +++ b/modules/juce_audio_plugin_client/utility/juce_FakeMouseMoveGenerator.h @@ -49,17 +49,10 @@ public: const ModifierKeys mods (ModifierKeys::getCurrentModifiers()); if (! mods.isAnyMouseButtonDown()) - { - Component* comp = Desktop::getInstance().findComponentAt (screenPos); - - if (comp != nullptr) - { - ComponentPeer* const peer = comp->getPeer(); - - if (peer != nullptr && ! peer->isFocused()) - peer->handleMouseEvent (0, screenPos - peer->getScreenPosition(), mods, Time::currentTimeMillis()); - } - } + if (Component* const comp = Desktop::getInstance().findComponentAt (screenPos)) + if (ComponentPeer* const peer = comp->getPeer()) + if (! peer->isFocused()) + peer->handleMouseEvent (0, screenPos - peer->getScreenPosition(), mods, Time::currentTimeMillis()); } } diff --git a/modules/juce_gui_basics/commands/juce_ApplicationCommandManager.cpp b/modules/juce_gui_basics/commands/juce_ApplicationCommandManager.cpp index 96d275c921..96066ac5a9 100644 --- a/modules/juce_gui_basics/commands/juce_ApplicationCommandManager.cpp +++ b/modules/juce_gui_basics/commands/juce_ApplicationCommandManager.cpp @@ -27,7 +27,6 @@ ApplicationCommandManager::ApplicationCommandManager() : firstTarget (nullptr) { keyMappings = new KeyPressMappingSet (this); - Desktop::getInstance().addFocusChangeListener (this); } @@ -65,7 +64,7 @@ void ApplicationCommandManager::registerCommand (const ApplicationCommandInfo& n } else { - // trying to re-register the same command with different parameters? + // trying to re-register the same command ID with different parameters? jassert (newCommand.shortName == getCommandForID (newCommand.commandID)->shortName && (newCommand.description == getCommandForID (newCommand.commandID)->description || newCommand.description.isEmpty()) && newCommand.categoryName == getCommandForID (newCommand.commandID)->categoryName @@ -169,26 +168,24 @@ bool ApplicationCommandManager::invokeDirectly (const CommandID commandID, const return invoke (info, asynchronously); } -bool ApplicationCommandManager::invoke (const ApplicationCommandTarget::InvocationInfo& info_, const bool asynchronously) +bool ApplicationCommandManager::invoke (const ApplicationCommandTarget::InvocationInfo& inf, const bool asynchronously) { // This call isn't thread-safe for use from a non-UI thread without locking the message // manager first.. jassert (MessageManager::getInstance()->currentThreadHasLockedMessageManager()); + bool ok = false; ApplicationCommandInfo commandInfo (0); - ApplicationCommandTarget* const target = getTargetForCommand (info_.commandID, commandInfo); - if (target == nullptr) - return false; + if (ApplicationCommandTarget* const target = getTargetForCommand (inf.commandID, commandInfo)) + { + ApplicationCommandTarget::InvocationInfo info (inf); + info.commandFlags = commandInfo.flags; - ApplicationCommandTarget::InvocationInfo info (info_); - info.commandFlags = commandInfo.flags; - - sendListenerInvokeCallback (info); - - const bool ok = target->invoke (info, asynchronously); - - commandStatusChanged(); + sendListenerInvokeCallback (info); + ok = target->invoke (info, asynchronously); + commandStatusChanged(); + } return ok; } @@ -239,9 +236,7 @@ ApplicationCommandTarget* ApplicationCommandManager::findDefaultComponentTarget( if (c == nullptr) { - TopLevelWindow* const activeWindow = TopLevelWindow::getActiveTopLevelWindow(); - - if (activeWindow != nullptr) + if (TopLevelWindow* const activeWindow = TopLevelWindow::getActiveTopLevelWindow()) { c = activeWindow->getPeer()->getLastFocusedSubcomponent(); @@ -252,16 +247,11 @@ ApplicationCommandTarget* ApplicationCommandManager::findDefaultComponentTarget( if (c == nullptr && Process::isForegroundProcess()) { - // getting a bit desperate now - try all desktop comps.. + // getting a bit desperate now: try all desktop comps.. for (int i = Desktop::getInstance().getNumComponents(); --i >= 0;) - { - ApplicationCommandTarget* const target - = findTargetForComponent (Desktop::getInstance().getComponent (i) - ->getPeer()->getLastFocusedSubcomponent()); - - if (target != nullptr) + if (ApplicationCommandTarget* const target = findTargetForComponent (Desktop::getInstance().getComponent (i) + ->getPeer()->getLastFocusedSubcomponent())) return target; - } } if (c != nullptr) @@ -275,9 +265,7 @@ ApplicationCommandTarget* ApplicationCommandManager::findDefaultComponentTarget( if (resizableWindow != nullptr && resizableWindow->getContentComponent() != nullptr) c = resizableWindow->getContentComponent(); - ApplicationCommandTarget* const target = findTargetForComponent (c); - - if (target != nullptr) + if (ApplicationCommandTarget* const target = findTargetForComponent (c)) return target; } diff --git a/modules/juce_gui_basics/commands/juce_ApplicationCommandManager.h b/modules/juce_gui_basics/commands/juce_ApplicationCommandManager.h index 324cd8c28b..e3935518d1 100644 --- a/modules/juce_gui_basics/commands/juce_ApplicationCommandManager.h +++ b/modules/juce_gui_basics/commands/juce_ApplicationCommandManager.h @@ -109,13 +109,11 @@ public: //============================================================================== /** Clears the current list of all commands. - Note that this will also clear the contents of the KeyPressMappingSet. */ void clearCommands(); /** Adds a command to the list of registered commands. - @see registerAllCommandsForTarget */ void registerCommand (const ApplicationCommandInfo& newCommand); @@ -131,7 +129,6 @@ public: void registerAllCommandsForTarget (ApplicationCommandTarget* target); /** Removes the command with a specified ID. - Note that this will also remove any key mappings that are mapped to the command. */ void removeCommand (CommandID commandID); @@ -150,13 +147,11 @@ public: //============================================================================== /** Returns the number of commands that have been registered. - @see registerCommand */ int getNumCommands() const noexcept { return commands.size(); } /** Returns the details about one of the registered commands. - The index is between 0 and (getNumCommands() - 1). */ const ApplicationCommandInfo* getCommandForIndex (int index) const noexcept { return commands [index]; } @@ -195,7 +190,6 @@ public: StringArray getCommandCategories() const; /** Returns a list of all the command UIDs in a particular category. - @see getCommandCategories() */ Array getCommandsInCategory (const String& categoryName) const; @@ -214,7 +208,6 @@ public: //============================================================================== /** Invokes the given command directly, sending it to the default target. - This is just an easy way to call invoke() without having to fill out the InvocationInfo structure. */ @@ -318,7 +311,7 @@ private: ScopedPointer keyMappings; ApplicationCommandTarget* firstTarget; - void sendListenerInvokeCallback (const ApplicationCommandTarget::InvocationInfo& info); + void sendListenerInvokeCallback (const ApplicationCommandTarget::InvocationInfo&); void handleAsyncUpdate(); void globalFocusChanged (Component*); diff --git a/modules/juce_gui_basics/commands/juce_ApplicationCommandTarget.cpp b/modules/juce_gui_basics/commands/juce_ApplicationCommandTarget.cpp index af288d5c57..e4173f593d 100644 --- a/modules/juce_gui_basics/commands/juce_ApplicationCommandTarget.cpp +++ b/modules/juce_gui_basics/commands/juce_ApplicationCommandTarget.cpp @@ -26,15 +26,14 @@ class ApplicationCommandTarget::CommandMessage : public MessageManager::MessageBase { public: - CommandMessage (ApplicationCommandTarget* const owner_, const InvocationInfo& info_) - : owner (owner_), info (info_) + CommandMessage (ApplicationCommandTarget* const target, const InvocationInfo& inf) + : owner (target), info (inf) { } void messageCallback() { - ApplicationCommandTarget* const target = owner; - if (target != nullptr) + if (ApplicationCommandTarget* const target = owner) target->tryToInvoke (info, false); } @@ -69,9 +68,9 @@ bool ApplicationCommandTarget::tryToInvoke (const InvocationInfo& info, const bo { const bool success = perform (info); - jassert (success); // hmm - your target should have been able to perform this command. 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. + jassert (success); // 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. return success; } } @@ -81,9 +80,7 @@ bool ApplicationCommandTarget::tryToInvoke (const InvocationInfo& info, const bo ApplicationCommandTarget* ApplicationCommandTarget::findFirstTargetParentComponent() { - Component* c = dynamic_cast (this); - - if (c != nullptr) + if (Component* const c = dynamic_cast (this)) return c->findParentComponentOfClass(); return nullptr; @@ -180,8 +177,8 @@ bool ApplicationCommandTarget::invokeDirectly (const CommandID commandID, const } //============================================================================== -ApplicationCommandTarget::InvocationInfo::InvocationInfo (const CommandID commandID_) - : commandID (commandID_), +ApplicationCommandTarget::InvocationInfo::InvocationInfo (const CommandID command) + : commandID (command), commandFlags (0), invocationMethod (direct), originatingComponent (nullptr), diff --git a/modules/juce_gui_basics/commands/juce_ApplicationCommandTarget.h b/modules/juce_gui_basics/commands/juce_ApplicationCommandTarget.h index 1833898ea8..f30f4d94cd 100644 --- a/modules/juce_gui_basics/commands/juce_ApplicationCommandTarget.h +++ b/modules/juce_gui_basics/commands/juce_ApplicationCommandTarget.h @@ -57,6 +57,7 @@ public: //============================================================================== /** + Contains contextual details about the invocation of a command. */ struct JUCE_API InvocationInfo { @@ -68,7 +69,6 @@ public: CommandID commandID; /** The command's flags. - See ApplicationCommandInfo for a description of these flag values. */ int commandFlags; @@ -124,7 +124,7 @@ public: that command, this method is used to determine the next target that should be tried. - It may return 0 if it doesn't know of another target. + It may return nullptr if it doesn't know of another target. If your target is a Component, you would usually use the findFirstTargetParentComponent() method to return a parent component that might want to handle it. diff --git a/modules/juce_gui_basics/components/juce_Component.h b/modules/juce_gui_basics/components/juce_Component.h index 85c9bf2ecb..1797d757df 100644 --- a/modules/juce_gui_basics/components/juce_Component.h +++ b/modules/juce_gui_basics/components/juce_Component.h @@ -776,11 +776,8 @@ public: TargetClass* findParentComponentOfClass() const { for (Component* p = parentComponent; p != nullptr; p = p->parentComponent) - { - TargetClass* const target = dynamic_cast (p); - if (target != nullptr) + if (TargetClass* const target = dynamic_cast (p)) return target; - } return nullptr; } diff --git a/modules/juce_gui_extra/code_editor/juce_CodeEditorComponent.cpp b/modules/juce_gui_extra/code_editor/juce_CodeEditorComponent.cpp index d520c6f526..f3e750786b 100644 --- a/modules/juce_gui_extra/code_editor/juce_CodeEditorComponent.cpp +++ b/modules/juce_gui_extra/code_editor/juce_CodeEditorComponent.cpp @@ -368,6 +368,7 @@ CodeEditorComponent::CodeEditorComponent (CodeDocument& doc, CodeTokeniser* cons selectionEnd (doc, 0, 0), verticalScrollBar (true), horizontalScrollBar (false), + appCommandManager (nullptr), codeTokeniser (tokeniser) { pimpl = new Pimpl (*this); @@ -590,6 +591,7 @@ void CodeEditorComponent::moveCaretTo (const CodeDocument::Position& newPos, con { caretPos = newPos; columnToTryToMaintain = -1; + bool selectionWasActive = isHighlightActive(); if (highlighting) { @@ -639,6 +641,9 @@ void CodeEditorComponent::moveCaretTo (const CodeDocument::Position& newPos, con updateCaretPosition(); scrollToKeepCaretOnScreen(); updateScrollBars(); + + if (appCommandManager != nullptr && selectionWasActive != isHighlightActive()) + appCommandManager->commandStatusChanged(); } void CodeEditorComponent::deselectAll() @@ -1142,6 +1147,11 @@ void CodeEditorComponent::newTransaction() pimpl->startTimer (600); } +void CodeEditorComponent::setCommandManager (ApplicationCommandManager* newManager) noexcept +{ + appCommandManager = newManager; +} + //============================================================================== Range CodeEditorComponent::getHighlightedRegion() const { @@ -1199,22 +1209,82 @@ void CodeEditorComponent::handleEscapeKey() } //============================================================================== -void CodeEditorComponent::addPopupMenuItems (PopupMenu& m, const MouseEvent*) +ApplicationCommandTarget* CodeEditorComponent::getNextCommandTarget() { - m.addItem (StandardApplicationCommandIDs::cut, TRANS("Cut")); - m.addItem (StandardApplicationCommandIDs::copy, TRANS("Copy"), ! getHighlightedRegion().isEmpty()); - m.addItem (StandardApplicationCommandIDs::paste, TRANS("Paste")); - m.addItem (StandardApplicationCommandIDs::del, TRANS("Delete")); - m.addSeparator(); - m.addItem (StandardApplicationCommandIDs::selectAll, TRANS("Select All")); - m.addSeparator(); - m.addItem (StandardApplicationCommandIDs::undo, TRANS("Undo"), document.getUndoManager().canUndo()); - m.addItem (StandardApplicationCommandIDs::redo, TRANS("Redo"), document.getUndoManager().canRedo()); + return findFirstTargetParentComponent(); } -void CodeEditorComponent::performPopupMenuAction (const int menuItemID) +void CodeEditorComponent::getAllCommands (Array & commands) { - switch (menuItemID) + const CommandID ids[] = { StandardApplicationCommandIDs::cut, + StandardApplicationCommandIDs::copy, + StandardApplicationCommandIDs::paste, + StandardApplicationCommandIDs::del, + StandardApplicationCommandIDs::selectAll, + StandardApplicationCommandIDs::undo, + StandardApplicationCommandIDs::redo }; + + commands.addArray (ids, numElementsInArray (ids)); +} + +void CodeEditorComponent::getCommandInfo (const CommandID commandID, ApplicationCommandInfo& result) +{ + const bool anythingSelected = isHighlightActive(); + + switch (commandID) + { + case StandardApplicationCommandIDs::cut: + result.setInfo (TRANS ("Cut"), TRANS ("Copies the currently selected text to the clipboard and deletes it."), "Editing", 0); + result.setActive (anythingSelected); + result.defaultKeypresses.add (KeyPress ('x', ModifierKeys::commandModifier, 0)); + break; + + case StandardApplicationCommandIDs::copy: + result.setInfo (TRANS ("Copy"), TRANS ("Copies the currently selected text to the clipboard."), "Editing", 0); + result.setActive (anythingSelected); + result.defaultKeypresses.add (KeyPress ('c', ModifierKeys::commandModifier, 0)); + break; + + case StandardApplicationCommandIDs::paste: + result.setInfo (TRANS ("Paste"), TRANS ("Inserts text from the clipboard."), "Editing", 0); + result.defaultKeypresses.add (KeyPress ('v', ModifierKeys::commandModifier, 0)); + break; + + case StandardApplicationCommandIDs::del: + result.setInfo (TRANS ("Delete"), TRANS ("Deletes any selected text."), "Editing", 0); + result.setActive (anythingSelected); + break; + + case StandardApplicationCommandIDs::selectAll: + result.setInfo (TRANS ("Select All"), TRANS ("Selects all the text in the editor."), "Editing", 0); + result.defaultKeypresses.add (KeyPress ('a', ModifierKeys::commandModifier, 0)); + break; + + case StandardApplicationCommandIDs::undo: + result.setInfo (TRANS ("Undo"), TRANS ("Undo"), "Editing", 0); + result.defaultKeypresses.add (KeyPress ('z', ModifierKeys::commandModifier, 0)); + result.setActive (document.getUndoManager().canUndo()); + break; + + case StandardApplicationCommandIDs::redo: + result.setInfo (TRANS ("Redo"), TRANS ("Redo"), "Editing", 0); + result.defaultKeypresses.add (KeyPress ('z', ModifierKeys::commandModifier | ModifierKeys::shiftModifier, 0)); + result.setActive (document.getUndoManager().canRedo()); + break; + + default: + break; + } +} + +bool CodeEditorComponent::perform (const InvocationInfo& info) +{ + return performCommand (info.commandID); +} + +bool CodeEditorComponent::performCommand (const int commandID) +{ + switch (commandID) { case StandardApplicationCommandIDs::cut: cutToClipboard(); break; case StandardApplicationCommandIDs::copy: copyToClipboard(); break; @@ -1223,8 +1293,29 @@ void CodeEditorComponent::performPopupMenuAction (const int menuItemID) case StandardApplicationCommandIDs::selectAll: selectAll(); break; case StandardApplicationCommandIDs::undo: undo(); break; case StandardApplicationCommandIDs::redo: redo(); break; - default: break; + default: return false; } + + return true; +} + +//============================================================================== +void CodeEditorComponent::addPopupMenuItems (PopupMenu& m, const MouseEvent*) +{ + m.addItem (StandardApplicationCommandIDs::cut, TRANS ("Cut")); + m.addItem (StandardApplicationCommandIDs::copy, TRANS ("Copy"), ! getHighlightedRegion().isEmpty()); + m.addItem (StandardApplicationCommandIDs::paste, TRANS ("Paste")); + m.addItem (StandardApplicationCommandIDs::del, TRANS ("Delete")); + m.addSeparator(); + m.addItem (StandardApplicationCommandIDs::selectAll, TRANS ("Select All")); + m.addSeparator(); + m.addItem (StandardApplicationCommandIDs::undo, TRANS ("Undo"), document.getUndoManager().canUndo()); + m.addItem (StandardApplicationCommandIDs::redo, TRANS ("Redo"), document.getUndoManager().canRedo()); +} + +void CodeEditorComponent::performPopupMenuAction (const int menuItemID) +{ + performCommand (menuItemID); } static void codeEditorMenuCallback (int menuResult, CodeEditorComponent* editor) diff --git a/modules/juce_gui_extra/code_editor/juce_CodeEditorComponent.h b/modules/juce_gui_extra/code_editor/juce_CodeEditorComponent.h index ba934fd713..a686816a98 100644 --- a/modules/juce_gui_extra/code_editor/juce_CodeEditorComponent.h +++ b/modules/juce_gui_extra/code_editor/juce_CodeEditorComponent.h @@ -37,6 +37,7 @@ class CodeTokeniser; files. */ class JUCE_API CodeEditorComponent : public Component, + public ApplicationCommandTarget, public TextInputTarget { public: @@ -300,6 +301,15 @@ public: */ virtual void performPopupMenuAction (int menuItemID); + /** Specifies a commmand-manager which the editor will notify whenever the state + of any of its commands changes. + If you're making use of the editor's ApplicationCommandTarget interface, then + you should also use this to tell it which command manager it should use. Make + sure that the manager does not go out of scope while the editor is using it. You + can pass a nullptr here to disable this. + */ + void setCommandManager (ApplicationCommandManager* newManager) noexcept; + //============================================================================== /** @internal */ void paint (Graphics&); @@ -325,6 +335,14 @@ public: bool isTextInputActive() const; /** @internal */ void setTemporaryUnderlining (const Array >&); + /** @internal */ + ApplicationCommandTarget* getNextCommandTarget(); + /** @internal */ + void getAllCommands (Array&); + /** @internal */ + void getCommandInfo (CommandID, ApplicationCommandInfo&); + /** @internal */ + bool perform (const InvocationInfo&); private: //============================================================================== @@ -342,6 +360,7 @@ private: ScopedPointer caret; ScrollBar verticalScrollBar, horizontalScrollBar; + ApplicationCommandManager* appCommandManager; class Pimpl; friend class Pimpl; @@ -375,13 +394,13 @@ private: OwnedArray cachedIterators; void clearCachedIterators (int firstLineToBeInvalid); void updateCachedIterators (int maxLineNum); - void getIteratorForPosition (int position, CodeDocument::Iterator& result); + void getIteratorForPosition (int position, CodeDocument::Iterator&); void moveLineDelta (int delta, bool selecting); int getGutterSize() const noexcept; //============================================================================== - void insertText (const String& textToInsert); + void insertText (const String&); void updateCaretPosition(); void updateScrollBars(); void scrollToLineInternal (int line); @@ -390,6 +409,7 @@ private: void cut(); void indentSelectedLines (int spacesToAdd); bool skipBackwardsToPreviousTab(); + bool performCommand (int); int indexToColumn (int line, int index) const noexcept; int columnToIndex (int line, int column) const noexcept;