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.

233 lines
8.6KB

  1. /*
  2. ==============================================================================
  3. This file is part of the JUCE 6 technical preview.
  4. Copyright (c) 2020 - Raw Material Software Limited
  5. You may use this code under the terms of the GPL v3
  6. (see www.gnu.org/licenses).
  7. For this technical preview, this file is not subject to commercial licensing.
  8. JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
  9. EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
  10. DISCLAIMED.
  11. ==============================================================================
  12. */
  13. #pragma once
  14. #include "jucer_DocumentEditorComponent.h"
  15. //==============================================================================
  16. class SourceCodeDocument : public OpenDocumentManager::Document
  17. {
  18. public:
  19. SourceCodeDocument (Project*, const File&);
  20. bool loadedOk() const override { return true; }
  21. bool isForFile (const File& file) const override { return getFile() == file; }
  22. bool isForNode (const ValueTree&) const override { return false; }
  23. bool refersToProject (Project& p) const override { return project == &p; }
  24. Project* getProject() const override { return project; }
  25. String getName() const override { return getFile().getFileName(); }
  26. String getType() const override { return getFile().getFileExtension() + " file"; }
  27. File getFile() const override { return modDetector.getFile(); }
  28. bool needsSaving() const override { return codeDoc != nullptr && codeDoc->hasChangedSinceSavePoint(); }
  29. bool hasFileBeenModifiedExternally() override { return modDetector.hasBeenModified(); }
  30. void fileHasBeenRenamed (const File& newFile) override { modDetector.fileHasBeenRenamed (newFile); }
  31. String getState() const override { return lastState != nullptr ? lastState->toString() : String(); }
  32. void restoreState (const String& state) override { lastState.reset (new CodeEditorComponent::State (state)); }
  33. File getCounterpartFile() const override
  34. {
  35. auto file = getFile();
  36. if (file.hasFileExtension (sourceFileExtensions))
  37. {
  38. static const char* extensions[] = { "h", "hpp", "hxx", "hh", nullptr };
  39. return findCounterpart (file, extensions);
  40. }
  41. if (file.hasFileExtension (headerFileExtensions))
  42. {
  43. static const char* extensions[] = { "cpp", "mm", "cc", "cxx", "c", "m", nullptr };
  44. return findCounterpart (file, extensions);
  45. }
  46. return {};
  47. }
  48. static File findCounterpart (const File& file, const char** extensions)
  49. {
  50. while (*extensions != nullptr)
  51. {
  52. auto f = file.withFileExtension (*extensions++);
  53. if (f.existsAsFile())
  54. return f;
  55. }
  56. return {};
  57. }
  58. void reloadFromFile() override;
  59. bool save() override;
  60. bool saveAs() override;
  61. Component* createEditor() override;
  62. Component* createViewer() override { return createEditor(); }
  63. void updateLastState (CodeEditorComponent&);
  64. void applyLastState (CodeEditorComponent&) const;
  65. CodeDocument& getCodeDocument();
  66. //==============================================================================
  67. struct Type : public OpenDocumentManager::DocumentType
  68. {
  69. bool canOpenFile (const File& file) override
  70. {
  71. if (file.hasFileExtension (sourceOrHeaderFileExtensions)
  72. || file.hasFileExtension ("txt;inc;tcc;xml;plist;rtf;html;htm;php;py;rb;cs"))
  73. return true;
  74. MemoryBlock mb;
  75. if (file.loadFileAsData (mb)
  76. && seemsToBeText (static_cast<const char*> (mb.getData()), (int) mb.getSize())
  77. && ! file.hasFileExtension ("svg"))
  78. return true;
  79. return false;
  80. }
  81. static bool seemsToBeText (const char* const chars, const int num) noexcept
  82. {
  83. for (int i = 0; i < num; ++i)
  84. {
  85. const char c = chars[i];
  86. if ((c < 32 && c != '\t' && c != '\r' && c != '\n') || chars[i] > 126)
  87. return false;
  88. }
  89. return true;
  90. }
  91. Document* openFile (Project* p, const File& file) override { return new SourceCodeDocument (p, file); }
  92. };
  93. protected:
  94. FileModificationDetector modDetector;
  95. std::unique_ptr<CodeDocument> codeDoc;
  96. Project* project;
  97. std::unique_ptr<CodeEditorComponent::State> lastState;
  98. void reloadInternal();
  99. };
  100. class GenericCodeEditorComponent;
  101. //==============================================================================
  102. class SourceCodeEditor : public DocumentEditorComponent,
  103. private ValueTree::Listener,
  104. private CodeDocument::Listener
  105. {
  106. public:
  107. SourceCodeEditor (OpenDocumentManager::Document*, CodeDocument&);
  108. SourceCodeEditor (OpenDocumentManager::Document*, GenericCodeEditorComponent*);
  109. ~SourceCodeEditor() override;
  110. void scrollToKeepRangeOnScreen (Range<int> range);
  111. void highlight (Range<int> range, bool cursorAtStart);
  112. std::unique_ptr<GenericCodeEditorComponent> editor;
  113. private:
  114. void resized() override;
  115. void lookAndFeelChanged() override;
  116. void valueTreePropertyChanged (ValueTree&, const Identifier&) override;
  117. void valueTreeChildAdded (ValueTree&, ValueTree&) override;
  118. void valueTreeChildRemoved (ValueTree&, ValueTree&, int) override;
  119. void valueTreeChildOrderChanged (ValueTree&, int, int) override;
  120. void valueTreeParentChanged (ValueTree&) override;
  121. void valueTreeRedirected (ValueTree&) override;
  122. void codeDocumentTextInserted (const String&, int) override;
  123. void codeDocumentTextDeleted (int, int) override;
  124. void setEditor (GenericCodeEditorComponent*);
  125. void updateColourScheme();
  126. void checkSaveState();
  127. JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (SourceCodeEditor)
  128. };
  129. //==============================================================================
  130. class GenericCodeEditorComponent : public CodeEditorComponent
  131. {
  132. public:
  133. GenericCodeEditorComponent (const File&, CodeDocument&, CodeTokeniser*);
  134. ~GenericCodeEditorComponent() override;
  135. void addPopupMenuItems (PopupMenu&, const MouseEvent*) override;
  136. void performPopupMenuAction (int menuItemID) override;
  137. void getAllCommands (Array<CommandID>&) override;
  138. void getCommandInfo (CommandID, ApplicationCommandInfo&) override;
  139. bool perform (const InvocationInfo&) override;
  140. void showFindPanel();
  141. void hideFindPanel();
  142. void findSelection();
  143. void findNext (bool forwards, bool skipCurrentSelection);
  144. void handleEscapeKey() override;
  145. void editorViewportPositionChanged() override;
  146. void resized() override;
  147. static String getSearchString() { return getAppSettings().getGlobalProperties().getValue ("searchString"); }
  148. static void setSearchString (const String& s) { getAppSettings().getGlobalProperties().setValue ("searchString", s); }
  149. static bool isCaseSensitiveSearch() { return getAppSettings().getGlobalProperties().getBoolValue ("searchCaseSensitive"); }
  150. static void setCaseSensitiveSearch (bool b) { getAppSettings().getGlobalProperties().setValue ("searchCaseSensitive", b); }
  151. struct Listener
  152. {
  153. virtual ~Listener() {}
  154. virtual void codeEditorViewportMoved (CodeEditorComponent&) = 0;
  155. };
  156. void addListener (Listener* listener);
  157. void removeListener (Listener* listener);
  158. private:
  159. File file;
  160. class FindPanel;
  161. std::unique_ptr<FindPanel> findPanel;
  162. ListenerList<Listener> listeners;
  163. JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (GenericCodeEditorComponent)
  164. };
  165. //==============================================================================
  166. class CppCodeEditorComponent : public GenericCodeEditorComponent
  167. {
  168. public:
  169. CppCodeEditorComponent (const File&, CodeDocument&);
  170. ~CppCodeEditorComponent() override;
  171. void addPopupMenuItems (PopupMenu&, const MouseEvent*) override;
  172. void performPopupMenuAction (int menuItemID) override;
  173. void handleReturnKey() override;
  174. void insertTextAtCaret (const String& newText) override;
  175. private:
  176. void insertComponentClass();
  177. JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (CppCodeEditorComponent)
  178. };