mirror of
https://github.com/juce-framework/JUCE.git
synced 2026-01-10 23:44:24 +00:00
Projucer: Added a simple sign-in form, added notification tray for project messages, general refactoring
This commit is contained in:
parent
6610a1959f
commit
fba0295a44
69 changed files with 4915 additions and 2205 deletions
|
|
@ -100,8 +100,8 @@ OBJECTS_APP := \
|
|||
$(JUCE_OBJDIR)/jucer_CompileEngineClient_aee8c99c.o \
|
||||
$(JUCE_OBJDIR)/jucer_CompileEngineServer_5d8914.o \
|
||||
$(JUCE_OBJDIR)/jucer_DownloadCompileEngineThread_19bb4bb3.o \
|
||||
$(JUCE_OBJDIR)/jucer_Modules_e20cbd10.o \
|
||||
$(JUCE_OBJDIR)/jucer_HeaderComponent_1ebf72ba.o \
|
||||
$(JUCE_OBJDIR)/jucer_Module_3f7666a5.o \
|
||||
$(JUCE_OBJDIR)/jucer_Project_c131864a.o \
|
||||
$(JUCE_OBJDIR)/jucer_ProjectExporter_cf377b25.o \
|
||||
$(JUCE_OBJDIR)/jucer_ProjectSaver_4276639b.o \
|
||||
|
|
@ -302,16 +302,16 @@ $(JUCE_OBJDIR)/jucer_DownloadCompileEngineThread_19bb4bb3.o: ../../Source/LiveBu
|
|||
@echo "Compiling jucer_DownloadCompileEngineThread.cpp"
|
||||
$(V_AT)$(CXX) $(JUCE_CXXFLAGS) $(JUCE_CPPFLAGS_APP) $(JUCE_CFLAGS_APP) -o "$@" -c "$<"
|
||||
|
||||
$(JUCE_OBJDIR)/jucer_Modules_e20cbd10.o: ../../Source/Project/Modules/jucer_Modules.cpp
|
||||
-$(V_AT)mkdir -p $(JUCE_OBJDIR)
|
||||
@echo "Compiling jucer_Modules.cpp"
|
||||
$(V_AT)$(CXX) $(JUCE_CXXFLAGS) $(JUCE_CPPFLAGS_APP) $(JUCE_CFLAGS_APP) -o "$@" -c "$<"
|
||||
|
||||
$(JUCE_OBJDIR)/jucer_HeaderComponent_1ebf72ba.o: ../../Source/Project/UI/jucer_HeaderComponent.cpp
|
||||
-$(V_AT)mkdir -p $(JUCE_OBJDIR)
|
||||
@echo "Compiling jucer_HeaderComponent.cpp"
|
||||
$(V_AT)$(CXX) $(JUCE_CXXFLAGS) $(JUCE_CPPFLAGS_APP) $(JUCE_CFLAGS_APP) -o "$@" -c "$<"
|
||||
|
||||
$(JUCE_OBJDIR)/jucer_Module_3f7666a5.o: ../../Source/Project/jucer_Module.cpp
|
||||
-$(V_AT)mkdir -p $(JUCE_OBJDIR)
|
||||
@echo "Compiling jucer_Module.cpp"
|
||||
$(V_AT)$(CXX) $(JUCE_CXXFLAGS) $(JUCE_CPPFLAGS_APP) $(JUCE_CFLAGS_APP) -o "$@" -c "$<"
|
||||
|
||||
$(JUCE_OBJDIR)/jucer_Project_c131864a.o: ../../Source/Project/jucer_Project.cpp
|
||||
-$(V_AT)mkdir -p $(JUCE_OBJDIR)
|
||||
@echo "Compiling jucer_Project.cpp"
|
||||
|
|
|
|||
|
|
@ -205,14 +205,14 @@
|
|||
isa = PBXBuildFile;
|
||||
fileRef = ADA538034910F52FDD2DC88D;
|
||||
};
|
||||
0E783907C6214ADD59EC95DC = {
|
||||
isa = PBXBuildFile;
|
||||
fileRef = F58B23995765C9FDBE28F871;
|
||||
};
|
||||
05A08E366EBF8D650974E695 = {
|
||||
isa = PBXBuildFile;
|
||||
fileRef = 516D6D7C564DD5DF5C15CB06;
|
||||
};
|
||||
3FCA61C401007B243E2E9035 = {
|
||||
isa = PBXBuildFile;
|
||||
fileRef = F797071D88542C813CF7222A;
|
||||
};
|
||||
30B921C38DCEE787B294B746 = {
|
||||
isa = PBXBuildFile;
|
||||
fileRef = BAC43B20E14A340CCF14119C;
|
||||
|
|
@ -548,13 +548,6 @@
|
|||
path = "../../Source/Utility/PIPs/jucer_PIPGenerator.cpp";
|
||||
sourceTree = "SOURCE_ROOT";
|
||||
};
|
||||
194457D806A26E793584AC0C = {
|
||||
isa = PBXFileReference;
|
||||
lastKnownFileType = file.svg;
|
||||
name = "huckleberry_icon.svg";
|
||||
path = "../../Source/BinaryData/Icons/huckleberry_icon.svg";
|
||||
sourceTree = "SOURCE_ROOT";
|
||||
};
|
||||
1B0F18E1D96F727C062B05FA = {
|
||||
isa = PBXFileReference;
|
||||
lastKnownFileType = sourcecode.cpp.cpp;
|
||||
|
|
@ -660,6 +653,13 @@
|
|||
path = "../../Source/LiveBuildEngine/jucer_ActivityList.h";
|
||||
sourceTree = "SOURCE_ROOT";
|
||||
};
|
||||
247768B490B9D759DDA79359 = {
|
||||
isa = PBXFileReference;
|
||||
lastKnownFileType = sourcecode.c.h;
|
||||
name = "jucer_UserAvatarComponent.h";
|
||||
path = "../../Source/Project/UI/jucer_UserAvatarComponent.h";
|
||||
sourceTree = "SOURCE_ROOT";
|
||||
};
|
||||
24EB4C2412821B8019D6F754 = {
|
||||
isa = PBXFileReference;
|
||||
lastKnownFileType = sourcecode.cpp.cpp;
|
||||
|
|
@ -709,6 +709,13 @@
|
|||
path = "../../Source/Application/jucer_CommandLine.h";
|
||||
sourceTree = "SOURCE_ROOT";
|
||||
};
|
||||
2F0A7CA808B2FCCC9ED68992 = {
|
||||
isa = PBXFileReference;
|
||||
lastKnownFileType = sourcecode.c.h;
|
||||
name = "jucer_LicenseQueryThread.h";
|
||||
path = "../../Source/Application/UserAccount/jucer_LicenseQueryThread.h";
|
||||
sourceTree = "SOURCE_ROOT";
|
||||
};
|
||||
2F373F97E30AC1A0BFC1FC61 = {
|
||||
isa = PBXFileReference;
|
||||
lastKnownFileType = sourcecode.c.h;
|
||||
|
|
@ -1094,6 +1101,13 @@
|
|||
path = "../../Source/ComponentEditor/Properties/jucer_ComponentTextProperty.h";
|
||||
sourceTree = "SOURCE_ROOT";
|
||||
};
|
||||
582F659B801F656C2B7C51B1 = {
|
||||
isa = PBXFileReference;
|
||||
lastKnownFileType = sourcecode.c.h;
|
||||
name = "jucer_Modules.h";
|
||||
path = "../../Source/Project/Modules/jucer_Modules.h";
|
||||
sourceTree = "SOURCE_ROOT";
|
||||
};
|
||||
5867DC4E39DF8539B54C0D59 = {
|
||||
isa = PBXFileReference;
|
||||
lastKnownFileType = sourcecode.cpp.objcpp;
|
||||
|
|
@ -1304,13 +1318,6 @@
|
|||
path = "../../Source/ComponentEditor/UI/jucer_RelativePositionedRectangle.h";
|
||||
sourceTree = "SOURCE_ROOT";
|
||||
};
|
||||
7211101FFA28400ADBB1D47A = {
|
||||
isa = PBXFileReference;
|
||||
lastKnownFileType = sourcecode.c.h;
|
||||
name = "jucer_Module.h";
|
||||
path = "../../Source/Project/jucer_Module.h";
|
||||
sourceTree = "SOURCE_ROOT";
|
||||
};
|
||||
728FE25157E9874D50BBECB2 = {
|
||||
isa = PBXFileReference;
|
||||
lastKnownFileType = wrapper.framework;
|
||||
|
|
@ -1584,6 +1591,13 @@
|
|||
path = "../../Source/Project/UI/jucer_ProjectContentComponent.h";
|
||||
sourceTree = "SOURCE_ROOT";
|
||||
};
|
||||
94146B40B41BF0AACF4359DD = {
|
||||
isa = PBXFileReference;
|
||||
lastKnownFileType = sourcecode.c.h;
|
||||
name = "jucer_LicenseState.h";
|
||||
path = "../../Source/Application/UserAccount/jucer_LicenseState.h";
|
||||
sourceTree = "SOURCE_ROOT";
|
||||
};
|
||||
951128CA33CCDEF570436B1C = {
|
||||
isa = PBXFileReference;
|
||||
lastKnownFileType = file.icns;
|
||||
|
|
@ -1899,6 +1913,13 @@
|
|||
path = "../../Source/Utility/Helpers/jucer_FileHelpers.cpp";
|
||||
sourceTree = "SOURCE_ROOT";
|
||||
};
|
||||
B6444A4A8DFD6828FF6BD1CB = {
|
||||
isa = PBXFileReference;
|
||||
lastKnownFileType = sourcecode.c.h;
|
||||
name = "jucer_LoginFormComponent.h";
|
||||
path = "../../Source/Application/UserAccount/jucer_LoginFormComponent.h";
|
||||
sourceTree = "SOURCE_ROOT";
|
||||
};
|
||||
B6F2905330EA5C560D527209 = {
|
||||
isa = PBXFileReference;
|
||||
lastKnownFileType = file;
|
||||
|
|
@ -2102,6 +2123,13 @@
|
|||
path = "../../Source/LiveBuildEngine/UI/jucer_BuildTabStatusComponent.h";
|
||||
sourceTree = "SOURCE_ROOT";
|
||||
};
|
||||
CD267A28C16C4E79EB749005 = {
|
||||
isa = PBXFileReference;
|
||||
lastKnownFileType = file.svg;
|
||||
name = "gpl_logo.svg";
|
||||
path = "../../Source/BinaryData/Icons/gpl_logo.svg";
|
||||
sourceTree = "SOURCE_ROOT";
|
||||
};
|
||||
CF6C8BD0DA3D8CD4E99EBADA = {
|
||||
isa = PBXFileReference;
|
||||
lastKnownFileType = wrapper.framework;
|
||||
|
|
@ -2438,6 +2466,13 @@
|
|||
path = "../../Source/Utility/Helpers/jucer_CodeHelpers.cpp";
|
||||
sourceTree = "SOURCE_ROOT";
|
||||
};
|
||||
F30DF63DBEFA4BEEF7C369FC = {
|
||||
isa = PBXFileReference;
|
||||
lastKnownFileType = sourcecode.c.h;
|
||||
name = "jucer_LicenseController.h";
|
||||
path = "../../Source/Application/UserAccount/jucer_LicenseController.h";
|
||||
sourceTree = "SOURCE_ROOT";
|
||||
};
|
||||
F313EE01ECE306DB2CFE011D = {
|
||||
isa = PBXFileReference;
|
||||
lastKnownFileType = file.in;
|
||||
|
|
@ -2459,6 +2494,13 @@
|
|||
path = "../../Source/ComponentEditor/Properties/jucer_ComponentBooleanProperty.h";
|
||||
sourceTree = "SOURCE_ROOT";
|
||||
};
|
||||
F58B23995765C9FDBE28F871 = {
|
||||
isa = PBXFileReference;
|
||||
lastKnownFileType = sourcecode.cpp.cpp;
|
||||
name = "jucer_Modules.cpp";
|
||||
path = "../../Source/Project/Modules/jucer_Modules.cpp";
|
||||
sourceTree = "SOURCE_ROOT";
|
||||
};
|
||||
F5DD97B45B8EA60C1ED0DD80 = {
|
||||
isa = PBXFileReference;
|
||||
lastKnownFileType = sourcecode.cpp.cpp;
|
||||
|
|
@ -2466,11 +2508,11 @@
|
|||
path = "../../Source/Settings/jucer_StoredSettings.cpp";
|
||||
sourceTree = "SOURCE_ROOT";
|
||||
};
|
||||
F797071D88542C813CF7222A = {
|
||||
F63F46CA0A51C679867855A7 = {
|
||||
isa = PBXFileReference;
|
||||
lastKnownFileType = sourcecode.cpp.cpp;
|
||||
name = "jucer_Module.cpp";
|
||||
path = "../../Source/Project/jucer_Module.cpp";
|
||||
lastKnownFileType = sourcecode.c.h;
|
||||
name = "jucer_ProjectMessagesComponent.h";
|
||||
path = "../../Source/Project/UI/jucer_ProjectMessagesComponent.h";
|
||||
sourceTree = "SOURCE_ROOT";
|
||||
};
|
||||
F7C74E934C954F6F1A3BE4F9 = {
|
||||
|
|
@ -2501,6 +2543,13 @@
|
|||
path = "../../Source/CodeEditor/jucer_OpenDocumentManager.cpp";
|
||||
sourceTree = "SOURCE_ROOT";
|
||||
};
|
||||
F9A363BFBB6B1143C2E967C3 = {
|
||||
isa = PBXFileReference;
|
||||
lastKnownFileType = sourcecode.c.h;
|
||||
name = "jucer_ModuleDescription.h";
|
||||
path = "../../Source/Project/Modules/jucer_ModuleDescription.h";
|
||||
sourceTree = "SOURCE_ROOT";
|
||||
};
|
||||
FA790C59A304579F660F112F = {
|
||||
isa = PBXFileReference;
|
||||
lastKnownFileType = sourcecode.c.h;
|
||||
|
|
@ -2522,6 +2571,13 @@
|
|||
path = "../../Source/ComponentEditor/Properties/jucer_ComponentColourProperty.h";
|
||||
sourceTree = "SOURCE_ROOT";
|
||||
};
|
||||
FDABEE6B64546586368A4729 = {
|
||||
isa = PBXFileReference;
|
||||
lastKnownFileType = sourcecode.c.h;
|
||||
name = "jucer_AvailableModulesList.h";
|
||||
path = "../../Source/Project/Modules/jucer_AvailableModulesList.h";
|
||||
sourceTree = "SOURCE_ROOT";
|
||||
};
|
||||
FE20FE5805A02A4843048200 = {
|
||||
isa = PBXFileReference;
|
||||
lastKnownFileType = sourcecode.c.h;
|
||||
|
|
@ -2550,6 +2606,17 @@
|
|||
path = "../../Source/ComponentEditor/UI/jucer_PaintRoutinePanel.cpp";
|
||||
sourceTree = "SOURCE_ROOT";
|
||||
};
|
||||
9D43579A76E23FBCE6B36333 = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
F30DF63DBEFA4BEEF7C369FC,
|
||||
2F0A7CA808B2FCCC9ED68992,
|
||||
94146B40B41BF0AACF4359DD,
|
||||
B6444A4A8DFD6828FF6BD1CB,
|
||||
);
|
||||
name = UserAccount;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
EB1D55A76652399EB81CC1F0 = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
|
|
@ -2568,6 +2635,7 @@
|
|||
BC67FD952A6F210A11A1ECB8 = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
9D43579A76E23FBCE6B36333,
|
||||
EB1D55A76652399EB81CC1F0,
|
||||
7CA44FF0BA319517C6E39651,
|
||||
EE690110171E1648FF2118B8,
|
||||
|
|
@ -2606,7 +2674,7 @@
|
|||
69B478C992FA0B8C885946A6,
|
||||
EAC1731150A7F79D59BAA0B6,
|
||||
8F4D281E98808204E2846A7D,
|
||||
194457D806A26E793584AC0C,
|
||||
CD267A28C16C4E79EB749005,
|
||||
432EC251A122071809471804,
|
||||
B83C9BD89F31EA9E5E12A3C6,
|
||||
8FEF6F5EA676B824C021EB6F,
|
||||
|
|
@ -2865,6 +2933,17 @@
|
|||
name = LiveBuildEngine;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
5108FDF7F62E617332FB13B0 = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
FDABEE6B64546586368A4729,
|
||||
F9A363BFBB6B1143C2E967C3,
|
||||
F58B23995765C9FDBE28F871,
|
||||
582F659B801F656C2B7C51B1,
|
||||
);
|
||||
name = Modules;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
236D186F5A6536C59D6E751C = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
|
|
@ -2891,6 +2970,8 @@
|
|||
B3528C08B84CBC950252EA69,
|
||||
1B0F18E1D96F727C062B05FA,
|
||||
92A66A8BD87F98EB6B4FB6D0,
|
||||
F63F46CA0A51C679867855A7,
|
||||
247768B490B9D759DDA79359,
|
||||
);
|
||||
name = UI;
|
||||
sourceTree = "<group>";
|
||||
|
|
@ -2898,9 +2979,8 @@
|
|||
89E9055A179B4C2019B4E1AE = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
5108FDF7F62E617332FB13B0,
|
||||
EBC037ECAAC8156B8B19DC69,
|
||||
F797071D88542C813CF7222A,
|
||||
7211101FFA28400ADBB1D47A,
|
||||
BAC43B20E14A340CCF14119C,
|
||||
BF3CEF080FA013E2778DCE90,
|
||||
);
|
||||
|
|
@ -3424,8 +3504,8 @@
|
|||
D25EBE02B55DB244BE0D5635,
|
||||
85E7FCB0516EFF853FA7B380,
|
||||
CC6C4D351BA9B473E5F95791,
|
||||
0E783907C6214ADD59EC95DC,
|
||||
05A08E366EBF8D650974E695,
|
||||
3FCA61C401007B243E2E9035,
|
||||
30B921C38DCEE787B294B746,
|
||||
244567D3AE2E417A8CB2B95E,
|
||||
26D6AEA321E80ABCC3CCCCD1,
|
||||
|
|
|
|||
|
|
@ -214,11 +214,11 @@
|
|||
<ClCompile Include="..\..\Source\LiveBuildEngine\jucer_CompileEngineClient.cpp"/>
|
||||
<ClCompile Include="..\..\Source\LiveBuildEngine\jucer_CompileEngineServer.cpp"/>
|
||||
<ClCompile Include="..\..\Source\LiveBuildEngine\jucer_DownloadCompileEngineThread.cpp"/>
|
||||
<ClCompile Include="..\..\Source\Project\Modules\jucer_Modules.cpp"/>
|
||||
<ClCompile Include="..\..\Source\Project\UI\jucer_HeaderComponent.cpp"/>
|
||||
<ClCompile Include="..\..\Source\Project\UI\jucer_ProjectContentComponent.cpp">
|
||||
<ExcludedFromBuild>true</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\Source\Project\jucer_Module.cpp"/>
|
||||
<ClCompile Include="..\..\Source\Project\jucer_Project.cpp"/>
|
||||
<ClCompile Include="..\..\Source\ProjectSaving\jucer_ProjectExporter.cpp"/>
|
||||
<ClCompile Include="..\..\Source\ProjectSaving\jucer_ProjectSaver.cpp"/>
|
||||
|
|
@ -1483,6 +1483,10 @@
|
|||
<ClCompile Include="..\..\JuceLibraryCode\include_juce_gui_extra.cpp"/>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="..\..\Source\Application\UserAccount\jucer_LicenseController.h"/>
|
||||
<ClInclude Include="..\..\Source\Application\UserAccount\jucer_LicenseQueryThread.h"/>
|
||||
<ClInclude Include="..\..\Source\Application\UserAccount\jucer_LicenseState.h"/>
|
||||
<ClInclude Include="..\..\Source\Application\UserAccount\jucer_LoginFormComponent.h"/>
|
||||
<ClInclude Include="..\..\Source\Application\Windows\jucer_AboutWindowComponent.h"/>
|
||||
<ClInclude Include="..\..\Source\Application\Windows\jucer_EditorColourSchemeWindowComponent.h"/>
|
||||
<ClInclude Include="..\..\Source\Application\Windows\jucer_FloatingToolWindow.h"/>
|
||||
|
|
@ -1603,6 +1607,9 @@
|
|||
<ClInclude Include="..\..\Source\LiveBuildEngine\jucer_MessageIDs.h"/>
|
||||
<ClInclude Include="..\..\Source\LiveBuildEngine\jucer_ProjectBuildInfo.h"/>
|
||||
<ClInclude Include="..\..\Source\LiveBuildEngine\jucer_SourceCodeRange.h"/>
|
||||
<ClInclude Include="..\..\Source\Project\Modules\jucer_AvailableModulesList.h"/>
|
||||
<ClInclude Include="..\..\Source\Project\Modules\jucer_ModuleDescription.h"/>
|
||||
<ClInclude Include="..\..\Source\Project\Modules\jucer_Modules.h"/>
|
||||
<ClInclude Include="..\..\Source\Project\UI\Sidebar\jucer_ExporterTreeItems.h"/>
|
||||
<ClInclude Include="..\..\Source\Project\UI\Sidebar\jucer_FileTreeItems.h"/>
|
||||
<ClInclude Include="..\..\Source\Project\UI\Sidebar\jucer_LiveBuildTab.h"/>
|
||||
|
|
@ -1616,7 +1623,8 @@
|
|||
<ClInclude Include="..\..\Source\Project\UI\jucer_HeaderComponent.h"/>
|
||||
<ClInclude Include="..\..\Source\Project\UI\jucer_ModulesInformationComponent.h"/>
|
||||
<ClInclude Include="..\..\Source\Project\UI\jucer_ProjectContentComponent.h"/>
|
||||
<ClInclude Include="..\..\Source\Project\jucer_Module.h"/>
|
||||
<ClInclude Include="..\..\Source\Project\UI\jucer_ProjectMessagesComponent.h"/>
|
||||
<ClInclude Include="..\..\Source\Project\UI\jucer_UserAvatarComponent.h"/>
|
||||
<ClInclude Include="..\..\Source\Project\jucer_Project.h"/>
|
||||
<ClInclude Include="..\..\Source\ProjectSaving\jucer_ProjectExport_Android.h"/>
|
||||
<ClInclude Include="..\..\Source\ProjectSaving\jucer_ProjectExport_CLion.h"/>
|
||||
|
|
@ -2105,7 +2113,7 @@
|
|||
<None Include="..\..\Source\BinaryData\Icons\export_linux.svg"/>
|
||||
<None Include="..\..\Source\BinaryData\Icons\export_visualStudio.svg"/>
|
||||
<None Include="..\..\Source\BinaryData\Icons\export_xcode.svg"/>
|
||||
<None Include="..\..\Source\BinaryData\Icons\huckleberry_icon.svg"/>
|
||||
<None Include="..\..\Source\BinaryData\Icons\gpl_logo.svg"/>
|
||||
<None Include="..\..\Source\BinaryData\Icons\juce-logo-with-text.svg"/>
|
||||
<None Include="..\..\Source\BinaryData\Icons\juce_icon.png"/>
|
||||
<None Include="..\..\Source\BinaryData\Icons\wizard_AnimatedApp.svg"/>
|
||||
|
|
|
|||
|
|
@ -2,6 +2,9 @@
|
|||
|
||||
<Project ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup>
|
||||
<Filter Include="Projucer\Application\UserAccount">
|
||||
<UniqueIdentifier>{DA27985D-8427-CE70-CA06-EAF7009CCC60}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="Projucer\Application\Windows">
|
||||
<UniqueIdentifier>{DC7E18A5-E854-3D99-627F-AAA88246B712}</UniqueIdentifier>
|
||||
</Filter>
|
||||
|
|
@ -47,6 +50,9 @@
|
|||
<Filter Include="Projucer\LiveBuildEngine">
|
||||
<UniqueIdentifier>{0A3B9446-F50B-3D4E-230F-7ED493541A07}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="Projucer\Project\Modules">
|
||||
<UniqueIdentifier>{F5C79836-30DE-9DC7-9392-DAAB3F04C18E}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="Projucer\Project\UI\Sidebar">
|
||||
<UniqueIdentifier>{A0A94AE6-B447-151A-D0DA-FAE9B5410EBF}</UniqueIdentifier>
|
||||
</Filter>
|
||||
|
|
@ -448,15 +454,15 @@
|
|||
<ClCompile Include="..\..\Source\LiveBuildEngine\jucer_DownloadCompileEngineThread.cpp">
|
||||
<Filter>Projucer\LiveBuildEngine</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\Source\Project\Modules\jucer_Modules.cpp">
|
||||
<Filter>Projucer\Project\Modules</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\Source\Project\UI\jucer_HeaderComponent.cpp">
|
||||
<Filter>Projucer\Project\UI</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\Source\Project\UI\jucer_ProjectContentComponent.cpp">
|
||||
<Filter>Projucer\Project\UI</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\Source\Project\jucer_Module.cpp">
|
||||
<Filter>Projucer\Project</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\Source\Project\jucer_Project.cpp">
|
||||
<Filter>Projucer\Project</Filter>
|
||||
</ClCompile>
|
||||
|
|
@ -1857,6 +1863,18 @@
|
|||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="..\..\Source\Application\UserAccount\jucer_LicenseController.h">
|
||||
<Filter>Projucer\Application\UserAccount</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\Source\Application\UserAccount\jucer_LicenseQueryThread.h">
|
||||
<Filter>Projucer\Application\UserAccount</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\Source\Application\UserAccount\jucer_LicenseState.h">
|
||||
<Filter>Projucer\Application\UserAccount</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\Source\Application\UserAccount\jucer_LoginFormComponent.h">
|
||||
<Filter>Projucer\Application\UserAccount</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\Source\Application\Windows\jucer_AboutWindowComponent.h">
|
||||
<Filter>Projucer\Application\Windows</Filter>
|
||||
</ClInclude>
|
||||
|
|
@ -2217,6 +2235,15 @@
|
|||
<ClInclude Include="..\..\Source\LiveBuildEngine\jucer_SourceCodeRange.h">
|
||||
<Filter>Projucer\LiveBuildEngine</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\Source\Project\Modules\jucer_AvailableModulesList.h">
|
||||
<Filter>Projucer\Project\Modules</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\Source\Project\Modules\jucer_ModuleDescription.h">
|
||||
<Filter>Projucer\Project\Modules</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\Source\Project\Modules\jucer_Modules.h">
|
||||
<Filter>Projucer\Project\Modules</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\Source\Project\UI\Sidebar\jucer_ExporterTreeItems.h">
|
||||
<Filter>Projucer\Project\UI\Sidebar</Filter>
|
||||
</ClInclude>
|
||||
|
|
@ -2256,8 +2283,11 @@
|
|||
<ClInclude Include="..\..\Source\Project\UI\jucer_ProjectContentComponent.h">
|
||||
<Filter>Projucer\Project\UI</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\Source\Project\jucer_Module.h">
|
||||
<Filter>Projucer\Project</Filter>
|
||||
<ClInclude Include="..\..\Source\Project\UI\jucer_ProjectMessagesComponent.h">
|
||||
<Filter>Projucer\Project\UI</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\Source\Project\UI\jucer_UserAvatarComponent.h">
|
||||
<Filter>Projucer\Project\UI</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\Source\Project\jucer_Project.h">
|
||||
<Filter>Projucer\Project</Filter>
|
||||
|
|
@ -3719,7 +3749,7 @@
|
|||
<None Include="..\..\Source\BinaryData\Icons\export_xcode.svg">
|
||||
<Filter>Projucer\BinaryData\Icons</Filter>
|
||||
</None>
|
||||
<None Include="..\..\Source\BinaryData\Icons\huckleberry_icon.svg">
|
||||
<None Include="..\..\Source\BinaryData\Icons\gpl_logo.svg">
|
||||
<Filter>Projucer\BinaryData\Icons</Filter>
|
||||
</None>
|
||||
<None Include="..\..\Source\BinaryData\Icons\juce-logo-with-text.svg">
|
||||
|
|
|
|||
|
|
@ -214,11 +214,11 @@
|
|||
<ClCompile Include="..\..\Source\LiveBuildEngine\jucer_CompileEngineClient.cpp"/>
|
||||
<ClCompile Include="..\..\Source\LiveBuildEngine\jucer_CompileEngineServer.cpp"/>
|
||||
<ClCompile Include="..\..\Source\LiveBuildEngine\jucer_DownloadCompileEngineThread.cpp"/>
|
||||
<ClCompile Include="..\..\Source\Project\Modules\jucer_Modules.cpp"/>
|
||||
<ClCompile Include="..\..\Source\Project\UI\jucer_HeaderComponent.cpp"/>
|
||||
<ClCompile Include="..\..\Source\Project\UI\jucer_ProjectContentComponent.cpp">
|
||||
<ExcludedFromBuild>true</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\Source\Project\jucer_Module.cpp"/>
|
||||
<ClCompile Include="..\..\Source\Project\jucer_Project.cpp"/>
|
||||
<ClCompile Include="..\..\Source\ProjectSaving\jucer_ProjectExporter.cpp"/>
|
||||
<ClCompile Include="..\..\Source\ProjectSaving\jucer_ProjectSaver.cpp"/>
|
||||
|
|
@ -1483,6 +1483,10 @@
|
|||
<ClCompile Include="..\..\JuceLibraryCode\include_juce_gui_extra.cpp"/>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="..\..\Source\Application\UserAccount\jucer_LicenseController.h"/>
|
||||
<ClInclude Include="..\..\Source\Application\UserAccount\jucer_LicenseQueryThread.h"/>
|
||||
<ClInclude Include="..\..\Source\Application\UserAccount\jucer_LicenseState.h"/>
|
||||
<ClInclude Include="..\..\Source\Application\UserAccount\jucer_LoginFormComponent.h"/>
|
||||
<ClInclude Include="..\..\Source\Application\Windows\jucer_AboutWindowComponent.h"/>
|
||||
<ClInclude Include="..\..\Source\Application\Windows\jucer_EditorColourSchemeWindowComponent.h"/>
|
||||
<ClInclude Include="..\..\Source\Application\Windows\jucer_FloatingToolWindow.h"/>
|
||||
|
|
@ -1603,6 +1607,9 @@
|
|||
<ClInclude Include="..\..\Source\LiveBuildEngine\jucer_MessageIDs.h"/>
|
||||
<ClInclude Include="..\..\Source\LiveBuildEngine\jucer_ProjectBuildInfo.h"/>
|
||||
<ClInclude Include="..\..\Source\LiveBuildEngine\jucer_SourceCodeRange.h"/>
|
||||
<ClInclude Include="..\..\Source\Project\Modules\jucer_AvailableModulesList.h"/>
|
||||
<ClInclude Include="..\..\Source\Project\Modules\jucer_ModuleDescription.h"/>
|
||||
<ClInclude Include="..\..\Source\Project\Modules\jucer_Modules.h"/>
|
||||
<ClInclude Include="..\..\Source\Project\UI\Sidebar\jucer_ExporterTreeItems.h"/>
|
||||
<ClInclude Include="..\..\Source\Project\UI\Sidebar\jucer_FileTreeItems.h"/>
|
||||
<ClInclude Include="..\..\Source\Project\UI\Sidebar\jucer_LiveBuildTab.h"/>
|
||||
|
|
@ -1616,7 +1623,8 @@
|
|||
<ClInclude Include="..\..\Source\Project\UI\jucer_HeaderComponent.h"/>
|
||||
<ClInclude Include="..\..\Source\Project\UI\jucer_ModulesInformationComponent.h"/>
|
||||
<ClInclude Include="..\..\Source\Project\UI\jucer_ProjectContentComponent.h"/>
|
||||
<ClInclude Include="..\..\Source\Project\jucer_Module.h"/>
|
||||
<ClInclude Include="..\..\Source\Project\UI\jucer_ProjectMessagesComponent.h"/>
|
||||
<ClInclude Include="..\..\Source\Project\UI\jucer_UserAvatarComponent.h"/>
|
||||
<ClInclude Include="..\..\Source\Project\jucer_Project.h"/>
|
||||
<ClInclude Include="..\..\Source\ProjectSaving\jucer_ProjectExport_Android.h"/>
|
||||
<ClInclude Include="..\..\Source\ProjectSaving\jucer_ProjectExport_CLion.h"/>
|
||||
|
|
@ -2105,7 +2113,7 @@
|
|||
<None Include="..\..\Source\BinaryData\Icons\export_linux.svg"/>
|
||||
<None Include="..\..\Source\BinaryData\Icons\export_visualStudio.svg"/>
|
||||
<None Include="..\..\Source\BinaryData\Icons\export_xcode.svg"/>
|
||||
<None Include="..\..\Source\BinaryData\Icons\huckleberry_icon.svg"/>
|
||||
<None Include="..\..\Source\BinaryData\Icons\gpl_logo.svg"/>
|
||||
<None Include="..\..\Source\BinaryData\Icons\juce-logo-with-text.svg"/>
|
||||
<None Include="..\..\Source\BinaryData\Icons\juce_icon.png"/>
|
||||
<None Include="..\..\Source\BinaryData\Icons\wizard_AnimatedApp.svg"/>
|
||||
|
|
|
|||
|
|
@ -2,6 +2,9 @@
|
|||
|
||||
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup>
|
||||
<Filter Include="Projucer\Application\UserAccount">
|
||||
<UniqueIdentifier>{DA27985D-8427-CE70-CA06-EAF7009CCC60}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="Projucer\Application\Windows">
|
||||
<UniqueIdentifier>{DC7E18A5-E854-3D99-627F-AAA88246B712}</UniqueIdentifier>
|
||||
</Filter>
|
||||
|
|
@ -47,6 +50,9 @@
|
|||
<Filter Include="Projucer\LiveBuildEngine">
|
||||
<UniqueIdentifier>{0A3B9446-F50B-3D4E-230F-7ED493541A07}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="Projucer\Project\Modules">
|
||||
<UniqueIdentifier>{F5C79836-30DE-9DC7-9392-DAAB3F04C18E}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="Projucer\Project\UI\Sidebar">
|
||||
<UniqueIdentifier>{A0A94AE6-B447-151A-D0DA-FAE9B5410EBF}</UniqueIdentifier>
|
||||
</Filter>
|
||||
|
|
@ -448,15 +454,15 @@
|
|||
<ClCompile Include="..\..\Source\LiveBuildEngine\jucer_DownloadCompileEngineThread.cpp">
|
||||
<Filter>Projucer\LiveBuildEngine</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\Source\Project\Modules\jucer_Modules.cpp">
|
||||
<Filter>Projucer\Project\Modules</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\Source\Project\UI\jucer_HeaderComponent.cpp">
|
||||
<Filter>Projucer\Project\UI</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\Source\Project\UI\jucer_ProjectContentComponent.cpp">
|
||||
<Filter>Projucer\Project\UI</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\Source\Project\jucer_Module.cpp">
|
||||
<Filter>Projucer\Project</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\Source\Project\jucer_Project.cpp">
|
||||
<Filter>Projucer\Project</Filter>
|
||||
</ClCompile>
|
||||
|
|
@ -1857,6 +1863,18 @@
|
|||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="..\..\Source\Application\UserAccount\jucer_LicenseController.h">
|
||||
<Filter>Projucer\Application\UserAccount</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\Source\Application\UserAccount\jucer_LicenseQueryThread.h">
|
||||
<Filter>Projucer\Application\UserAccount</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\Source\Application\UserAccount\jucer_LicenseState.h">
|
||||
<Filter>Projucer\Application\UserAccount</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\Source\Application\UserAccount\jucer_LoginFormComponent.h">
|
||||
<Filter>Projucer\Application\UserAccount</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\Source\Application\Windows\jucer_AboutWindowComponent.h">
|
||||
<Filter>Projucer\Application\Windows</Filter>
|
||||
</ClInclude>
|
||||
|
|
@ -2217,6 +2235,15 @@
|
|||
<ClInclude Include="..\..\Source\LiveBuildEngine\jucer_SourceCodeRange.h">
|
||||
<Filter>Projucer\LiveBuildEngine</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\Source\Project\Modules\jucer_AvailableModulesList.h">
|
||||
<Filter>Projucer\Project\Modules</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\Source\Project\Modules\jucer_ModuleDescription.h">
|
||||
<Filter>Projucer\Project\Modules</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\Source\Project\Modules\jucer_Modules.h">
|
||||
<Filter>Projucer\Project\Modules</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\Source\Project\UI\Sidebar\jucer_ExporterTreeItems.h">
|
||||
<Filter>Projucer\Project\UI\Sidebar</Filter>
|
||||
</ClInclude>
|
||||
|
|
@ -2256,8 +2283,11 @@
|
|||
<ClInclude Include="..\..\Source\Project\UI\jucer_ProjectContentComponent.h">
|
||||
<Filter>Projucer\Project\UI</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\Source\Project\jucer_Module.h">
|
||||
<Filter>Projucer\Project</Filter>
|
||||
<ClInclude Include="..\..\Source\Project\UI\jucer_ProjectMessagesComponent.h">
|
||||
<Filter>Projucer\Project\UI</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\Source\Project\UI\jucer_UserAvatarComponent.h">
|
||||
<Filter>Projucer\Project\UI</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\Source\Project\jucer_Project.h">
|
||||
<Filter>Projucer\Project</Filter>
|
||||
|
|
@ -3719,7 +3749,7 @@
|
|||
<None Include="..\..\Source\BinaryData\Icons\export_xcode.svg">
|
||||
<Filter>Projucer\BinaryData\Icons</Filter>
|
||||
</None>
|
||||
<None Include="..\..\Source\BinaryData\Icons\huckleberry_icon.svg">
|
||||
<None Include="..\..\Source\BinaryData\Icons\gpl_logo.svg">
|
||||
<Filter>Projucer\BinaryData\Icons</Filter>
|
||||
</None>
|
||||
<None Include="..\..\Source\BinaryData\Icons\juce-logo-with-text.svg">
|
||||
|
|
|
|||
|
|
@ -214,11 +214,11 @@
|
|||
<ClCompile Include="..\..\Source\LiveBuildEngine\jucer_CompileEngineClient.cpp"/>
|
||||
<ClCompile Include="..\..\Source\LiveBuildEngine\jucer_CompileEngineServer.cpp"/>
|
||||
<ClCompile Include="..\..\Source\LiveBuildEngine\jucer_DownloadCompileEngineThread.cpp"/>
|
||||
<ClCompile Include="..\..\Source\Project\Modules\jucer_Modules.cpp"/>
|
||||
<ClCompile Include="..\..\Source\Project\UI\jucer_HeaderComponent.cpp"/>
|
||||
<ClCompile Include="..\..\Source\Project\UI\jucer_ProjectContentComponent.cpp">
|
||||
<ExcludedFromBuild>true</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\Source\Project\jucer_Module.cpp"/>
|
||||
<ClCompile Include="..\..\Source\Project\jucer_Project.cpp"/>
|
||||
<ClCompile Include="..\..\Source\ProjectSaving\jucer_ProjectExporter.cpp"/>
|
||||
<ClCompile Include="..\..\Source\ProjectSaving\jucer_ProjectSaver.cpp"/>
|
||||
|
|
@ -1483,6 +1483,10 @@
|
|||
<ClCompile Include="..\..\JuceLibraryCode\include_juce_gui_extra.cpp"/>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="..\..\Source\Application\UserAccount\jucer_LicenseController.h"/>
|
||||
<ClInclude Include="..\..\Source\Application\UserAccount\jucer_LicenseQueryThread.h"/>
|
||||
<ClInclude Include="..\..\Source\Application\UserAccount\jucer_LicenseState.h"/>
|
||||
<ClInclude Include="..\..\Source\Application\UserAccount\jucer_LoginFormComponent.h"/>
|
||||
<ClInclude Include="..\..\Source\Application\Windows\jucer_AboutWindowComponent.h"/>
|
||||
<ClInclude Include="..\..\Source\Application\Windows\jucer_EditorColourSchemeWindowComponent.h"/>
|
||||
<ClInclude Include="..\..\Source\Application\Windows\jucer_FloatingToolWindow.h"/>
|
||||
|
|
@ -1603,6 +1607,9 @@
|
|||
<ClInclude Include="..\..\Source\LiveBuildEngine\jucer_MessageIDs.h"/>
|
||||
<ClInclude Include="..\..\Source\LiveBuildEngine\jucer_ProjectBuildInfo.h"/>
|
||||
<ClInclude Include="..\..\Source\LiveBuildEngine\jucer_SourceCodeRange.h"/>
|
||||
<ClInclude Include="..\..\Source\Project\Modules\jucer_AvailableModulesList.h"/>
|
||||
<ClInclude Include="..\..\Source\Project\Modules\jucer_ModuleDescription.h"/>
|
||||
<ClInclude Include="..\..\Source\Project\Modules\jucer_Modules.h"/>
|
||||
<ClInclude Include="..\..\Source\Project\UI\Sidebar\jucer_ExporterTreeItems.h"/>
|
||||
<ClInclude Include="..\..\Source\Project\UI\Sidebar\jucer_FileTreeItems.h"/>
|
||||
<ClInclude Include="..\..\Source\Project\UI\Sidebar\jucer_LiveBuildTab.h"/>
|
||||
|
|
@ -1616,7 +1623,8 @@
|
|||
<ClInclude Include="..\..\Source\Project\UI\jucer_HeaderComponent.h"/>
|
||||
<ClInclude Include="..\..\Source\Project\UI\jucer_ModulesInformationComponent.h"/>
|
||||
<ClInclude Include="..\..\Source\Project\UI\jucer_ProjectContentComponent.h"/>
|
||||
<ClInclude Include="..\..\Source\Project\jucer_Module.h"/>
|
||||
<ClInclude Include="..\..\Source\Project\UI\jucer_ProjectMessagesComponent.h"/>
|
||||
<ClInclude Include="..\..\Source\Project\UI\jucer_UserAvatarComponent.h"/>
|
||||
<ClInclude Include="..\..\Source\Project\jucer_Project.h"/>
|
||||
<ClInclude Include="..\..\Source\ProjectSaving\jucer_ProjectExport_Android.h"/>
|
||||
<ClInclude Include="..\..\Source\ProjectSaving\jucer_ProjectExport_CLion.h"/>
|
||||
|
|
@ -2105,7 +2113,7 @@
|
|||
<None Include="..\..\Source\BinaryData\Icons\export_linux.svg"/>
|
||||
<None Include="..\..\Source\BinaryData\Icons\export_visualStudio.svg"/>
|
||||
<None Include="..\..\Source\BinaryData\Icons\export_xcode.svg"/>
|
||||
<None Include="..\..\Source\BinaryData\Icons\huckleberry_icon.svg"/>
|
||||
<None Include="..\..\Source\BinaryData\Icons\gpl_logo.svg"/>
|
||||
<None Include="..\..\Source\BinaryData\Icons\juce-logo-with-text.svg"/>
|
||||
<None Include="..\..\Source\BinaryData\Icons\juce_icon.png"/>
|
||||
<None Include="..\..\Source\BinaryData\Icons\wizard_AnimatedApp.svg"/>
|
||||
|
|
|
|||
|
|
@ -2,6 +2,9 @@
|
|||
|
||||
<Project ToolsVersion="16.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup>
|
||||
<Filter Include="Projucer\Application\UserAccount">
|
||||
<UniqueIdentifier>{DA27985D-8427-CE70-CA06-EAF7009CCC60}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="Projucer\Application\Windows">
|
||||
<UniqueIdentifier>{DC7E18A5-E854-3D99-627F-AAA88246B712}</UniqueIdentifier>
|
||||
</Filter>
|
||||
|
|
@ -47,6 +50,9 @@
|
|||
<Filter Include="Projucer\LiveBuildEngine">
|
||||
<UniqueIdentifier>{0A3B9446-F50B-3D4E-230F-7ED493541A07}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="Projucer\Project\Modules">
|
||||
<UniqueIdentifier>{F5C79836-30DE-9DC7-9392-DAAB3F04C18E}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="Projucer\Project\UI\Sidebar">
|
||||
<UniqueIdentifier>{A0A94AE6-B447-151A-D0DA-FAE9B5410EBF}</UniqueIdentifier>
|
||||
</Filter>
|
||||
|
|
@ -448,15 +454,15 @@
|
|||
<ClCompile Include="..\..\Source\LiveBuildEngine\jucer_DownloadCompileEngineThread.cpp">
|
||||
<Filter>Projucer\LiveBuildEngine</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\Source\Project\Modules\jucer_Modules.cpp">
|
||||
<Filter>Projucer\Project\Modules</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\Source\Project\UI\jucer_HeaderComponent.cpp">
|
||||
<Filter>Projucer\Project\UI</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\Source\Project\UI\jucer_ProjectContentComponent.cpp">
|
||||
<Filter>Projucer\Project\UI</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\Source\Project\jucer_Module.cpp">
|
||||
<Filter>Projucer\Project</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\Source\Project\jucer_Project.cpp">
|
||||
<Filter>Projucer\Project</Filter>
|
||||
</ClCompile>
|
||||
|
|
@ -1857,6 +1863,18 @@
|
|||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="..\..\Source\Application\UserAccount\jucer_LicenseController.h">
|
||||
<Filter>Projucer\Application\UserAccount</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\Source\Application\UserAccount\jucer_LicenseQueryThread.h">
|
||||
<Filter>Projucer\Application\UserAccount</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\Source\Application\UserAccount\jucer_LicenseState.h">
|
||||
<Filter>Projucer\Application\UserAccount</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\Source\Application\UserAccount\jucer_LoginFormComponent.h">
|
||||
<Filter>Projucer\Application\UserAccount</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\Source\Application\Windows\jucer_AboutWindowComponent.h">
|
||||
<Filter>Projucer\Application\Windows</Filter>
|
||||
</ClInclude>
|
||||
|
|
@ -2217,6 +2235,15 @@
|
|||
<ClInclude Include="..\..\Source\LiveBuildEngine\jucer_SourceCodeRange.h">
|
||||
<Filter>Projucer\LiveBuildEngine</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\Source\Project\Modules\jucer_AvailableModulesList.h">
|
||||
<Filter>Projucer\Project\Modules</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\Source\Project\Modules\jucer_ModuleDescription.h">
|
||||
<Filter>Projucer\Project\Modules</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\Source\Project\Modules\jucer_Modules.h">
|
||||
<Filter>Projucer\Project\Modules</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\Source\Project\UI\Sidebar\jucer_ExporterTreeItems.h">
|
||||
<Filter>Projucer\Project\UI\Sidebar</Filter>
|
||||
</ClInclude>
|
||||
|
|
@ -2256,8 +2283,11 @@
|
|||
<ClInclude Include="..\..\Source\Project\UI\jucer_ProjectContentComponent.h">
|
||||
<Filter>Projucer\Project\UI</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\Source\Project\jucer_Module.h">
|
||||
<Filter>Projucer\Project</Filter>
|
||||
<ClInclude Include="..\..\Source\Project\UI\jucer_ProjectMessagesComponent.h">
|
||||
<Filter>Projucer\Project\UI</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\Source\Project\UI\jucer_UserAvatarComponent.h">
|
||||
<Filter>Projucer\Project\UI</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\Source\Project\jucer_Project.h">
|
||||
<Filter>Projucer\Project</Filter>
|
||||
|
|
@ -3719,7 +3749,7 @@
|
|||
<None Include="..\..\Source\BinaryData\Icons\export_xcode.svg">
|
||||
<Filter>Projucer\BinaryData\Icons</Filter>
|
||||
</None>
|
||||
<None Include="..\..\Source\BinaryData\Icons\huckleberry_icon.svg">
|
||||
<None Include="..\..\Source\BinaryData\Icons\gpl_logo.svg">
|
||||
<Filter>Projucer\BinaryData\Icons</Filter>
|
||||
</None>
|
||||
<None Include="..\..\Source\BinaryData\Icons\juce-logo-with-text.svg">
|
||||
|
|
|
|||
|
|
@ -57,12 +57,11 @@ target_sources(Projucer PRIVATE
|
|||
Source/ComponentEditor/jucer_JucerDocument.cpp
|
||||
Source/ComponentEditor/jucer_ObjectTypes.cpp
|
||||
Source/ComponentEditor/jucer_PaintRoutine.cpp
|
||||
Source/Licenses/jucer_LicenseController.cpp
|
||||
Source/LiveBuildEngine/jucer_CompileEngineClient.cpp
|
||||
Source/LiveBuildEngine/jucer_CompileEngineServer.cpp
|
||||
Source/LiveBuildEngine/jucer_DownloadCompileEngineThread.cpp
|
||||
Source/Project/Modules/jucer_Modules.cpp
|
||||
Source/Project/UI/jucer_HeaderComponent.cpp
|
||||
Source/Project/jucer_Module.cpp
|
||||
Source/Project/jucer_Project.cpp
|
||||
Source/ProjectSaving/jucer_ProjectExporter.cpp
|
||||
Source/ProjectSaving/jucer_ProjectSaver.cpp
|
||||
|
|
@ -97,7 +96,7 @@ juce_add_binary_data(ProjucerData SOURCES
|
|||
Source/BinaryData/Icons/export_linux.svg
|
||||
Source/BinaryData/Icons/export_visualStudio.svg
|
||||
Source/BinaryData/Icons/export_xcode.svg
|
||||
Source/BinaryData/Icons/huckleberry_icon.svg
|
||||
Source/BinaryData/Icons/gpl_logo.svg
|
||||
Source/BinaryData/Icons/juce-logo-with-text.svg
|
||||
Source/BinaryData/Icons/juce_icon.png
|
||||
Source/BinaryData/Icons/wizard_AnimatedApp.svg
|
||||
|
|
|
|||
|
|
@ -1981,60 +1981,131 @@ static const unsigned char temp_binary_data_16[] =
|
|||
|
||||
const char* export_xcode_svg = (const char*) temp_binary_data_16;
|
||||
|
||||
//================== huckleberry_icon.svg ==================
|
||||
//================== gpl_logo.svg ==================
|
||||
static const unsigned char temp_binary_data_17[] =
|
||||
"<?xml version=\"1.0\" encoding=\"utf-8\"?>\n"
|
||||
"<!-- Generator: Adobe Illustrator 21.0.2, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->\n"
|
||||
"<svg version=\"1.1\" id=\"Layer_1\" xmlns=\"http://www.w3.org/2000/svg\" xmlns:xlink=\"http://www.w3.org/1999/xlink\" x=\"0px\" y=\"0px\"\n"
|
||||
"\t viewBox=\"0 0 169.7 205.2\" style=\"enable-background:new 0 0 169.7 205.2;\" xml:space=\"preserve\">\n"
|
||||
"<style type=\"text/css\">\n"
|
||||
"\t.st0{fill:#A65A95;}\n"
|
||||
"\t.st1{fill:#001946;}\n"
|
||||
"</style>\n"
|
||||
"<g>\n"
|
||||
"\t<g>\n"
|
||||
"\t\t<path class=\"st0\" d=\"M45.2,167.8c-3,0-5.4-1.1-7.8-4.3l3.6-3.1c1.6,2.1,2.7,2.7,4.2,2.7c2.6,0,4.4-2,4.4-5v-17.2h5V158\n"
|
||||
"\t\t\tC54.6,163.9,50.7,167.8,45.2,167.8z\"/>\n"
|
||||
"\t\t<path class=\"st0\" d=\"M70.7,167.8c-5.8,0-10.8-4.2-10.8-11.2v-15.8h5v15.6c0,4.1,2.4,6.7,5.8,6.7c3.4,0,5.8-2.6,5.8-6.7v-15.6h5\n"
|
||||
"\t\t\tv15.8C81.5,163.5,76.5,167.8,70.7,167.8z\"/>\n"
|
||||
"\t\t<path class=\"st0\" d=\"M99,167.8c-7.6,0-13.9-6.1-13.9-13.6c0-7.6,6.3-13.6,13.9-13.6c3.4,0,6.3,1.2,9.1,3.4l-2.9,3.6\n"
|
||||
"\t\t\tc-2.6-1.8-4.1-2.4-6.2-2.4c-4.8,0-8.8,3.9-8.8,9c0,5,3.9,9,8.8,9c2,0,3.6-0.6,6.1-2.4l3,3.7C104.6,167,102,167.8,99,167.8z\"/>\n"
|
||||
"\t\t<path class=\"st0\" d=\"M111.3,167.4v-26.6h16.6v4.5h-11.6v6.4h11.2v4.5h-11.2v6.7h11.6v4.5H111.3z\"/>\n"
|
||||
"\t</g>\n"
|
||||
"\t<g>\n"
|
||||
"\t\t<circle class=\"st1\" cx=\"84.9\" cy=\"74.9\" r=\"37.4\"/>\n"
|
||||
"\t\t<circle class=\"st0\" cx=\"84.9\" cy=\"74.9\" r=\"28\"/>\n"
|
||||
"\t\t<circle class=\"st1\" cx=\"84.9\" cy=\"67.9\" r=\"2.1\"/>\n"
|
||||
"\t\t<circle class=\"st1\" cx=\"91.4\" cy=\"72.6\" r=\"2.1\"/>\n"
|
||||
"\t\t<circle class=\"st1\" cx=\"88.9\" cy=\"80.3\" r=\"2.1\"/>\n"
|
||||
"\t\t<circle class=\"st1\" cx=\"80.8\" cy=\"80.3\" r=\"2.1\"/>\n"
|
||||
"\t\t<circle class=\"st1\" cx=\"78.3\" cy=\"72.6\" r=\"2.1\"/>\n"
|
||||
"\t</g>\n"
|
||||
"\t<g>\n"
|
||||
"\t\t<path class=\"st1\" d=\"M48.2,131.7v-4.6h-4.3v4.6h-2V121h2v4.3h4.3V121h2v10.8H48.2z\"/>\n"
|
||||
"\t\t<path class=\"st1\" d=\"M56.7,131.7v-0.5c-0.5,0.4-1.3,0.7-2.1,0.7c-1.9,0-3.2-1.3-3.2-3.4v-5h2v4.8c0,1.2,0.7,1.8,1.7,1.8\n"
|
||||
"\t\t\tc1,0,1.7-0.7,1.7-1.8v-4.8h2v8.3H56.7z\"/>\n"
|
||||
"\t\t<path class=\"st1\" d=\"M63.8,131.9c-2.4,0-4.3-1.9-4.3-4.3c0-2.4,1.9-4.3,4.3-4.3c1.1,0,2.1,0.4,3.3,1.5l-1.3,1.2\n"
|
||||
"\t\t\tc-0.7-0.7-1.3-1-2-1c-1.3,0-2.3,1.1-2.3,2.5c0,1.3,1,2.5,2.3,2.5c0.6,0,1.3-0.2,2-0.9l1.3,1.2C66,131.5,65,131.9,63.8,131.9z\"/>\n"
|
||||
"\t\t<path class=\"st1\" d=\"M73.8,131.7l-3.9-3.9v3.9h-2v-11.3h2v6.8l3.6-3.7h2.5l-3.9,4l4.3,4.3H73.8z\"/>\n"
|
||||
"\t\t<path class=\"st1\" d=\"M77.1,131.7v-11.3h2v11.3H77.1z\"/>\n"
|
||||
"\t\t<path class=\"st1\" d=\"M88.6,128.4h-6.2c0.1,1,1.1,1.7,2.1,1.7c0.7,0,1.5-0.3,2.3-1.1l1.3,1.2c-1.1,1.2-2.3,1.7-3.6,1.7\n"
|
||||
"\t\t\tc-2.4,0-4.3-1.9-4.3-4.3c0-2.4,1.9-4.3,4.3-4.3c2.4,0,4.1,1.9,4.1,4.2C88.7,127.9,88.6,128.4,88.6,128.4z M84.5,125.1\n"
|
||||
"\t\t\tc-1,0-1.9,0.6-2.1,1.5h4.1C86.3,125.8,85.5,125.1,84.5,125.1z\"/>\n"
|
||||
"\t\t<path class=\"st1\" d=\"M93.9,131.9c-0.9,0-1.7-0.3-2.3-0.8v0.6h-2v-11.3h2v3.7c0.6-0.5,1.4-0.8,2.3-0.8c2.3,0,4.2,1.9,4.2,4.3\n"
|
||||
"\t\t\tC98.1,129.9,96.2,131.9,93.9,131.9z M93.9,125.1c-1.3,0-2.2,1.1-2.2,2.5c0,1.4,1,2.5,2.2,2.5c1.3,0,2.2-1.1,2.2-2.5\n"
|
||||
"\t\t\tC96.2,126.2,95.2,125.1,93.9,125.1z\"/>\n"
|
||||
"\t\t<path class=\"st1\" d=\"M107.4,128.4h-6.2c0.1,1,1.1,1.7,2.1,1.7c0.7,0,1.5-0.3,2.3-1.1l1.3,1.2c-1.1,1.2-2.3,1.7-3.6,1.7\n"
|
||||
"\t\t\tc-2.4,0-4.3-1.9-4.3-4.3c0-2.4,1.9-4.3,4.3-4.3c2.4,0,4.1,1.9,4.1,4.2C107.5,127.9,107.4,128.4,107.4,128.4z M103.3,125.1\n"
|
||||
"\t\t\tc-1,0-1.9,0.6-2.1,1.5h4.1C105.1,125.8,104.3,125.1,103.3,125.1z\"/>\n"
|
||||
"\t\t<path class=\"st1\" d=\"M110.4,127.8v3.9h-2v-8.3h2v0.8c0.7-0.6,1.4-0.9,2.6-1v1.8C111,125.4,110.4,126.6,110.4,127.8z\"/>\n"
|
||||
"\t\t<path class=\"st1\" d=\"M116,127.8v3.9h-2v-8.3h2v0.8c0.7-0.6,1.4-0.9,2.6-1v1.8C116.6,125.4,116,126.6,116,127.8z\"/>\n"
|
||||
"\t\t<path class=\"st1\" d=\"M122.2,134.6h-2.1l2.2-4.2l-3.4-6.9h2.1l2.4,4.8l2.3-4.8h2.2L122.2,134.6z\"/>\n"
|
||||
"\t</g>\n"
|
||||
"</g>\n"
|
||||
"</svg>\n";
|
||||
"<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"720\" height=\"358\" version=\"1.1\">\n"
|
||||
" <g id=\"g1\" transform=\"translate(-26.149211,-6.9701601)\">\n"
|
||||
" <path id=\"path1\" style=\"fill:#bd0000;\" d=\"m 107.04146,18.25331 c 2e-5,0 -59.309734,258.76742 -59.309734,258.76742 0.01705,0 0.01919,0 0.05329,0 0,0 274.380814,0 274.380814,0 10e-6,0 142.70573,0 142.70573,0 -17.00107,-1.48353 -30.42327,-7.451"
|
||||
"82 -38.42076,-18.33112 -1.48353,-2.01219 -2.70918,-4.17993 -3.78347,-6.44788 -0.68207,-1.6711 -1.32368,-3.35715 -1.97167,-5.06237 -1.70524,-5.42261 -2.38517,-11.43991 -2.07824,-17.85154 0.85262,-17.87074 9.23805,-39.12802 23.76654,-61.38798 15.43225,"
|
||||
"-23.65656 37.79837,-48.45089 65.49116,-71.45944 6.20699,-5.15319 12.62503,-10.24199 19.34361,-15.18714 8.30441,-6.10979 16.67281,-11.73661 25.04545,-16.99893 30.84745,-19.42077 61.61817,-33.01012 88.88467,-39.91282 -26.05577,8.50051 -55.32805,22.9313"
|
||||
"8 -84.24861,42.57724 -1.04016,0.70255 -2.06758,1.42215 -3.09072,2.13152 -16.04613,11.11805 -30.58314,22.92586 -43.26998,34.85046 -40.82303,38.38457 -62.40046,78.15884 -52.59544,101.46069 0.69916,1.6029 1.53256,3.13335 2.50455,4.58279 10.53825,15.5004"
|
||||
"7 36.65587,18.17979 69.75422,9.85831 2.25089,-0.56275 4.50178,-1.20004 6.82088,-1.86508 10.57238,-3.05237 21.797,-7.17473 33.3584,-12.25628 2.77949,-1.22777 5.58887,-2.48963 8.41953,-3.83676 0.28988,-0.13641 0.56273,-0.27283 0.85261,-0.4263 36.49173,"
|
||||
"-18.13162 64.53625,-38.99458 70.60684,-51.52967 1.33008,-2.72662 1.6498,-5.0513 0.74603,-6.87417 -4.33124,-8.78188 -34.63945,-2.849 -71.35287,13.0556 -2.95003,1.2789 -5.93417,2.59492 -8.95241,3.99661 2.45552,-2.27986 5.01123,-4.56828 7.6202,-6.82089 "
|
||||
"4.16075,-3.58438 8.46856,-7.08945 13.0556,-10.55104 7.179,-5.43627 14.43685,-10.35071 21.58173,-14.70754 33.45643,-25.24067 50.3701,-49.11722 46.8403,-57.97753 -0.66505,-1.66943 -2.08037,-2.81789 -4.26306,-3.51703 -6.97438,-2.21847 -19.70383,0.42929 "
|
||||
"-35.17019,6.7676 -12.75504,5.23164 -27.40504,12.9908 -42.25752,22.64748 0,0 -2.02495,1.3322 -2.02495,1.3322 2e-5,0 -0.37302,0.21314 -0.37302,0.21314 2e-5,2e-5 -7.14061,4.74265 -7.14061,4.74265 -2e-5,-1e-5 4.10319,-7.51363 4.10319,-7.51363 6.08765,-11"
|
||||
".14364 16.0035,-22.77067 28.3493,-33.57154 9.05473,-7.89689 19.39903,-15.33762 30.53413,-21.84816 4.21191,-2.46573 8.4174,-4.75586 12.62929,-6.82088 4.31422,-2.10769 8.63055,-3.98089 12.84246,-5.64859 12.23682,-4.8393 23.91781,-7.7798 34.10442,-8.579"
|
||||
"4 -0.92767,0 -28.61574,0 -28.61574,0 10e-6,0 -96.45159,0 -96.45159,0 10e-6,0 -425.29295,0 -425.29295,0 0,0 -33.73141,0 -33.73141,0 z m 305.98071,0.3731 c -1.67109,25.50496 3.27403,62.86211 14.49439,104.3382 1.99509,7.38021 4.16712,14.89085 6.55444,22"
|
||||
".48762 1.48356,4.69104 3.01399,9.30881 4.58278,13.85492 -0.9208,1.35396 -1.84804,2.69937 -2.7177,4.0499 -13.99985,21.45508 -22.1828,41.73104 -24.24611,59.36303 -5.91714,-19.81468 -10.37201,-41.5183 -12.89574,-64.53198 -0.71619,-6.5941 -1.27679,-13.11"
|
||||
"442 -1.65194,-19.55675 -2.76247,-46.79639 3.34649,-89.2172 15.87988,-120.00494 z m -279.3899,33.1985 c 0.31934,-0.0075 0.63414,0 0.95918,0 0,-2e-5 63.03991,0 63.03991,0 5.38851,-2e-5 9.55564,1.00991 12.52272,3.03742 2.95002,2.03946 4.05631,4.67743 3."
|
||||
"35715,7.88665 2e-5,2e-5 -7.51363,33.94456 -7.51363,33.94456 0,3e-5 -22.22116,0 -22.22116,0 2e-5,3e-5 7.30048,-33.03866 7.30048,-33.03866 -2e-5,0 -55.63285,0 -55.63285,0 -2e-5,0 -20.08965,90.80305 -20.08965,90.80305 2e-5,0 -7.24719,32.87881 -7.24719,3"
|
||||
"2.87881 0,3e-5 55.57957,0 55.57957,0 0,3e-5 0.0533,-0.21316 0.0533,-0.21316 0,2e-5 11.13722,-50.30404 11.13722,-50.30404 0,-2e-5 -26.1112,0 -26.1112,0 0,-2e-5 2.50454,-11.35038 2.50454,-11.35038 -1e-5,-2e-5 48.33238,0 48.33238,0 0,-2e-5 -13.85493,62."
|
||||
"77348 -13.85493,62.77348 -0.18757,0.89352 -0.51582,1.70308 -0.95919,2.50453 -1.14249,2.08037 -3.13547,3.86234 -5.91498,5.32883 -3.85378,2.02923 -8.46643,3.03742 -13.85493,3.03742 0,2e-5 -62.98662,0 -62.98662,0 -5.388524,2e-5 -9.555644,-1.00821 -12.52"
|
||||
"2724,-3.03742 -2.95001,-2.0292 -4.07335,-4.62073 -3.35715,-7.83336 10e-6,-2e-5 27.763134,-125.49366 27.763134,-125.49366 0.71618,-3.20921 2.95005,-5.84721 6.82089,-7.88665 0.13642,-0.07331 0.28989,-0.08995 0.4263,-0.15986 3.53302,-1.7697 7.67937,-2.7"
|
||||
"6443 12.46944,-2.87756 z m 98.79628,0 c -2e-5,-2e-5 79.34608,0 79.34608,0 5.32031,-2e-5 9.50235,1.00991 12.46943,3.03742 2.98417,2.03946 4.12666,4.67743 3.41045,7.88665 2e-5,2e-5 -14.81411,66.92995 -14.81411,66.92995 -0.69912,3.18874 -2.98627,5.7905 "
|
||||
"-6.87417,7.83336 -3.8879,2.04966 -8.4643,3.09071 -13.80164,3.09071 -2e-5,0 -57.6578,0 -57.6578,0 0,0 -11.13723,50.25075 -11.13723,50.25075 0,2e-5 -1.8118,8.25967 -1.8118,8.25967 1e-5,2e-5 -21.74158,0 -21.74158,0 0,2e-5 1.65193,-7.46034 1.65193,-7.460"
|
||||
"34 0,2e-5 30.96044,-139.82817 30.96044,-139.82817 z m 109.61377,0 c -1e-5,-2e-5 21.74158,0 21.74158,0 2e-5,-2e-5 -24.61914,111.21241 -24.61914,111.21241 2e-5,2e-5 -5.3821,24.29942 -5.3821,24.29942 0,3e-5 52.00926,0 52.00926,0 0.54568,3.98854 1.18299,"
|
||||
"7.90582 1.86508,11.77668 -2e-5,2e-5 -78.22705,0 -78.22705,0 2e-5,2e-5 6.18143,-27.92301 6.18143,-27.92301 2e-5,0 26.43094,-119.3655 26.43094,-119.3655 z M 251.559,63.65488 c 2e-5,0 -14.4411,65.11814 -14.4411,65.11814 0,-2e-5 54.19408,0 54.19408,0 -1e"
|
||||
"-5,-2e-5 14.3878,-65.11814 14.3878,-65.11814 2e-5,0 -54.14078,0 -54.14078,0 z m -45.5614,145.68987 c 0.21267,-0.007 0.42524,0 0.63947,0 2.52373,2e-5 4.72772,0.44336 6.50115,1.27891 1.8928,0.88671 3.24632,2.204 3.99662,3.94333 0.73325,1.68819 0.92508,"
|
||||
"3.60441 0.53287,5.70184 0,1e-5 -0.15985,0.79933 -0.15985,0.79933 1e-5,-3e-5 -6.23472,0 -6.23472,0 -2e-5,-3e-5 0.0533,-0.74605 0.0533,-0.74605 0.16118,-1.46543 -0.0205,-2.61779 -0.58618,-3.41043 -0.0737,-0.0994 -0.18053,-0.23063 -0.26644,-0.31973 -0.1"
|
||||
"4068,-0.14363 -0.35198,-0.3078 -0.53287,-0.42631 -0.87238,-0.5495 -2.23703,-0.85262 -3.99662,-0.85262 -2.33615,2e-5 -4.08187,0.40712 -5.27552,1.22564 -1.15956,0.80146 -1.8928,1.6967 -2.13153,2.77098 -0.23875,1.09134 0.15346,1.66472 0.42631,1.97166 0."
|
||||
"008,0.008 0.0429,0.0438 0.0533,0.0533 0.34552,0.29445 1.54536,0.98476 5.27553,1.86508 3.37632,0.81851 5.61232,1.55389 6.87418,2.18482 1.90987,0.97196 3.24419,2.2317 3.94334,3.78346 0.69911,1.53472 0.8526,3.33157 0.4263,5.27553 -0.4263,1.89279 -1.3918"
|
||||
"9,3.63852 -2.82428,5.27554 -1.41532,1.637 -3.21647,2.93297 -5.38211,3.83673 -2.1486,0.88672 -4.50604,1.38549 -6.92746,1.38549 -3.0694,-1e-5 -5.53343,-0.46467 -7.46034,-1.38549 -2.01217,-0.95491 -3.46374,-2.4619 -4.31634,-4.42291 -0.81851,-1.90986 -0."
|
||||
"9933,-4.07762 -0.53289,-6.44786 0,-3e-5 0.15987,-0.74605 0.15987,-0.74605 0,0 6.12814,0 6.12814,0 0,0 -0.0533,0.74605 -0.0533,0.74605 -0.15348,1.41532 -0.002,2.55782 0.37302,3.41043 0.35809,0.81853 1.04019,1.49633 2.13152,2.02496 1.15954,0.5627 2.608"
|
||||
"98,0.8526 4.26305,0.8526 1.48355,-1e-5 2.83921,-0.24939 4.04991,-0.69273 1.19365,-0.4263 2.14218,-0.98904 2.82427,-1.70523 0.66502,-0.71622 1.05511,-1.47288 1.22563,-2.2914 0.17052,-0.73324 0.13002,-1.3535 -0.15987,-1.86508 -0.32399,-0.54564 -0.96558"
|
||||
",-1.02953 -1.97165,-1.43878 0,-1e-5 -5.22226,-1.54536 -5.22226,-1.54536 -2.91592,-0.73323 -4.87905,-1.43238 -6.02155,-2.13152 -1.55177,-0.92081 -2.67081,-2.10169 -3.25059,-3.51702 -0.57977,-1.39831 -0.64158,-2.94791 -0.26643,-4.63608 0.3922,-1.80753 "
|
||||
"1.26399,-3.52767 2.61111,-5.06237 1.3642,-1.55177 3.12482,-2.76885 5.22225,-3.57031 1.85443,-0.6954 3.80596,-1.10321 5.86169,-1.17234 z m 55.9526,0.10658 c 0.33725,-0.0263 0.65436,0 1.01247,0 10e-6,0 3.83675,0.4263 3.83675,0.4263 -10e-6,0 1.27891,0.1"
|
||||
"0658 1.27891,0.10658 2e-5,1e-5 -1.86508,4.74264 -1.86508,4.74264 -1e-5,2e-5 -0.37302,0.74604 -0.37302,0.74604 0,-2e-5 -2.93084,-0.26644 -2.93084,-0.26644 -0.86541,0 -1.50113,0.13352 -1.91838,0.4263 -0.0277,0.0209 -0.081,0.0842 -0.10658,0.10658 -0.055"
|
||||
"9,0.049 -0.14991,0.13458 -0.21315,0.21316 -0.25659,0.33651 -0.56912,0.93786 -0.79932,2.02495 -2e-5,0 -0.11084,0.4604 -0.21315,0.85261 1.34713,1e-5 4.58277,0 4.58277,0 0,1e-5 -1.17233,5.27552 -1.17233,5.27552 0,-1e-5 -3.35076,0 -4.4762,0 -0.34106,1.53"
|
||||
"469 -4.5295,20.3028 -4.5295,20.3028 -2e-5,-2e-5 -6.18143,0 -6.18143,0 -2e-5,-2e-5 4.01793,-18.03485 4.5295,-20.3028 -1.04021,-1e-5 -3.57031,0 -3.57031,0 0,-1e-5 1.17234,-5.27552 1.17234,-5.27552 10e-6,1e-5 2.54504,0 3.51701,0 0.17052,-0.73324 0.4263,"
|
||||
"-1.65194 0.4263,-1.65194 0.37516,-1.70522 0.76735,-2.93085 1.27891,-3.78346 0.69917,-1.17659 1.68606,-2.16137 2.93087,-2.87756 1.02527,-0.59575 2.32198,-0.95194 3.78346,-1.06576 z m 14.76082,0.26644 c -2e-5,-1e-5 -1.6157,7.27064 -2.02495,9.11228 1.19"
|
||||
"364,1e-5 3.99661,0 3.99661,0 0,1e-5 -1.17233,5.27552 -1.17233,5.27552 -2e-5,-1e-5 -2.93939,0 -3.99662,0 -0.32401,1.46647 -2.87756,12.84246 -2.87756,12.84246 2e-5,-2e-5 -0.21316,1.36631 -0.21316,1.75851 2.8e-4,0.0131 -10e-4,0.0437 0,0.0533 8.4e-4,0.00"
|
||||
"4 -10e-4,0.05 0,0.0533 0.002,0.003 0.0512,-0.002 0.0533,0 0,-2e-5 0.63947,0.0533 0.63947,0.0533 0,0 2.93085,-0.21315 2.93085,-0.21315 0,0 -0.31973,4.74264 -0.31973,4.74264 2e-5,0 0.0533,0.85261 0.0533,0.85261 -2e-5,-2e-5 -4.20978,0.4796 -4.20978,0.47"
|
||||
"96 -1.6711,-2e-5 -2.89675,-0.27283 -3.78346,-0.8526 -0.93785,-0.61392 -1.48354,-1.42814 -1.70522,-2.45126 -0.0341,-0.18759 -0.10658,-0.46042 -0.10658,-0.85261 0,-0.76736 0.14495,-2.06545 0.63946,-4.31634 2e-5,2e-5 2.24023,-10.03524 2.7177,-12.14972 -"
|
||||
"0.80143,-1e-5 -2.93085,0 -2.93085,0 2e-5,-1e-5 1.17233,-5.27552 1.17233,-5.27552 -2e-5,10e-6 2.07824,0 2.93086,0 0.27281,-1.22775 1.22562,-5.4354 1.22562,-5.4354 0,2e-5 4.95581,-2.61112 4.95581,-2.61112 -10e-6,2e-5 2.02495,-1.06576 2.02495,-1.06576 z"
|
||||
" m -196.366934,0.21315 c 2e-5,0 23.979684,0 23.979684,0 0,0 -1.3322,5.96828 -1.3322,5.96828 0,2e-5 -15.997114,0 -17.531814,0 -0.27282,1.21073 -1.36631,6.11322 -1.75851,7.88665 2.2168,0 15.18713,0 15.18713,0 0,0 -1.33221,5.96826 -1.33221,5.96826 -1e-5"
|
||||
",0 -13.65242,0 -15.18713,0 -0.32399,1.48355 -3.25058,14.65426 -3.25058,14.65426 2e-5,-2e-5 -6.44786,0 -6.44786,0 1e-5,-2e-5 7.67349,-34.47745 7.67349,-34.47745 z m 32.132764,8.41954 c 0.24067,-0.0296 0.50358,0 0.74604,0 1.5347,0 2.95217,0.4668 4.3163"
|
||||
"5,1.43877 0,2e-5 0.8526,0.58617 0.8526,0.58617 0,0 -3.30386,5.4354 -3.30386,5.4354 0,-2e-5 -0.90589,-0.63946 -0.90589,-0.63946 -0.66504,-0.42629 -1.38123,-0.63946 -2.13153,-0.63946 -0.64799,2e-5 -1.25121,0.2302 -1.86509,0.63946 -0.64797,0.4263 -1.189"
|
||||
"4,0.99115 -1.59864,1.75851 -0.7162,1.31304 -1.24056,2.78377 -1.59865,4.36963 0,1e-5 -2.87756,13.10889 -2.87756,13.10889 0,-2e-5 -6.181434,0 -6.181434,0 0,-2e-5 5.701844,-25.57832 5.701844,-25.57832 2e-5,1e-5 5.75512,0 5.75512,0 0,1e-5 -0.19824,0.7758"
|
||||
"8 -0.26645,1.06576 0.27284,-0.20461 0.56059,-0.48599 0.79933,-0.63946 0.82597,-0.4929 1.69837,-0.80035 2.55782,-0.90589 z m 18.33114,0 c 0.37219,-0.0282 0.73859,0 1.11906,0 3.47866,0 6.11108,1.21922 7.83335,3.62359 1.07428,1.55174 1.65195,3.47012 1.6"
|
||||
"5195,5.75512 0,1.26185 -0.15561,2.61965 -0.47959,4.10319 0,0 -0.47961,1.86509 -0.47961,1.86509 0,-2e-5 -15.63261,0 -17.37194,0 -0.0341,0.35808 -0.0533,0.74177 -0.0533,1.06576 0,1.33009 0.27283,2.37665 0.85261,3.14401 0.2755,0.37513 0.5949,0.71299 0.9"
|
||||
"5919,0.95918 0.68678,0.44789 1.57334,0.69275 2.61112,0.69275 1.26188,-2e-5 2.37025,-0.34745 3.41044,-1.01248 0.98905,-0.63093 1.93544,-1.63914 2.77099,-3.03742 0,-3e-5 6.60773,0 6.60773,0 0,-3e-5 -0.58616,1.27891 -0.58616,1.27891 -1.26187,2.55785 -3."
|
||||
"02251,4.55294 -5.22225,5.96828 -2.19973,1.41533 -4.82791,2.1848 -7.72679,2.1848 -3.76854,-1e-5 -6.57363,-1.21922 -8.31296,-3.62358 -1.72226,-2.35323 -2.09315,-5.60593 -1.17233,-9.69846 0.92083,-4.16073 2.7582,-7.48591 5.43539,-9.80502 2.39958,-2.0806"
|
||||
"2 5.12245,-3.23468 8.15309,-3.46372 z m 27.76315,0 c 0.37218,-0.0282 0.73857,0 1.11904,0 3.47867,0 6.1111,1.21922 7.83337,3.62359 1.07429,1.55174 1.65193,3.47012 1.65193,5.75512 0,1.2448 -0.1556,2.58341 -0.4796,4.0499 0,2e-5 -0.47958,1.91838 -0.47958"
|
||||
",1.91838 0,-2e-5 -15.63263,0 -17.37195,0 -0.0171,0.2387 -0.0362,0.45402 -0.0533,0.69275 -0.0128,0.0895 0.006,0.22541 0,0.31972 -5e-4,0.0154 0,0.0384 0,0.0533 0,0.2558 0.0362,0.5073 0.0533,0.74604 0.0852,0.97196 0.33892,1.78409 0.79932,2.39797 0.0877,"
|
||||
"0.11936 0.17008,0.2667 0.26644,0.37302 0.78101,0.83554 1.8864,1.27891 3.30387,1.27891 1.26188,-2e-5 2.38731,-0.34745 3.41045,-1.01248 0.98904,-0.63093 1.93542,-1.63914 2.77098,-3.03742 0,-3e-5 6.66102,0 6.66102,0 -1e-5,-3e-5 -0.63946,1.27891 -0.63946"
|
||||
",1.27891 -1.26186,2.55785 -3.0225,4.55294 -5.22224,5.96828 -2.19974,1.41533 -4.82791,2.1848 -7.72678,2.1848 -3.76853,-1e-5 -6.57363,-1.21922 -8.31296,-3.62358 -1.12545,-1.53472 -1.65194,-3.48931 -1.65194,-5.80841 0,-0.35812 0.0192,-0.74391 0.0533,-1."
|
||||
"11905 0.0682,-0.88671 0.20463,-1.78196 0.42631,-2.771 0.92084,-4.14368 2.70491,-7.48591 5.3821,-9.80502 2.39957,-2.08062 5.17575,-3.23468 8.20639,-3.46372 z m 75.61591,0 c 0.38084,-0.0293 0.73112,0 1.11905,0 3.54687,0 6.2731,1.20004 8.04652,3.5703 1."
|
||||
"7564,2.37023 2.18269,5.56754 1.27891,9.59186 -0.69913,3.13763 -1.70947,5.672 -3.0907,7.51365 -1.38126,1.84165 -3.14188,3.34649 -5.22226,4.36962 -2.06328,1.02314 -4.24813,1.54535 -6.44786,1.54535 -3.61507,-1e-5 -6.30719,-1.23628 -8.04652,-3.62358 -1.1"
|
||||
"2546,-1.51764 -1.70522,-3.47226 -1.70522,-5.80841 2e-5,-1.26187 0.13856,-2.6026 0.4796,-4.10319 1.02315,-4.57001 3.11202,-8.05078 6.18143,-10.28462 2.25301,-1.62634 4.74114,-2.56606 7.40705,-2.77098 z m 93.62733,0 c 0.4496,-0.0277 0.86593,0 1.3322,0 "
|
||||
"2.14859,0 3.83675,0.2174 5.11567,0.74602 1.36418,0.54569 2.33189,1.31729 2.87756,2.23811 0.52864,0.86963 0.79933,1.93756 0.79933,3.25057 10e-6,2e-5 -0.63948,3.89004 -0.63948,3.89004 3e-5,0 -1.17232,5.27554 -1.17232,5.27554 -1.00611,4.50176 -1.22776,6"
|
||||
".18995 -1.27893,6.82089 -0.0512,0.85262 0.0277,1.6839 0.26645,2.45125 2e-5,-2e-5 0.4263,1.38549 0.4263,1.38549 2e-5,-2e-5 -6.288,0 -6.288,0 -2e-5,-2e-5 -0.26645,-0.79933 -0.26645,-0.79933 -0.10231,-0.37512 -0.0725,-0.8526 -0.10657,-1.27891 -1.19365,0"
|
||||
".73325 -2.38944,1.38336 -3.46373,1.75851 -1.58584,0.54569 -3.23139,0.8526 -4.90251,0.8526 -2.89886,-1e-5 -5.04532,-0.75454 -6.3413,-2.2381 -0.98902,-1.09133 -1.43877,-2.42567 -1.43877,-3.94332 -2e-5,-0.57977 0.0767,-1.18087 0.21314,-1.81179 0.28988,-"
|
||||
"1.29597 0.81638,-2.49603 1.65194,-3.57032 0.81851,-1.05726 1.78623,-1.92689 2.87756,-2.55782 1.05726,-0.63092 2.23598,-1.07855 3.46374,-1.3855 -2e-5,0 3.78346,-0.63946 3.78346,-0.63946 2.91594,-0.34106 5.09221,-0.76521 6.66102,-1.22562 0.0341,-0.1705"
|
||||
"2 0.10657,-0.37302 0.10657,-0.37302 0.24726,-1.09718 0.21632,-1.92188 -0.0533,-2.34468 -0.0198,-0.0273 -0.0842,-0.0831 -0.10657,-0.10658 -0.0576,-0.0614 -0.14603,-0.15779 -0.21316,-0.21315 -0.64135,-0.50753 -1.73506,-0.74603 -3.19728,-0.74603 -1.6540"
|
||||
"7,0 -2.87756,0.27071 -3.73018,0.79931 -0.83555,0.52863 -1.60931,1.49634 -2.29139,2.87756 -1e-5,-1e-5 -6.44787,0 -6.44787,0 2e-5,-1e-5 0.58617,-1.27891 0.58617,-1.27891 0.76733,-1.77345 1.68178,-3.24418 2.82428,-4.36963 1.1425,-1.12547 2.68572,-1.9972"
|
||||
"4 4.4762,-2.61111 1.37216,-0.45297 2.8705,-0.75354 4.47621,-0.85261 z m 27.01711,0 c 0.24046,-0.0296 0.50356,0 0.74603,0 1.55173,0 3.00545,0.4668 4.36963,1.43877 2e-5,2e-5 0.79932,0.58617 0.79932,0.58617 1e-5,0 -3.30386,5.4354 -3.30386,5.4354 10e-6,-"
|
||||
"2e-5 -0.9059,-0.63946 -0.9059,-0.63946 -0.66503,-0.42629 -1.34501,-0.63946 -2.07824,-0.63946 -0.64801,2e-5 -1.28744,0.2302 -1.91839,0.63946 -0.64797,0.4263 -1.11904,0.99115 -1.54534,1.75851 -0.69916,1.31304 -1.24056,2.78377 -1.59865,4.36963 -2e-5,1e-"
|
||||
"5 -2.93085,13.10889 -2.93085,13.10889 2e-5,-2e-5 -6.18142,0 -6.18142,0 0,-2e-5 5.70182,-25.57832 5.70182,-25.57832 -10e-6,1e-5 5.75512,0 5.75512,0 0,1e-5 -0.14494,0.77588 -0.21314,1.06576 0.27282,-0.20461 0.54353,-0.48599 0.79932,-0.63946 0.81263,-0."
|
||||
"4929 1.64571,-0.80035 2.50455,-0.90589 z m 18.27783,0 c 0.37185,-0.0282 0.73859,0 1.11906,0 3.47866,0 6.12813,1.21922 7.83337,3.62359 1.09135,1.55174 1.65193,3.47012 1.65193,5.75512 -2e-5,1.26185 -0.2089,2.61965 -0.53289,4.10319 0,0 -0.4263,1.86509 -"
|
||||
"0.4263,1.86509 -10e-6,-2e-5 -15.64968,0 -17.37194,0 -0.0341,0.35808 -0.10659,0.74177 -0.10659,1.06576 0,1.33009 0.28989,2.37665 0.85262,3.14401 0.0877,0.11936 0.223,0.2667 0.31972,0.37302 0.056,0.0597 0.15412,0.15773 0.21316,0.21314 0.76235,0.69302 1"
|
||||
".79981,1.06577 3.0907,1.06577 1.26189,-2e-5 2.37027,-0.34745 3.41045,-1.01248 0.98905,-0.63093 1.91839,-1.63914 2.77099,-3.03742 -2e-5,-3e-5 6.66102,0 6.66102,0 0,-3e-5 -0.63946,1.27891 -0.63946,1.27891 -1.26187,2.55785 -3.03955,4.55294 -5.22224,5.96"
|
||||
"828 -2.21677,1.41533 -4.81085,2.1848 -7.72679,2.1848 -3.76851,-1e-5 -6.52034,-1.21922 -8.25966,-3.62358 -1.7223,-2.35323 -2.1294,-5.60593 -1.22563,-9.69846 0.92081,-4.16073 2.70491,-7.48591 5.38211,-9.80502 2.41475,-2.08062 5.17852,-3.23468 8.20637,-"
|
||||
"3.46372 z m -93.3076,0.47959 c 2e-5,1e-5 6.34131,0 6.34131,0 2e-5,1e-5 0.78226,15.17861 0.79931,15.40027 0.25578,-0.54356 0.45424,-1.00087 0.47961,-1.06575 1e-5,1e-5 6.98074,-14.33452 6.98074,-14.33452 2e-5,1e-5 5.80841,0 5.80841,0 -10e-6,1e-5 0.5328"
|
||||
"8,14.99528 0.53288,15.08054 0.17055,-0.30691 7.93994,-15.08054 7.93994,-15.08054 -2e-5,1e-5 6.28801,0 6.28801,0 -10e-6,1e-5 -13.85493,25.57832 -13.85493,25.57832 2e-5,-2e-5 -5.70183,0 -5.70183,0 0,-2e-5 -0.55206,-13.86984 -0.58617,-14.65426 -2.35323,"
|
||||
"4.8258 -7.14063,14.65426 -7.14063,14.65426 0,-2e-5 -5.86168,0 -5.86168,0 0,-2e-5 -2.02497,-25.57832 -2.02497,-25.57832 z m -148.88715,4.84922 c -1.46893,0.062 -2.80295,0.59149 -4.04989,1.59864 -0.98902,0.78441 -1.65621,1.86084 -2.18483,3.03743 0,2e-5"
|
||||
" 10.49777,0 10.49777,0 0.0171,-0.18756 0.0533,-0.41564 0.0533,-0.58617 -2e-5,-0.97195 -0.17266,-1.72653 -0.47959,-2.2381 -0.75028,-1.22777 -1.86295,-1.8118 -3.51702,-1.8118 -0.0991,0 -0.2218,-0.004 -0.31973,0 z m 27.76313,0 c -1.46892,0.062 -2.80295,"
|
||||
"0.59149 -4.0499,1.59864 -0.98904,0.78441 -1.63913,1.86084 -2.1848,3.03743 0,2e-5 10.49776,0 10.49776,0 0.017,-0.18756 0.0533,-0.41564 0.0533,-0.58617 -1e-5,-0.97195 -0.1556,-1.72653 -0.4796,-2.2381 -0.14894,-0.24939 -0.35043,-0.49739 -0.53288,-0.6927"
|
||||
"4 -0.71199,-0.73572 -1.6919,-1.11906 -2.98413,-1.11906 -0.0991,0 -0.2218,-0.004 -0.31974,0 z m 214.75136,0 c -1.51056,0.0465 -2.92125,0.55794 -4.20977,1.59864 -0.97198,0.78441 -1.63915,1.86084 -2.18482,3.03743 2e-5,2e-5 10.44449,0 10.44449,0 0.017,-0"
|
||||
".18756 0.0533,-0.41564 0.0533,-0.58617 -1e-5,-0.97195 -0.1556,-1.72653 -0.4796,-2.2381 -0.73324,-1.21072 -1.86296,-1.79474 -3.51702,-1.8118 -0.049,5.3e-4 -0.0578,-0.001 -0.10657,0 z m -139.61502,0.10658 c -1.40963,0.16739 -2.72036,0.81051 -3.94333,1."
|
||||
"91837 -1.46648,1.33009 -2.53012,3.41897 -3.14399,6.18143 -0.25579,1.15955 -0.37303,2.15071 -0.37303,3.03742 2e-5,1.2107 0.23233,2.16137 0.69275,2.87756 0.12257,0.18384 0.28516,0.37811 0.42631,0.53289 0.75804,0.80488 1.81659,1.22563 3.144,1.22563 1.72"
|
||||
"226,-2e-5 3.23992,-0.64159 4.68935,-1.97167 1.46652,-1.34714 2.51307,-3.45734 3.144,-6.288 0.5798,-2.59195 0.49878,-4.52736 -0.31972,-5.75512 -0.7844,-1.19366 -1.93116,-1.75851 -3.51701,-1.75851 -0.26911,0 -0.5383,-0.031 -0.79933,0 z m 96.29173,9.325"
|
||||
"43 c -1.44941,0.39218 -3.07367,0.72258 -5.22224,1.01248 -1.60289,0.23874 -2.74541,0.49024 -3.41045,0.74603 -0.57976,0.23872 -1.04658,0.56911 -1.43878,1.01248 -0.37516,0.42627 -0.62666,0.87392 -0.74602,1.38549 -0.0341,0.20464 -0.0533,0.41564 -0.0533,0"
|
||||
".58617 0,0.0138 -3.1e-4,0.0396 0,0.0533 0.002,0.0406 -0.004,0.1207 0,0.15985 0.0107,0.0774 0.0322,0.1944 0.0533,0.26645 0.008,0.0237 0.0445,0.0834 0.0533,0.10657 0.0187,0.0458 0.0301,0.11611 0.0533,0.15987 0.0243,0.0433 0.0779,0.11849 0.10658,0.15986"
|
||||
" 0.0446,0.0614 0.1055,0.1556 0.15987,0.21315 0.42631,0.47746 1.27678,0.69275 2.50454,0.69275 1.34715,1e-5 2.6431,-0.25578 3.83675,-0.85261 1.17662,-0.57977 2.12513,-1.44518 2.82427,-2.45126 0.51159,-0.7162 0.92083,-1.8182 1.27892,-3.25057 z\"/>\n"
|
||||
" <path id=\"path2\" style=\"fill:none;stroke:#bd0000;stroke-width:8.52610779;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;\" d=\"m 417.07944,250.20635 c 0.69221,1.77962 1.38445,3.55633 2.1055,5.2941 1.11046,2.36077 2.39396,4.6206 "
|
||||
"3.93704,6.73045 8.33557,11.33086 22.29546,17.53495 40.01931,19.07947 0,0 19.06506,0 19.06506,0 6.02811,-0.47014 12.34467,-1.34696 18.89198,-2.62759 11.29193,-2.2079 23.26167,-5.5998 35.69288,-10.13244 9.41715,-3.43375 19.0939,-7.49624 28.91485,-12.21"
|
||||
"778 21.38688,-10.25215 43.48041,-23.47509 65.15575,-39.43235 7.13857,-5.25082 13.98872,-10.63863 20.56487,-16.1173 6.02813,-5.01576 11.8111,-10.10942 17.33446,-15.25927 15.41645,-14.85689 27.0545,-29.94597 33.64507,-43.1949 6.86452,-13.7969 8.23461,-"
|
||||
"25.59358 2.61028,-33.02493 -3.44673,-4.56146 -9.21527,-7.00589 -16.64228,-7.5813 33.45753,-25.10471 52.95528,-55.55833 45.96096,-74.7589 -2.22096,-6.1277 -7.10981,-10.6992 -14.11858,-13.2273 -3.11497,-1.1205 -6.61943,-1.8301 -10.4411,-2.1531 0,0 -10."
|
||||
"29683,0 -10.29683,0 -14.37808,1.0369 -35.28664,6.1853 -53.0249,14.8785\"/>\n"
|
||||
" <g id=\"g2\" style=\"fill:#bd0000;fill-opacity:1\" transform=\"scale(1.705222,1.705222)\">\n"
|
||||
" <path id=\"path1\" transform=\"translate(15.5783,177.825)\" d=\"m 0,36 c 0,0 7.46,0 7.46,0 0,0 3.35,-14 3.35,-14 0,0 12.12,0 12.12,0 0,0 1.56,-6 1.56,-6 0,0 -12.17,0 -12.17,0 0,0 2.02,-9 2.02,-9 0,0 12.95,0 12.95,0 0,0 1.56,-7 1.56,-7 C 28.85,0"
|
||||
" 8.4,0 8.4,0 8.4,0 0,36 0,36 z\"/>\n"
|
||||
" <path id=\"path2\" transform=\"translate(41.5283,187.825)\" d=\"m 7.51,26 c 0,0 2.24,-9.4 2.24,-9.4 1.18,-5.09 3.67,-9.6 8.38,-9.6 0.42,0 0.83,0.21 1.14,0.26 0,0 1.82,-7.21 1.82,-7.21 -0.42,0 -0.88,-0.05 -1.4,-0.05 -3.47,0 -6.38,2.44 -8.32,5.94"
|
||||
" 0,0 -0.2,0 -0.2,0 C 11.46,4.23 11.71,2.61 11.9,1 11.9,1 5.47,1 5.47,1 5.1,3.08 4.53,7.15 3.66,10.82 3.66,10.82 0,26 0,26 c 0,0 7.51,0 7.51,0 z\"/>\n"
|
||||
" <path id=\"path3\" transform=\"translate(62.1583,187.825)\" d=\"M 20.06,19.25 C 17.99,20.26 15.63,20 12.88,20 10.71,20 9.03,19.62 8.11,18.88 7.63,18.07 7.43,16.81 7.47,16 17.6,16.27 23.99,13.93 24.31,7.53 24.55,2.7 21.02,0 15.89,0 6.73,0 0.73,8"
|
||||
".08 0.34,15.86 0,22.65 3.52,26 10.78,26 c 2.79,0 6.49,-0.32 9.52,-1.23 0,0 -0.24,-5.52 -0.24,-5.52 z M 17.32,7.53 C 17.2,9.91 14.26,10.05 8.47,10 9.1,7.91 11.22,6 14.69,6 c 1.71,0 2.69,0.65 2.63,1.53 z\"/>\n"
|
||||
" <path id=\"path4\" transform=\"translate(88.6783,187.825)\" d=\"M 20.05,19.25 C 17.98,20.26 15.62,20 12.88,20 10.7,20 9.03,19.62 8.11,18.88 7.63,18.07 7.42,16.81 7.46,16 17.6,16.27 23.98,13.93 24.31,7.53 24.55,2.7 21.02,0 15.89,0 6.72,0 0.72,8."
|
||||
"08 0.33,15.86 0,22.65 3.52,26 10.77,26 c 2.8,0 6.5,-0.32 9.53,-1.23 0,0 -0.25,-5.52 -0.25,-5.52 z M 17.32,7.53 C 17.2,9.91 14.26,10.05 8.46,10 9.1,7.91 11.21,6 14.68,6 c 1.71,0 2.7,0.65 2.64,1.53 z\"/>\n"
|
||||
" <path id=\"path5\" transform=\"translate(124.5883,187.825)\" d=\"M 22.74,26 C 22.8,22.83 23.56,17.85 24.35,14.58 24.35,14.58 27.56,1 27.56,1 25.52,0.31 22.34,0 19.28,0 6.86,0 0.7,9.2 0.27,17.82 0,23.23 2.93,26 7.49,26 c 2.95,0 6.28,-1.43 8.87,-"
|
||||
"5.73 0,0 0.11,0 0.11,0 -0.2,2.07 -0.44,4.08 -0.57,5.73 0,0 6.84,0 6.84,0 z M 17.61,11.72 C 16.15,18.08 13.17,20 10.95,20 8.88,20 7.98,18.53 8.1,16.39 8.34,11.56 12.16,6 16.98,6 c 0.78,0 1.39,-0.14 1.96,-0.28 0,0 -1.33,6 -1.33,6 z\"/>\n"
|
||||
" <path id=\"path6\" transform=\"translate(152.2183,187.825)\" d=\"m 0,24.82 c 1.44,1.12 4.46,1.13 7.61,1.18 6.73,0.05 11.81,-2.89 12.11,-8.29 0.17,-3.6 -2.62,-5.73 -5.35,-7.16 C 12.4,9.6 11.41,8.69 11.46,7.63 11.53,6.2 12.87,6 14.84,6 c 2.22,0 4"
|
||||
",0.27 5.02,0.47 0,0 2.02,-5.42 2.02,-5.42 C 20.73,0.36 18.43,0 15.48,0 8.95,0 4.17,3.45 3.9,8.69 c -0.16,3.24 2.17,5.42 4.99,6.9 2.28,1.17 3.06,2.07 3,3.34 C 11.82,20.21 10.68,20 8.61,20 6.18,20 3.49,19.68 2.07,19.46 2.07,19.46 0,24.82 0,24.82 z\"/>\n"
|
||||
" <path id=\"path7\" transform=\"translate(184.6683,176.825)\" d=\"m 7.45,37 c 0,0 6.05,-25 6.05,-25 0,0 -7.41,0 -7.41,0 0,0 -6.09,25 -6.09,25 0,0 7.45,0 7.45,0 z M 10.92,9 C 13.46,9 15.72,6.9 15.86,3.3 15.98,0.86 14.4,0 12.07,0 9.64,0 7.42,1.58 "
|
||||
"7.29,3.94 7.17,6.32 8.75,9 10.92,9 z\"/>\n"
|
||||
" <path id=\"path8\" transform=\"translate(198.9583,188.515)\" d=\"m 7.46,25.31 c 0,0 2.64,-11.26 2.64,-11.26 1.37,-5.73 4.32,-7.74 6.75,-7.74 1.92,0 2.48,0.82 2.39,2.01 -0.05,0.96 -0.2,1.97 -0.4,2.87 0,0 -3.36,14.12 -3.36,14.12 0,0 7.46,0 7.46,0"
|
||||
" 0,0 3.54,-14.81 3.54,-14.81 C 26.75,9.22 27.05,7.31 27.11,6.15 27.33,1.64 25.08,0 20.94,0 c -3.32,0 -6.55,1.54 -9.1,4.88 0,0 -0.1,0 -0.1,0 0,0 0.68,-4.57 0.68,-4.57 0,0 -6.58,0 -6.58,0 C 5.41,2.45 4.86,5.04 4.08,8.06 4.08,8.06 0,25.31 0,25.31 c 0,0 "
|
||||
"7.46,0 7.46,0 z\"/>\n"
|
||||
" <path id=\"path9\" transform=\"translate(238.5183,177.825)\" d=\"m 0,36 c 0,0 7.46,0 7.46,0 0,0 3.36,-14 3.36,-14 0,0 12.11,0 12.11,0 0,0 1.56,-6 1.56,-6 0,0 -12.17,0 -12.17,0 0,0 2.02,-9 2.02,-9 0,0 12.95,0 12.95,0 0,0 1.56,-7 1.56,-7 C 28.85,"
|
||||
"0 8.4,0 8.4,0 8.4,0 0,36 0,36 z\"/>\n"
|
||||
" <path id=\"path10\" transform=\"translate(264.4683,187.825)\" d=\"m 7.51,26 c 0,0 2.24,-9.4 2.24,-9.4 1.18,-5.09 3.67,-9.6 8.38,-9.6 0.42,0 0.83,0.21 1.14,0.26 0,0 1.82,-7.21 1.82,-7.21 -0.42,0 -0.88,-0.05 -1.4,-0.05 -3.47,0 -6.38,2.44 -8.32,5."
|
||||
"94 0,0 -0.2,0 -0.2,0 C 11.46,4.23 11.71,2.61 11.9,1 11.9,1 5.47,1 5.47,1 5.11,3.08 4.53,7.15 3.66,10.82 3.66,10.82 0,26 0,26 c 0,0 7.51,0 7.51,0 z\"/>\n"
|
||||
" <path id=\"path11\" transform=\"translate(285.0983,187.825)\" d=\"M 20.06,19.25 C 17.99,20.26 15.63,20 12.88,20 10.71,20 9.03,19.62 8.11,18.88 7.63,18.07 7.43,16.81 7.47,16 17.6,16.27 23.99,13.93 24.31,7.53 24.55,2.7 21.02,0 15.89,0 6.73,0 0.73"
|
||||
",8.08 0.34,15.86 0,22.65 3.53,26 10.78,26 c 2.79,0 6.5,-0.32 9.52,-1.23 0,0 -0.24,-5.52 -0.24,-5.52 z M 17.32,7.53 C 17.2,9.91 14.26,10.05 8.47,10 9.1,7.91 11.22,6 14.69,6 c 1.71,0 2.69,0.65 2.63,1.53 z\"/>\n"
|
||||
" <path id=\"path12\" transform=\"translate(311.6183,187.825)\" d=\"M 20.05,19.25 C 17.98,20.26 15.62,20 12.88,20 10.7,20 9.03,19.62 8.11,18.88 7.63,18.07 7.42,16.81 7.46,16 17.6,16.27 23.98,13.93 24.31,7.53 24.55,2.7 21.02,0 15.89,0 6.72,0 0.72,"
|
||||
"8.08 0.33,15.86 0,22.65 3.52,26 10.77,26 c 2.8,0 6.5,-0.32 9.53,-1.23 0,0 -0.25,-5.52 -0.25,-5.52 z M 17.32,7.53 C 17.2,9.91 14.26,10.05 8.46,10 9.1,7.91 11.21,6 14.68,6 c 1.71,0 2.7,0.65 2.64,1.53 z\"/>\n"
|
||||
" <path id=\"path13\" transform=\"translate(337.9983,176.825)\" d=\"M 23.31,0 C 23.31,0 20.5,11.36 20.5,11.36 19.48,10.94 18.15,11 17.11,11 7.53,11 0.75,19.2 0.3,28.08 0,34.34 3.34,37 7.64,37 c 3.01,0 6.18,-1.33 8.58,-4.77 0,0 0.1,0 0.1,0 0,0 -0."
|
||||
"57,4.77 -0.57,4.77 0,0 6.78,0 6.78,0 0.31,-3 0.96,-6.57 1.69,-9.83 0,0 6.49,-27.17 6.49,-27.17 0,0 -7.4,0 -7.4,0 z M 17.47,24.42 C 16.3,29.35 13.54,31 11.36,31 9.19,31 7.98,29.49 8.13,26.8 8.38,21.82 11.8,17 16.25,17 c 1.25,0 2.32,0.19 2.91,0.47 0,0 "
|
||||
"-1.69,6.95 -1.69,6.95 z\"/>\n"
|
||||
" <path id=\"path14\" transform=\"translate(367.7083,187.825)\" d=\"M 10.61,26 C 19.31,26 26.02,19.41 26.49,10.44 26.78,4.5 23.08,0 16.25,0 7.23,0 0.76,7.3 0.31,16.12 0,22.54 4.14,26 10.61,26 z m 1.17,-6 C 9.24,20 7.84,18.38 7.99,15.96 8.19,11.93"
|
||||
" 10.68,6 14.97,6 c 2.96,0 3.87,2.27 3.75,4.5 -0.22,4.4 -2.9,9.5 -6.94,9.5 z\"/>\n"
|
||||
" <path id=\"path15\" transform=\"translate(396.2683,187.825)\" d=\"M 7.2,26 C 7.2,26 9.9,14.58 9.9,14.58 11.03,9.49 13.85,6 16.38,6 c 1.82,0 2.32,1.33 2.23,3.07 -0.05,0.9 -0.25,1.91 -0.46,2.91 0,0 -3.34,14.02 -3.34,14.02 0,0 7.2,0 7.2,0 0,0 2.7,"
|
||||
"-11.47 2.7,-11.47 C 25.95,9.28 28.61,6 31.09,6 c 1.71,0 2.42,1.22 2.34,2.96 -0.05,1.01 -0.26,2.12 -0.52,3.13 0,0 -3.24,13.91 -3.24,13.91 0,0 7.25,0 7.25,0 0,0 3.49,-14.81 3.49,-14.81 0.27,-1.33 0.58,-3.4 0.63,-4.46 C 41.26,2.33 39.11,0 35.23,0 31.91,"
|
||||
"0 28.68,1.5 26.23,4.66 26.14,2.38 24.51,0 20.47,0 17.2,0 14.08,1.48 11.58,4.83 c 0,0 -0.1,0 -0.1,0 0,0 0.67,-3.83 0.67,-3.83 0,0 -6.42,0 -6.42,0 C 5.31,3.14 4.8,5.73 4.02,8.75 4.02,8.75 0,26 0,26 c 0,0 7.2,0 7.2,0 z\"/>\n"
|
||||
" </g>\n"
|
||||
" </g>\n"
|
||||
"</svg>";
|
||||
|
||||
const char* huckleberry_icon_svg = (const char*) temp_binary_data_17;
|
||||
const char* gpl_logo_svg = (const char*) temp_binary_data_17;
|
||||
|
||||
//================== juce-logo-with-text.svg ==================
|
||||
static const unsigned char temp_binary_data_18[] =
|
||||
|
|
@ -7720,7 +7791,7 @@ const char* getNamedResource (const char* resourceNameUTF8, int& numBytes)
|
|||
case 0x96d2a1ce: numBytes = 28184; return export_linux_svg;
|
||||
case 0x2505bd06: numBytes = 1706; return export_visualStudio_svg;
|
||||
case 0x3198e2bf: numBytes = 12295; return export_xcode_svg;
|
||||
case 0x0cd37295: numBytes = 3375; return huckleberry_icon_svg;
|
||||
case 0xc9c78dec: numBytes = 27030; return gpl_logo_svg;
|
||||
case 0x80b17530: numBytes = 5312; return jucelogowithtext_svg;
|
||||
case 0x154a7275: numBytes = 45854; return juce_icon_png;
|
||||
case 0x1f3b6d2f: numBytes = 5978; return wizard_AnimatedApp_svg;
|
||||
|
|
@ -7793,7 +7864,7 @@ const char* namedResourceList[] =
|
|||
"export_linux_svg",
|
||||
"export_visualStudio_svg",
|
||||
"export_xcode_svg",
|
||||
"huckleberry_icon_svg",
|
||||
"gpl_logo_svg",
|
||||
"jucelogowithtext_svg",
|
||||
"juce_icon_png",
|
||||
"wizard_AnimatedApp_svg",
|
||||
|
|
@ -7861,7 +7932,7 @@ const char* originalFilenames[] =
|
|||
"export_linux.svg",
|
||||
"export_visualStudio.svg",
|
||||
"export_xcode.svg",
|
||||
"huckleberry_icon.svg",
|
||||
"gpl_logo.svg",
|
||||
"juce-logo-with-text.svg",
|
||||
"juce_icon.png",
|
||||
"wizard_AnimatedApp.svg",
|
||||
|
|
|
|||
|
|
@ -59,8 +59,8 @@ namespace BinaryData
|
|||
extern const char* export_xcode_svg;
|
||||
const int export_xcode_svgSize = 12295;
|
||||
|
||||
extern const char* huckleberry_icon_svg;
|
||||
const int huckleberry_icon_svgSize = 3375;
|
||||
extern const char* gpl_logo_svg;
|
||||
const int gpl_logo_svgSize = 27030;
|
||||
|
||||
extern const char* jucelogowithtext_svg;
|
||||
const int jucelogowithtext_svgSize = 5312;
|
||||
|
|
|
|||
|
|
@ -101,6 +101,16 @@
|
|||
</EXPORTFORMATS>
|
||||
<MAINGROUP name="Projucer" id="NhrJq66R">
|
||||
<GROUP id="{9E4C4E0D-7BAB-EB6F-87DA-FB264EC2AE68}" name="Application">
|
||||
<GROUP id="{70333C48-4F84-A180-24E1-0EC9EF223F3B}" name="UserAccount">
|
||||
<FILE id="Rw7w0l" name="jucer_LicenseController.h" compile="0" resource="0"
|
||||
file="Source/Application/UserAccount/jucer_LicenseController.h"/>
|
||||
<FILE id="rUtPud" name="jucer_LicenseQueryThread.h" compile="0" resource="0"
|
||||
file="Source/Application/UserAccount/jucer_LicenseQueryThread.h"/>
|
||||
<FILE id="Dwndl3" name="jucer_LicenseState.h" compile="0" resource="0"
|
||||
file="Source/Application/UserAccount/jucer_LicenseState.h"/>
|
||||
<FILE id="d5kWEN" name="jucer_LoginFormComponent.h" compile="0" resource="0"
|
||||
file="Source/Application/UserAccount/jucer_LoginFormComponent.h"/>
|
||||
</GROUP>
|
||||
<GROUP id="{2F08ABDF-C7BB-5F54-55F5-0C2E27983930}" name="Windows">
|
||||
<FILE id="w1XB4w" name="jucer_AboutWindowComponent.h" compile="0" resource="0"
|
||||
file="Source/Application/Windows/jucer_AboutWindowComponent.h"/>
|
||||
|
|
@ -177,8 +187,7 @@
|
|||
file="Source/BinaryData/Icons/export_visualStudio.svg"/>
|
||||
<FILE id="G0oYd6" name="export_xcode.svg" compile="0" resource="1"
|
||||
file="Source/BinaryData/Icons/export_xcode.svg"/>
|
||||
<FILE id="k4zzKu" name="huckleberry_icon.svg" compile="0" resource="1"
|
||||
file="Source/BinaryData/Icons/huckleberry_icon.svg"/>
|
||||
<FILE id="CfDTJ0" name="gpl_logo.svg" compile="0" resource="1" file="Source/BinaryData/Icons/gpl_logo.svg"/>
|
||||
<FILE id="Pk2LIn" name="juce-logo-with-text.svg" compile="0" resource="1"
|
||||
file="Source/BinaryData/Icons/juce-logo-with-text.svg"/>
|
||||
<FILE id="Zrx1Gl" name="juce_icon.png" compile="0" resource="1" file="Source/BinaryData/Icons/juce_icon.png"/>
|
||||
|
|
@ -523,6 +532,15 @@
|
|||
file="Source/LiveBuildEngine/jucer_SourceCodeRange.h"/>
|
||||
</GROUP>
|
||||
<GROUP id="{6653587F-C475-46AA-E7CF-1D0DFA0FEAA9}" name="Project">
|
||||
<GROUP id="{F2E7D5CA-F002-2635-DA2C-898FA5EA2936}" name="Modules">
|
||||
<FILE id="w7QIJd" name="jucer_AvailableModulesList.h" compile="0" resource="0"
|
||||
file="Source/Project/Modules/jucer_AvailableModulesList.h"/>
|
||||
<FILE id="fQrJvA" name="jucer_ModuleDescription.h" compile="0" resource="0"
|
||||
file="Source/Project/Modules/jucer_ModuleDescription.h"/>
|
||||
<FILE id="mOC0iL" name="jucer_Modules.cpp" compile="1" resource="0"
|
||||
file="Source/Project/Modules/jucer_Modules.cpp"/>
|
||||
<FILE id="TnngL4" name="jucer_Modules.h" compile="0" resource="0" file="Source/Project/Modules/jucer_Modules.h"/>
|
||||
</GROUP>
|
||||
<GROUP id="{C37B7D1A-F059-9C82-9436-A2A94552BF90}" name="UI">
|
||||
<GROUP id="{19B83596-13BE-A80E-2722-BB5CCDA111FA}" name="Sidebar">
|
||||
<FILE id="bItg9o" name="jucer_ExporterTreeItems.h" compile="0" resource="0"
|
||||
|
|
@ -556,10 +574,11 @@
|
|||
resource="0" file="Source/Project/UI/jucer_ProjectContentComponent.cpp"/>
|
||||
<FILE id="z576fZ" name="jucer_ProjectContentComponent.h" compile="0"
|
||||
resource="0" file="Source/Project/UI/jucer_ProjectContentComponent.h"/>
|
||||
<FILE id="itkVli" name="jucer_ProjectMessagesComponent.h" compile="0"
|
||||
resource="0" file="Source/Project/UI/jucer_ProjectMessagesComponent.h"/>
|
||||
<FILE id="UUlUDF" name="jucer_UserAvatarComponent.h" compile="0" resource="0"
|
||||
file="Source/Project/UI/jucer_UserAvatarComponent.h"/>
|
||||
</GROUP>
|
||||
<FILE id="kPwhZB" name="jucer_Module.cpp" compile="1" resource="0"
|
||||
file="Source/Project/jucer_Module.cpp"/>
|
||||
<FILE id="YlGT8P" name="jucer_Module.h" compile="0" resource="0" file="Source/Project/jucer_Module.h"/>
|
||||
<FILE id="JT1rMJ" name="jucer_Project.cpp" compile="1" resource="0"
|
||||
file="Source/Project/jucer_Project.cpp"/>
|
||||
<FILE id="bUjtVS" name="jucer_Project.h" compile="0" resource="0" file="Source/Project/jucer_Project.h"/>
|
||||
|
|
|
|||
|
|
@ -0,0 +1,194 @@
|
|||
/*
|
||||
==============================================================================
|
||||
|
||||
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
|
||||
|
||||
#include "jucer_LicenseState.h"
|
||||
|
||||
//==============================================================================
|
||||
class LicenseController
|
||||
{
|
||||
public:
|
||||
LicenseController() = default;
|
||||
|
||||
//==============================================================================
|
||||
LicenseState getCurrentState() const noexcept
|
||||
{
|
||||
return state;
|
||||
}
|
||||
|
||||
void setState (const LicenseState& newState)
|
||||
{
|
||||
state = newState;
|
||||
licenseStateToSettings (state, getGlobalProperties());
|
||||
|
||||
stateListeners.call ([] (LicenseStateListener& l) { l.licenseStateChanged(); });
|
||||
}
|
||||
|
||||
void resetState()
|
||||
{
|
||||
setState ({});
|
||||
}
|
||||
|
||||
static LicenseState getGPLState()
|
||||
{
|
||||
static auto logoImage = []() -> Image
|
||||
{
|
||||
if (auto logo = Drawable::createFromImageData (BinaryData::gpl_logo_svg, BinaryData::gpl_logo_svgSize))
|
||||
{
|
||||
auto bounds = logo->getDrawableBounds();
|
||||
|
||||
Image image (Image::ARGB, roundToInt (bounds.getWidth()), roundToInt (bounds.getHeight()), true);
|
||||
Graphics g (image);
|
||||
logo->draw (g, 1.0f);
|
||||
|
||||
return image;
|
||||
}
|
||||
|
||||
jassertfalse;
|
||||
return {};
|
||||
}();
|
||||
|
||||
return { LicenseState::Type::gpl, {}, {}, logoImage };
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
struct LicenseStateListener
|
||||
{
|
||||
virtual ~LicenseStateListener() = default;
|
||||
virtual void licenseStateChanged() = 0;
|
||||
};
|
||||
|
||||
void addListener (LicenseStateListener* listenerToAdd)
|
||||
{
|
||||
stateListeners.add (listenerToAdd);
|
||||
}
|
||||
|
||||
void removeListener (LicenseStateListener* listenerToRemove)
|
||||
{
|
||||
stateListeners.remove (listenerToRemove);
|
||||
}
|
||||
|
||||
private:
|
||||
//==============================================================================
|
||||
static const char* getLicenseStateValue (LicenseState::Type type)
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case LicenseState::Type::gpl: return "GPL";
|
||||
case LicenseState::Type::personal: return "personal";
|
||||
case LicenseState::Type::educational: return "edu";
|
||||
case LicenseState::Type::indie: return "indie";
|
||||
case LicenseState::Type::pro: return "pro";
|
||||
case LicenseState::Type::none:
|
||||
default: break;
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
static LicenseState::Type getLicenseTypeFromValue (const String& d)
|
||||
{
|
||||
if (d == getLicenseStateValue (LicenseState::Type::gpl)) return LicenseState::Type::gpl;
|
||||
if (d == getLicenseStateValue (LicenseState::Type::personal)) return LicenseState::Type::personal;
|
||||
if (d == getLicenseStateValue (LicenseState::Type::educational)) return LicenseState::Type::educational;
|
||||
if (d == getLicenseStateValue (LicenseState::Type::indie)) return LicenseState::Type::indie;
|
||||
if (d == getLicenseStateValue (LicenseState::Type::pro)) return LicenseState::Type::pro;
|
||||
return LicenseState::Type::none;
|
||||
}
|
||||
|
||||
static Image avatarFromLicenseState (const String& licenseState)
|
||||
{
|
||||
MemoryOutputStream imageData;
|
||||
Base64::convertFromBase64 (imageData, licenseState);
|
||||
|
||||
return ImageFileFormat::loadFrom (imageData.getData(), imageData.getDataSize());
|
||||
}
|
||||
|
||||
static String avatarToLicenseState (Image avatarImage)
|
||||
{
|
||||
MemoryOutputStream imageData;
|
||||
|
||||
if (avatarImage.isValid() && PNGImageFormat().writeImageToStream (avatarImage, imageData))
|
||||
return Base64::toBase64 (imageData.getData(), imageData.getDataSize());
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
static LicenseState licenseStateFromSettings (PropertiesFile& props)
|
||||
{
|
||||
if (auto licenseXml = props.getXmlValue ("license"))
|
||||
{
|
||||
// this is here for backwards compatibility with old-style settings files using XML text elements
|
||||
if (licenseXml->getChildElementAllSubText ("type", {}).isNotEmpty())
|
||||
{
|
||||
auto stateFromOldSettings = [&licenseXml]() -> LicenseState
|
||||
{
|
||||
return { getLicenseTypeFromValue (licenseXml->getChildElementAllSubText ("type", {})),
|
||||
licenseXml->getChildElementAllSubText ("authToken", {}),
|
||||
licenseXml->getChildElementAllSubText ("username", {}),
|
||||
avatarFromLicenseState (licenseXml->getStringAttribute ("avatar", {})) };
|
||||
}();
|
||||
|
||||
licenseStateToSettings (stateFromOldSettings, props);
|
||||
|
||||
return stateFromOldSettings;
|
||||
}
|
||||
|
||||
return { getLicenseTypeFromValue (licenseXml->getStringAttribute ("type", {})),
|
||||
licenseXml->getStringAttribute ("authToken", {}),
|
||||
licenseXml->getStringAttribute ("username", {}),
|
||||
avatarFromLicenseState (licenseXml->getStringAttribute ("avatar", {})) };
|
||||
}
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
static void licenseStateToSettings (const LicenseState& state, PropertiesFile& props)
|
||||
{
|
||||
props.removeValue ("license");
|
||||
|
||||
if (state.isValid())
|
||||
{
|
||||
XmlElement licenseXml ("license");
|
||||
|
||||
if (auto* typeString = getLicenseStateValue (state.type))
|
||||
licenseXml.setAttribute ("type", typeString);
|
||||
|
||||
licenseXml.setAttribute ("authToken", state.authToken);
|
||||
licenseXml.setAttribute ("username", state.username);
|
||||
licenseXml.setAttribute ("avatar", avatarToLicenseState (state.avatar));
|
||||
|
||||
props.setValue ("license", &licenseXml);
|
||||
}
|
||||
|
||||
props.saveIfNeeded();
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
#if JUCER_ENABLE_GPL_MODE
|
||||
LicenseState state = getGPLState();
|
||||
#else
|
||||
LicenseState state = licenseStateFromSettings (getGlobalProperties());
|
||||
#endif
|
||||
|
||||
ListenerList<LicenseStateListener> stateListeners;
|
||||
|
||||
//==============================================================================
|
||||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (LicenseController)
|
||||
};
|
||||
|
|
@ -0,0 +1,274 @@
|
|||
/*
|
||||
==============================================================================
|
||||
|
||||
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
|
||||
|
||||
|
||||
//==============================================================================
|
||||
class LicenseQueryThread : public Thread
|
||||
{
|
||||
public:
|
||||
LicenseQueryThread (const String& userEmail, const String& userPassword,
|
||||
std::function<void(LicenseState, String)>&& cb)
|
||||
: Thread ("LicenseQueryThread"),
|
||||
email (userEmail),
|
||||
password (userPassword),
|
||||
completionCallback (std::move (cb))
|
||||
{
|
||||
startThread();
|
||||
}
|
||||
|
||||
~LicenseQueryThread() override
|
||||
{
|
||||
signalThreadShouldExit();
|
||||
waitForThreadToExit (-1);
|
||||
}
|
||||
|
||||
void run() override
|
||||
{
|
||||
LicenseState state;
|
||||
|
||||
auto errorMessage = runJob (std::make_unique<UserLogin> (email, password), state);
|
||||
|
||||
if (errorMessage.isEmpty())
|
||||
errorMessage = runJob (std::make_unique<UserLicenseQuery> (state.authToken), state);
|
||||
|
||||
if (errorMessage.isNotEmpty())
|
||||
state = {};
|
||||
|
||||
WeakReference<LicenseQueryThread> weakThis (this);
|
||||
MessageManager::callAsync ([this, weakThis, state, errorMessage]
|
||||
{
|
||||
if (weakThis != nullptr)
|
||||
completionCallback (state, errorMessage);
|
||||
});
|
||||
}
|
||||
|
||||
private:
|
||||
//==============================================================================
|
||||
struct AccountEnquiryBase
|
||||
{
|
||||
virtual ~AccountEnquiryBase() = default;
|
||||
|
||||
virtual bool isPOSTLikeRequest() const = 0;
|
||||
virtual String getEndpointURLSuffix() const = 0;
|
||||
virtual StringPairArray getParameterNamesAndValues() const = 0;
|
||||
virtual int getSuccessCode() const = 0;
|
||||
virtual String errorCodeToString (int) const = 0;
|
||||
virtual bool parseServerResponse (const String&, LicenseState&) = 0;
|
||||
};
|
||||
|
||||
struct UserLogin : public AccountEnquiryBase
|
||||
{
|
||||
UserLogin (const String& e, const String& p)
|
||||
: userEmail (e), userPassword (p)
|
||||
{
|
||||
}
|
||||
|
||||
bool isPOSTLikeRequest() const override { return true; }
|
||||
String getEndpointURLSuffix() const override { return "/authenticate"; }
|
||||
int getSuccessCode() const override { return 200; }
|
||||
|
||||
StringPairArray getParameterNamesAndValues() const override
|
||||
{
|
||||
StringPairArray namesAndValues;
|
||||
namesAndValues.set ("email", userEmail);
|
||||
namesAndValues.set ("password", userPassword);
|
||||
|
||||
return namesAndValues;
|
||||
}
|
||||
|
||||
String errorCodeToString (int errorCode) const override
|
||||
{
|
||||
switch (errorCode)
|
||||
{
|
||||
case 400: return "Please enter your email and password to log in.";
|
||||
case 401: return "Your email and password are incorrect.";
|
||||
case 451: return "Access denied.";
|
||||
default: return "Something went wrong, please try again.";
|
||||
}
|
||||
}
|
||||
|
||||
bool parseServerResponse (const String& serverResponse, LicenseState& licenseState) override
|
||||
{
|
||||
auto json = JSON::parse (serverResponse);
|
||||
|
||||
licenseState.authToken = json.getProperty ("token", {}).toString();
|
||||
licenseState.username = json.getProperty ("user", {}).getProperty ("username", {}).toString();
|
||||
|
||||
auto avatarURL = json.getProperty ("user", {}).getProperty ("avatar_url", {}).toString();
|
||||
|
||||
if (avatarURL.isNotEmpty())
|
||||
{
|
||||
URL url (avatarURL);
|
||||
|
||||
if (auto stream = url.createInputStream (false))
|
||||
{
|
||||
MemoryBlock mb;
|
||||
stream->readIntoMemoryBlock (mb);
|
||||
|
||||
licenseState.avatar = ImageFileFormat::loadFrom (mb.getData(), mb.getSize());
|
||||
}
|
||||
}
|
||||
|
||||
return (licenseState.authToken.isNotEmpty() && licenseState.username.isNotEmpty());
|
||||
}
|
||||
|
||||
String userEmail, userPassword;
|
||||
};
|
||||
|
||||
struct UserLicenseQuery : public AccountEnquiryBase
|
||||
{
|
||||
UserLicenseQuery (const String& authToken)
|
||||
: userAuthToken (authToken)
|
||||
{
|
||||
}
|
||||
|
||||
bool isPOSTLikeRequest() const override { return false; }
|
||||
String getEndpointURLSuffix() const override { return "/user/licences"; }
|
||||
int getSuccessCode() const override { return 200; }
|
||||
|
||||
StringPairArray getParameterNamesAndValues() const override
|
||||
{
|
||||
StringPairArray namesAndValues;
|
||||
namesAndValues.set ("token", userAuthToken);
|
||||
|
||||
return namesAndValues;
|
||||
}
|
||||
|
||||
String errorCodeToString (int errorCode) const override
|
||||
{
|
||||
switch (errorCode)
|
||||
{
|
||||
case 401: return "User not found or could not be verified.";
|
||||
default: return "User licenses info fetch failed (unknown error).";
|
||||
}
|
||||
}
|
||||
|
||||
bool parseServerResponse (const String& serverResponse, LicenseState& licenseState) override
|
||||
{
|
||||
auto json = JSON::parse (serverResponse);
|
||||
|
||||
if (auto* licensesJson = json.getArray())
|
||||
{
|
||||
StringArray licenseTypes;
|
||||
|
||||
for (auto& license : *licensesJson)
|
||||
{
|
||||
auto name = license.getProperty ("product_name", {}).toString();
|
||||
auto status = license.getProperty ("status", {}).toString();
|
||||
|
||||
if (name == "Projucer" && status == "active")
|
||||
licenseTypes.add (license.getProperty ("licence_type", {}).toString());
|
||||
}
|
||||
|
||||
licenseTypes.removeEmptyStrings();
|
||||
licenseTypes.removeDuplicates (false);
|
||||
|
||||
licenseState.type = [licenseTypes] ()
|
||||
{
|
||||
if (licenseTypes.contains ("juce-pro")) return LicenseState::Type::pro;
|
||||
else if (licenseTypes.contains ("juce-indie")) return LicenseState::Type::indie;
|
||||
else if (licenseTypes.contains ("juce-personal")) return LicenseState::Type::personal;
|
||||
else if (licenseTypes.contains ("juce-edu")) return LicenseState::Type::educational;
|
||||
|
||||
return LicenseState::Type::none;
|
||||
}();
|
||||
|
||||
return (licenseState.type != LicenseState::Type::none);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
String userAuthToken;
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
static String postDataStringAsJSON (const StringPairArray& parameters)
|
||||
{
|
||||
DynamicObject::Ptr d (new DynamicObject());
|
||||
|
||||
for (auto& key : parameters.getAllKeys())
|
||||
d->setProperty (key, parameters[key]);
|
||||
|
||||
return JSON::toString (var (d.get()));
|
||||
}
|
||||
|
||||
String runJob (std::unique_ptr<AccountEnquiryBase> accountEnquiryJob, LicenseState& state)
|
||||
{
|
||||
const String endpointURL = "https://api.roli.com/api/v1";
|
||||
const String extraHeaders = "Content-Type: application/json";
|
||||
|
||||
auto url = URL (endpointURL + accountEnquiryJob->getEndpointURLSuffix());
|
||||
|
||||
auto isPOST = accountEnquiryJob->isPOSTLikeRequest();
|
||||
|
||||
if (isPOST)
|
||||
url = url.withPOSTData (postDataStringAsJSON (accountEnquiryJob->getParameterNamesAndValues()));
|
||||
else
|
||||
url = url.withParameters (accountEnquiryJob->getParameterNamesAndValues());
|
||||
|
||||
if (threadShouldExit())
|
||||
return "Cancelled.";
|
||||
|
||||
int statusCode = 0;
|
||||
auto urlStream = url.createInputStream (isPOST, nullptr, nullptr, extraHeaders, 0, nullptr, &statusCode);
|
||||
|
||||
if (urlStream == nullptr)
|
||||
return "Failed to connect to the web server.";
|
||||
|
||||
if (statusCode != accountEnquiryJob->getSuccessCode())
|
||||
return accountEnquiryJob->errorCodeToString (statusCode);
|
||||
|
||||
if (threadShouldExit())
|
||||
return "Cancelled.";
|
||||
|
||||
String response;
|
||||
|
||||
for (;;)
|
||||
{
|
||||
char buffer [8192];
|
||||
auto num = urlStream->read (buffer, sizeof (buffer));
|
||||
|
||||
if (threadShouldExit())
|
||||
return "Cancelled.";
|
||||
|
||||
if (num <= 0)
|
||||
break;
|
||||
|
||||
response += buffer;
|
||||
}
|
||||
|
||||
if (threadShouldExit())
|
||||
return "Cancelled.";
|
||||
|
||||
if (! accountEnquiryJob->parseServerResponse (response, state))
|
||||
return "Failed to parse server response.";
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
const String email, password;
|
||||
const std::function<void(LicenseState, String)> completionCallback;
|
||||
|
||||
//==============================================================================
|
||||
JUCE_DECLARE_WEAK_REFERENCEABLE (LicenseQueryThread)
|
||||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (LicenseQueryThread)
|
||||
};
|
||||
|
|
@ -0,0 +1,68 @@
|
|||
/*
|
||||
==============================================================================
|
||||
|
||||
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 LicenseState
|
||||
{
|
||||
enum class Type
|
||||
{
|
||||
none,
|
||||
gpl,
|
||||
personal,
|
||||
educational,
|
||||
indie,
|
||||
pro
|
||||
};
|
||||
|
||||
LicenseState() = default;
|
||||
|
||||
LicenseState (Type t, String token, String user, Image avatarImage)
|
||||
: type (t), authToken (token), username (user), avatar (avatarImage)
|
||||
{
|
||||
}
|
||||
|
||||
bool isValid() const noexcept { return isGPL() || (type != Type::none && authToken.isNotEmpty() && username.isNotEmpty()); }
|
||||
|
||||
bool isPaid() const noexcept { return type == Type::indie || type == Type::pro; }
|
||||
bool isGPL() const noexcept { return type == Type::gpl; }
|
||||
bool isPaidOrGPL() const noexcept { return isPaid() || isGPL(); }
|
||||
|
||||
String getLicenseTypeString() const
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case Type::none: return "No license";
|
||||
case Type::gpl: return "GPL";
|
||||
case Type::personal: return "Personal";
|
||||
case Type::educational: return "Educational";
|
||||
case Type::indie: return "Indie";
|
||||
case Type::pro: return "Pro";
|
||||
default: break;
|
||||
};
|
||||
|
||||
jassertfalse;
|
||||
return {};
|
||||
}
|
||||
|
||||
Type type = Type::none;
|
||||
String authToken, username;
|
||||
Image avatar;
|
||||
};
|
||||
|
|
@ -0,0 +1,273 @@
|
|||
/*
|
||||
==============================================================================
|
||||
|
||||
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
|
||||
|
||||
#include "jucer_LicenseQueryThread.h"
|
||||
#include "../../Project/UI/jucer_UserAvatarComponent.h"
|
||||
|
||||
//==============================================================================
|
||||
class LoginFormComponent : public Component
|
||||
{
|
||||
public:
|
||||
LoginFormComponent (MainWindow& window)
|
||||
: mainWindow (window)
|
||||
{
|
||||
addAndMakeVisible (emailBox);
|
||||
emailBox.setTextToShowWhenEmpty ("Email", Colours::black.withAlpha (0.2f));
|
||||
emailBox.setJustification (Justification::centredLeft);
|
||||
emailBox.onReturnKey = [this] { submitDetails(); };
|
||||
|
||||
addAndMakeVisible (passwordBox);
|
||||
passwordBox.setTextToShowWhenEmpty ("Password", Colours::black.withAlpha (0.2f));
|
||||
passwordBox.setPasswordCharacter ((juce_wchar) 0x2022);
|
||||
passwordBox.setJustification (Justification::centredLeft);
|
||||
passwordBox.onReturnKey = [this] { submitDetails(); };
|
||||
|
||||
addAndMakeVisible (logInButton);
|
||||
logInButton.onClick = [this] { submitDetails(); };
|
||||
|
||||
addAndMakeVisible (enableGPLButton);
|
||||
enableGPLButton.onClick = [this]
|
||||
{
|
||||
ProjucerApplication::getApp().getLicenseController().setState (LicenseController::getGPLState());
|
||||
mainWindow.hideLoginFormOverlay();
|
||||
};
|
||||
|
||||
addAndMakeVisible (userAvatar);
|
||||
|
||||
addAndMakeVisible (createAccountLabel);
|
||||
createAccountLabel.setFont (Font (14.0f, Font::underlined));
|
||||
createAccountLabel.addMouseListener (this, false);
|
||||
createAccountLabel.setMouseCursor (MouseCursor::PointingHandCursor);
|
||||
|
||||
addAndMakeVisible (errorMessageLabel);
|
||||
errorMessageLabel.setMinimumHorizontalScale (1.0f);
|
||||
errorMessageLabel.setFont (12.0f);
|
||||
errorMessageLabel.setColour (Label::textColourId, Colours::red);
|
||||
errorMessageLabel.setVisible (false);
|
||||
|
||||
dismissButton.setShape (getLookAndFeel().getCrossShape (1.0f), false, true, false);
|
||||
addAndMakeVisible (dismissButton);
|
||||
dismissButton.onClick = [this] { mainWindow.hideLoginFormOverlay(); };
|
||||
|
||||
setWantsKeyboardFocus (true);
|
||||
setOpaque (true);
|
||||
|
||||
lookAndFeelChanged();
|
||||
|
||||
setSize (300, 350);
|
||||
}
|
||||
|
||||
void resized() override
|
||||
{
|
||||
auto bounds = getLocalBounds().reduced (20);
|
||||
auto spacing = bounds.getHeight() / 20;
|
||||
|
||||
userAvatar.setBounds (bounds.removeFromTop (iconHeight).reduced ((bounds.getWidth() / 2) - (iconHeight / 2), 0));
|
||||
|
||||
errorMessageLabel.setBounds (bounds.removeFromTop (spacing));
|
||||
bounds.removeFromTop (spacing / 2);
|
||||
|
||||
auto textEditorHeight = bounds.getHeight() / 5;
|
||||
|
||||
emailBox.setBounds (bounds.removeFromTop (textEditorHeight));
|
||||
bounds.removeFromTop (spacing);
|
||||
|
||||
passwordBox.setBounds (bounds.removeFromTop (textEditorHeight));
|
||||
bounds.removeFromTop (spacing * 2);
|
||||
|
||||
emailBox.setFont (Font (textEditorHeight / 2.5f));
|
||||
passwordBox.setFont (Font (textEditorHeight / 2.5f));
|
||||
|
||||
logInButton.setBounds (bounds.removeFromTop (textEditorHeight));
|
||||
|
||||
auto slice = bounds.removeFromTop (textEditorHeight);
|
||||
createAccountLabel.setBounds (slice.removeFromLeft (createAccountLabel.getFont().getStringWidth (createAccountLabel.getText()) + 5));
|
||||
slice.removeFromLeft (15);
|
||||
enableGPLButton.setBounds (slice.reduced (0, 5));
|
||||
|
||||
dismissButton.setBounds (getLocalBounds().reduced (10).removeFromTop (20).removeFromRight (20));
|
||||
}
|
||||
|
||||
void paint (Graphics& g) override
|
||||
{
|
||||
g.fillAll (findColour (secondaryBackgroundColourId).contrasting (0.1f));
|
||||
}
|
||||
|
||||
void mouseUp (const MouseEvent& event) override
|
||||
{
|
||||
if (event.eventComponent == &createAccountLabel)
|
||||
URL ("https://auth.roli.com/register").launchInDefaultBrowser();
|
||||
}
|
||||
|
||||
void lookAndFeelChanged() override
|
||||
{
|
||||
enableGPLButton.setColour (TextButton::buttonColourId, findColour (secondaryButtonBackgroundColourId));
|
||||
}
|
||||
|
||||
private:
|
||||
class ProgressButton : public TextButton,
|
||||
private Timer
|
||||
{
|
||||
public:
|
||||
ProgressButton (const String& buttonName)
|
||||
: TextButton (buttonName), text (buttonName)
|
||||
{
|
||||
}
|
||||
|
||||
void setBusy (bool shouldBeBusy)
|
||||
{
|
||||
isInProgress = shouldBeBusy;
|
||||
|
||||
if (isInProgress)
|
||||
{
|
||||
setEnabled (false);
|
||||
setButtonText ({});
|
||||
startTimerHz (30);
|
||||
}
|
||||
else
|
||||
{
|
||||
setEnabled (true);
|
||||
setButtonText (text);
|
||||
stopTimer();
|
||||
}
|
||||
}
|
||||
|
||||
void paint (Graphics& g) override
|
||||
{
|
||||
TextButton::paint (g);
|
||||
|
||||
if (isInProgress)
|
||||
{
|
||||
auto size = getHeight() - 10;
|
||||
auto halfSize = size / 2;
|
||||
|
||||
getLookAndFeel().drawSpinningWaitAnimation (g, Colours::white,
|
||||
(getWidth() / 2) - halfSize, (getHeight() / 2) - halfSize,
|
||||
size, size);
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
void timerCallback() override
|
||||
{
|
||||
repaint();
|
||||
}
|
||||
|
||||
String text;
|
||||
bool isInProgress = false;
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
void updateLoginButtonStates (bool isLoggingIn)
|
||||
{
|
||||
logInButton.setBusy (isLoggingIn);
|
||||
|
||||
emailBox.setEnabled (! isLoggingIn);
|
||||
passwordBox.setEnabled (! isLoggingIn);
|
||||
}
|
||||
|
||||
void submitDetails()
|
||||
{
|
||||
if ((licenseQueryThread != nullptr && licenseQueryThread->isThreadRunning()))
|
||||
return;
|
||||
|
||||
auto loginFormError = checkLoginFormsAreValid();
|
||||
|
||||
if (loginFormError.isNotEmpty())
|
||||
{
|
||||
showErrorMessage (loginFormError);
|
||||
return;
|
||||
}
|
||||
|
||||
updateLoginButtonStates (true);
|
||||
|
||||
WeakReference<Component> weakThis (this);
|
||||
licenseQueryThread.reset (new LicenseQueryThread (emailBox.getText(), passwordBox.getText(),
|
||||
[this, weakThis] (LicenseState newState, String errorMessage)
|
||||
{
|
||||
if (weakThis == nullptr)
|
||||
return;
|
||||
|
||||
updateLoginButtonStates (false);
|
||||
|
||||
if (errorMessage.isNotEmpty())
|
||||
{
|
||||
showErrorMessage (errorMessage);
|
||||
}
|
||||
else
|
||||
{
|
||||
hideErrorMessage();
|
||||
|
||||
auto& licenseController = ProjucerApplication::getApp().getLicenseController();
|
||||
licenseController.setState (newState);
|
||||
mainWindow.hideLoginFormOverlay();
|
||||
|
||||
ProjucerApplication::getApp().getCommandManager().commandStatusChanged();
|
||||
}
|
||||
}));
|
||||
}
|
||||
|
||||
String checkLoginFormsAreValid() const
|
||||
{
|
||||
auto email = emailBox.getText();
|
||||
|
||||
if (email.isEmpty() || email.indexOfChar ('@') < 0)
|
||||
return "Please enter a valid email.";
|
||||
|
||||
auto password = passwordBox.getText();
|
||||
|
||||
if (password.isEmpty() || password.length() < 8)
|
||||
return "Please enter a valid password.";
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
void showErrorMessage (const String& errorMessage)
|
||||
{
|
||||
errorMessageLabel.setText (errorMessage, dontSendNotification);
|
||||
errorMessageLabel.setVisible (true);
|
||||
}
|
||||
|
||||
void hideErrorMessage()
|
||||
{
|
||||
errorMessageLabel.setText ({}, dontSendNotification);
|
||||
errorMessageLabel.setVisible (false);
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
static constexpr int iconHeight = 50;
|
||||
|
||||
MainWindow& mainWindow;
|
||||
|
||||
TextEditor emailBox, passwordBox;
|
||||
ProgressButton logInButton { "Log In" };
|
||||
TextButton enableGPLButton { "Enable GPL Mode" };
|
||||
ShapeButton dismissButton { {},
|
||||
findColour (treeIconColourId),
|
||||
findColour (treeIconColourId).overlaidWith (findColour (defaultHighlightedTextColourId).withAlpha (0.2f)),
|
||||
findColour (treeIconColourId).overlaidWith (findColour (defaultHighlightedTextColourId).withAlpha (0.4f)) };
|
||||
UserAvatarComponent userAvatar { false, false };
|
||||
Label createAccountLabel { {}, "Create an account" },
|
||||
errorMessageLabel { {}, {} };
|
||||
|
||||
std::unique_ptr<LicenseQueryThread> licenseQueryThread;
|
||||
|
||||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (LoginFormComponent)
|
||||
};
|
||||
|
|
@ -50,23 +50,15 @@ public:
|
|||
auto bounds = getLocalBounds();
|
||||
bounds.removeFromBottom (20);
|
||||
|
||||
auto rightSlice = bounds.removeFromRight (150);
|
||||
auto leftSlice = bounds.removeFromLeft (150);
|
||||
auto centreSlice = bounds;
|
||||
auto centreSlice = bounds.withTrimmedRight (150);
|
||||
|
||||
//==============================================================================
|
||||
rightSlice.removeFromRight (20);
|
||||
auto iconSlice = rightSlice.removeFromRight (100);
|
||||
huckleberryLogoBounds = iconSlice.removeFromBottom (100).toFloat();
|
||||
|
||||
//==============================================================================
|
||||
juceLogoBounds = leftSlice.removeFromTop (150).toFloat();
|
||||
juceLogoBounds.setWidth (juceLogoBounds.getWidth() + 100);
|
||||
juceLogoBounds.setHeight (juceLogoBounds.getHeight() + 100);
|
||||
|
||||
copyrightLabel.setBounds (leftSlice.removeFromBottom (20));
|
||||
|
||||
//==============================================================================
|
||||
auto titleHeight = 40;
|
||||
|
||||
centreSlice.removeFromTop ((centreSlice.getHeight() / 2) - (titleHeight / 2));
|
||||
|
|
@ -86,9 +78,6 @@ public:
|
|||
|
||||
if (juceLogo != nullptr)
|
||||
juceLogo->drawWithin (g, juceLogoBounds.translated (-75, -75), RectanglePlacement::centred, 1.0);
|
||||
|
||||
if (huckleberryLogo != nullptr)
|
||||
huckleberryLogo->drawWithin (g, huckleberryLogoBounds, RectanglePlacement::centred, 1.0);
|
||||
}
|
||||
|
||||
private:
|
||||
|
|
@ -98,13 +87,10 @@ private:
|
|||
|
||||
HyperlinkButton aboutButton { "About Us", URL ("https://juce.com") };
|
||||
|
||||
Rectangle<float> huckleberryLogoBounds, juceLogoBounds;
|
||||
Rectangle<float> juceLogoBounds;
|
||||
|
||||
std::unique_ptr<Drawable> juceLogo { Drawable::createFromImageData (BinaryData::juce_icon_png,
|
||||
BinaryData::juce_icon_pngSize) };
|
||||
|
||||
std::unique_ptr<Drawable> huckleberryLogo { Drawable::createFromImageData (BinaryData::huckleberry_icon_svg,
|
||||
BinaryData::huckleberry_icon_svgSize) };
|
||||
|
||||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (AboutWindowComponent)
|
||||
};
|
||||
|
|
|
|||
|
|
@ -23,7 +23,8 @@
|
|||
//==============================================================================
|
||||
class GlobalPathsWindowComponent : public Component,
|
||||
private Timer,
|
||||
private Value::Listener
|
||||
private Value::Listener,
|
||||
private ChangeListener
|
||||
{
|
||||
public:
|
||||
GlobalPathsWindowComponent()
|
||||
|
|
@ -42,6 +43,16 @@ public:
|
|||
lastUserModulePath = getAppSettings().getStoredPath (Ids::defaultUserModulePath, TargetOS::getThisOS()).get();
|
||||
};
|
||||
|
||||
addChildComponent (warnAboutJUCEPathButton);
|
||||
warnAboutJUCEPathButton.setToggleState (ProjucerApplication::getApp().shouldPromptUserAboutIncorrectJUCEPath(),
|
||||
dontSendNotification);
|
||||
warnAboutJUCEPathButton.onClick = [this]
|
||||
{
|
||||
ProjucerApplication::getApp().setShouldPromptUserAboutIncorrectJUCEPath (warnAboutJUCEPathButton.getToggleState());
|
||||
};
|
||||
|
||||
getGlobalProperties().addChangeListener (this);
|
||||
|
||||
addAndMakeVisible (resetToDefaultsButton);
|
||||
resetToDefaultsButton.onClick = [this] { resetCurrentOSPathsToDefaults(); };
|
||||
|
||||
|
|
@ -64,6 +75,8 @@ public:
|
|||
|
||||
~GlobalPathsWindowComponent() override
|
||||
{
|
||||
getGlobalProperties().removeChangeListener (this);
|
||||
|
||||
auto juceValue = getAppSettings().getStoredPath (Ids::defaultJuceModulePath, TargetOS::getThisOS());
|
||||
auto userValue = getAppSettings().getStoredPath (Ids::defaultUserModulePath, TargetOS::getThisOS());
|
||||
|
||||
|
|
@ -86,12 +99,15 @@ public:
|
|||
{
|
||||
auto b = getLocalBounds().reduced (10);
|
||||
|
||||
auto buttonBounds = b.removeFromBottom (50);
|
||||
auto bottomBounds = b.removeFromBottom (80);
|
||||
auto buttonBounds = bottomBounds.removeFromBottom (50);
|
||||
|
||||
rescanJUCEPathButton.setBounds (buttonBounds.removeFromLeft (150).reduced (5, 10));
|
||||
rescanUserPathButton.setBounds (buttonBounds.removeFromLeft (150).reduced (5, 10));
|
||||
|
||||
resetToDefaultsButton.setBounds (buttonBounds.removeFromRight (150).reduced (5, 10));
|
||||
warnAboutJUCEPathButton.setBounds (bottomBounds.reduced (0, 5));
|
||||
warnAboutJUCEPathButton.changeWidthToFitText();
|
||||
|
||||
propertyGroup.updateSize (0, 0, getWidth() - 20 - propertyViewport.getScrollBarThickness());
|
||||
propertyViewport.setBounds (b);
|
||||
|
|
@ -145,6 +161,12 @@ private:
|
|||
resized();
|
||||
}
|
||||
|
||||
void changeListenerCallback (ChangeBroadcaster*) override
|
||||
{
|
||||
warnAboutJUCEPathButton.setToggleState (ProjucerApplication::getApp().shouldPromptUserAboutIncorrectJUCEPath(),
|
||||
dontSendNotification);
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
bool isSelectedOSThisOS() { return TargetOS::getThisOS() == getSelectedOS(); }
|
||||
|
||||
|
|
@ -223,15 +245,11 @@ private:
|
|||
"This path will be used for the \"Save Project and Open in IDE...\" option of the CLion exporter.");
|
||||
builder.add (new FilePathPropertyComponent (androidStudioExePathValue, "Android Studio " + exeLabel, false, isThisOS),
|
||||
"This path will be used for the \"Save Project and Open in IDE...\" option of the Android Studio exporter.");
|
||||
}
|
||||
|
||||
rescanJUCEPathButton.setVisible (true);
|
||||
rescanUserPathButton.setVisible (true);
|
||||
}
|
||||
else
|
||||
{
|
||||
rescanJUCEPathButton.setVisible (false);
|
||||
rescanUserPathButton.setVisible (false);
|
||||
}
|
||||
rescanJUCEPathButton.setVisible (isThisOS);
|
||||
rescanUserPathButton.setVisible (isThisOS);
|
||||
warnAboutJUCEPathButton.setVisible (isThisOS);
|
||||
|
||||
propertyGroup.setProperties (builder);
|
||||
}
|
||||
|
|
@ -279,6 +297,7 @@ private:
|
|||
Viewport propertyViewport;
|
||||
PropertyGroupComponent propertyGroup { "Global Paths", { getIcons().openFolder, Colours::transparentBlack } };
|
||||
|
||||
ToggleButton warnAboutJUCEPathButton { "Warn about incorrect JUCE path" };
|
||||
TextButton rescanJUCEPathButton { "Re-scan JUCE Modules" },
|
||||
rescanUserPathButton { "Re-scan User Modules" },
|
||||
resetToDefaultsButton { "Reset to Defaults" };
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
|
||||
//==============================================================================
|
||||
static String getWidthLimitedStringFromVarArray (const var& varArray) noexcept
|
||||
{
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@
|
|||
==============================================================================
|
||||
*/
|
||||
|
||||
void createGUIEditorMenu (PopupMenu&);
|
||||
PopupMenu createGUIEditorMenu();
|
||||
void handleGUIEditorMenuCommand (int);
|
||||
void registerGUIEditorCommands();
|
||||
|
||||
|
|
@ -36,9 +36,7 @@ struct ProjucerApplication::MainMenuModel : public MenuBarModel
|
|||
|
||||
PopupMenu getMenuForIndex (int /*topLevelMenuIndex*/, const String& menuName) override
|
||||
{
|
||||
PopupMenu menu;
|
||||
getApp().createMenu (menu, menuName);
|
||||
return menu;
|
||||
return getApp().createMenu (menuName);
|
||||
}
|
||||
|
||||
void menuItemSelected (int menuItemID, int /*topLevelMenuIndex*/) override
|
||||
|
|
@ -48,10 +46,6 @@ struct ProjucerApplication::MainMenuModel : public MenuBarModel
|
|||
};
|
||||
|
||||
//==============================================================================
|
||||
ProjucerApplication::ProjucerApplication() : isRunningCommandLine (false)
|
||||
{
|
||||
}
|
||||
|
||||
void ProjucerApplication::initialise (const String& commandLine)
|
||||
{
|
||||
if (commandLine.trimStart().startsWith ("--server"))
|
||||
|
|
@ -99,22 +93,6 @@ void ProjucerApplication::initialise (const String& commandLine)
|
|||
return;
|
||||
}
|
||||
|
||||
rescanJUCEPathModules();
|
||||
rescanUserPathModules();
|
||||
|
||||
openDocumentManager.registerType (new ProjucerAppClasses::LiveBuildCodeEditorDocument::Type(), 2);
|
||||
|
||||
childProcessCache.reset (new ChildProcessCache());
|
||||
|
||||
initCommandManager();
|
||||
menuModel.reset (new MainMenuModel());
|
||||
|
||||
settings->appearance.refreshPresetSchemeList();
|
||||
|
||||
setColourScheme (settings->getGlobalProperties().getIntValue ("COLOUR SCHEME"), false);
|
||||
setEditorColourScheme (settings->getGlobalProperties().getIntValue ("EDITOR COLOUR SCHEME"), false);
|
||||
updateEditorColourSchemeIfNeeded();
|
||||
|
||||
// do further initialisation in a moment when the message loop has started
|
||||
triggerAsyncUpdate();
|
||||
}
|
||||
|
|
@ -153,29 +131,37 @@ void ProjucerApplication::initialiseWindows (const String& commandLine)
|
|||
|
||||
void ProjucerApplication::handleAsyncUpdate()
|
||||
{
|
||||
licenseController = std::make_unique<LicenseController>();
|
||||
|
||||
LookAndFeel::setDefaultLookAndFeel (&lookAndFeel);
|
||||
|
||||
rescanJUCEPathModules();
|
||||
rescanUserPathModules();
|
||||
|
||||
openDocumentManager.registerType (new ProjucerAppClasses::LiveBuildCodeEditorDocument::Type(), 2);
|
||||
childProcessCache.reset (new ChildProcessCache());
|
||||
|
||||
initCommandManager();
|
||||
menuModel.reset (new MainMenuModel());
|
||||
|
||||
#if JUCE_MAC
|
||||
rebuildAppleMenu();
|
||||
appleMenuRebuildListener = std::make_unique<AppleMenuRebuildListener>();
|
||||
#endif
|
||||
|
||||
settings->appearance.refreshPresetSchemeList();
|
||||
setColourScheme (getGlobalProperties().getIntValue ("COLOUR SCHEME"), false);
|
||||
setEditorColourScheme (getGlobalProperties().getIntValue ("EDITOR COLOUR SCHEME"), false);
|
||||
updateEditorColourSchemeIfNeeded();
|
||||
|
||||
ImageCache::setCacheTimeout (30 * 1000);
|
||||
icons = std::make_unique<Icons>();
|
||||
|
||||
tooltipWindow = std::make_unique<TooltipWindow> (nullptr, 1200);
|
||||
|
||||
#if JUCE_MAC
|
||||
PopupMenu extraAppleMenuItems;
|
||||
createExtraAppleMenuItems (extraAppleMenuItems);
|
||||
|
||||
// workaround broken "Open Recent" submenu: not passing the
|
||||
// submenu's title here avoids the defect in JuceMainMenuHandler::addMenuItem
|
||||
MenuBarModel::setMacMainMenu (menuModel.get(), &extraAppleMenuItems); //, "Open Recent");
|
||||
#endif
|
||||
|
||||
if (getGlobalProperties().getValue (Ids::dontQueryForUpdate, {}).isEmpty())
|
||||
LatestVersionCheckerAndUpdater::getInstance()->checkForNewVersion (false);
|
||||
if (isAutomaticVersionCheckingEnabled())
|
||||
LatestVersionCheckerAndUpdater::getInstance()->checkForNewVersion (true);
|
||||
|
||||
initialiseWindows (getCommandLineParameters());
|
||||
|
||||
if (! isRunningCommandLine && settings->shouldAskUserToSetJUCEPath())
|
||||
showSetJUCEPathAlert();
|
||||
}
|
||||
|
||||
static void deleteTemporaryFiles()
|
||||
|
|
@ -314,25 +300,52 @@ MenuBarModel* ProjucerApplication::getMenuModel()
|
|||
|
||||
StringArray ProjucerApplication::getMenuNames()
|
||||
{
|
||||
return { "File", "Edit", "View", "Build", "Window", "Document", "GUI Editor", "Tools", "Help" };
|
||||
StringArray currentMenuNames { "File", "Edit", "View", "Build", "Window", "Document", "GUI Editor", "Tools", "Help" };
|
||||
|
||||
if (! isLiveBuildEnabled()) currentMenuNames.removeString ("Build");
|
||||
if (! isGUIEditorEnabled()) currentMenuNames.removeString ("GUI Editor");
|
||||
|
||||
return currentMenuNames;
|
||||
}
|
||||
|
||||
void ProjucerApplication::createMenu (PopupMenu& menu, const String& menuName)
|
||||
PopupMenu ProjucerApplication::createMenu (const String& menuName)
|
||||
{
|
||||
if (menuName == "File") createFileMenu (menu);
|
||||
else if (menuName == "Edit") createEditMenu (menu);
|
||||
else if (menuName == "View") createViewMenu (menu);
|
||||
else if (menuName == "Build") createBuildMenu (menu);
|
||||
else if (menuName == "Window") createWindowMenu (menu);
|
||||
else if (menuName == "Document") createDocumentMenu (menu);
|
||||
else if (menuName == "Tools") createToolsMenu (menu);
|
||||
else if (menuName == "Help") createHelpMenu (menu);
|
||||
else if (menuName == "GUI Editor") createGUIEditorMenu (menu);
|
||||
else jassertfalse; // names have changed?
|
||||
if (menuName == "File")
|
||||
return createFileMenu();
|
||||
|
||||
if (menuName == "Edit")
|
||||
return createEditMenu();
|
||||
|
||||
if (menuName == "View")
|
||||
return createViewMenu();
|
||||
|
||||
if (menuName == "Build")
|
||||
if (isLiveBuildEnabled())
|
||||
return createBuildMenu();
|
||||
|
||||
if (menuName == "Window")
|
||||
return createWindowMenu();
|
||||
|
||||
if (menuName == "Document")
|
||||
return createDocumentMenu();
|
||||
|
||||
if (menuName == "Tools")
|
||||
return createToolsMenu();
|
||||
|
||||
if (menuName == "Help")
|
||||
return createHelpMenu();
|
||||
|
||||
if (menuName == "GUI Editor")
|
||||
if (isGUIEditorEnabled())
|
||||
return createGUIEditorMenu();
|
||||
|
||||
jassertfalse; // names have changed?
|
||||
return {};
|
||||
}
|
||||
|
||||
void ProjucerApplication::createFileMenu (PopupMenu& menu)
|
||||
PopupMenu ProjucerApplication::createFileMenu()
|
||||
{
|
||||
PopupMenu menu;
|
||||
menu.addCommandItem (commandManager.get(), CommandIDs::newProject);
|
||||
menu.addCommandItem (commandManager.get(), CommandIDs::newProjectFromClipboard);
|
||||
menu.addCommandItem (commandManager.get(), CommandIDs::newPIP);
|
||||
|
|
@ -353,12 +366,7 @@ void ProjucerApplication::createFileMenu (PopupMenu& menu)
|
|||
menu.addSubMenu ("Open Recent", recentFiles);
|
||||
}
|
||||
|
||||
{
|
||||
PopupMenu examples;
|
||||
|
||||
createExamplesPopupMenu (examples);
|
||||
menu.addSubMenu ("Open Example", examples);
|
||||
}
|
||||
menu.addSubMenu ("Open Example", createExamplesPopupMenu());
|
||||
|
||||
menu.addSeparator();
|
||||
menu.addCommandItem (commandManager.get(), CommandIDs::closeDocument);
|
||||
|
|
@ -373,17 +381,25 @@ void ProjucerApplication::createFileMenu (PopupMenu& menu)
|
|||
menu.addCommandItem (commandManager.get(), CommandIDs::saveAndOpenInIDE);
|
||||
menu.addSeparator();
|
||||
|
||||
#if ! JUCE_MAC
|
||||
menu.addCommandItem (commandManager.get(), CommandIDs::showAboutWindow);
|
||||
menu.addCommandItem (commandManager.get(), CommandIDs::checkForNewVersion);
|
||||
menu.addCommandItem (commandManager.get(), CommandIDs::showGlobalPathsWindow);
|
||||
menu.addSeparator();
|
||||
menu.addCommandItem (commandManager.get(), StandardApplicationCommandIDs::quit);
|
||||
#endif
|
||||
#if ! JUCER_ENABLE_GPL_MODE
|
||||
menu.addCommandItem (commandManager.get(), CommandIDs::loginLogout);
|
||||
#endif
|
||||
|
||||
#if ! JUCE_MAC
|
||||
menu.addCommandItem (commandManager.get(), CommandIDs::showAboutWindow);
|
||||
menu.addCommandItem (commandManager.get(), CommandIDs::checkForNewVersion);
|
||||
menu.addCommandItem (commandManager.get(), CommandIDs::enableNewVersionCheck);
|
||||
menu.addCommandItem (commandManager.get(), CommandIDs::showGlobalPathsWindow);
|
||||
menu.addSeparator();
|
||||
menu.addCommandItem (commandManager.get(), StandardApplicationCommandIDs::quit);
|
||||
#endif
|
||||
|
||||
return menu;
|
||||
}
|
||||
|
||||
void ProjucerApplication::createEditMenu (PopupMenu& menu)
|
||||
PopupMenu ProjucerApplication::createEditMenu()
|
||||
{
|
||||
PopupMenu menu;
|
||||
menu.addCommandItem (commandManager.get(), StandardApplicationCommandIDs::undo);
|
||||
menu.addCommandItem (commandManager.get(), StandardApplicationCommandIDs::redo);
|
||||
menu.addSeparator();
|
||||
|
|
@ -398,10 +414,12 @@ void ProjucerApplication::createEditMenu (PopupMenu& menu)
|
|||
menu.addCommandItem (commandManager.get(), CommandIDs::findSelection);
|
||||
menu.addCommandItem (commandManager.get(), CommandIDs::findNext);
|
||||
menu.addCommandItem (commandManager.get(), CommandIDs::findPrevious);
|
||||
return menu;
|
||||
}
|
||||
|
||||
void ProjucerApplication::createViewMenu (PopupMenu& menu)
|
||||
PopupMenu ProjucerApplication::createViewMenu()
|
||||
{
|
||||
PopupMenu menu;
|
||||
menu.addCommandItem (commandManager.get(), CommandIDs::showProjectSettings);
|
||||
menu.addCommandItem (commandManager.get(), CommandIDs::showProjectTab);
|
||||
menu.addCommandItem (commandManager.get(), CommandIDs::showBuildTab);
|
||||
|
|
@ -412,10 +430,13 @@ void ProjucerApplication::createViewMenu (PopupMenu& menu)
|
|||
|
||||
menu.addSeparator();
|
||||
createColourSchemeItems (menu);
|
||||
|
||||
return menu;
|
||||
}
|
||||
|
||||
void ProjucerApplication::createBuildMenu (PopupMenu& menu)
|
||||
PopupMenu ProjucerApplication::createBuildMenu()
|
||||
{
|
||||
PopupMenu menu;
|
||||
menu.addCommandItem (commandManager.get(), CommandIDs::toggleBuildEnabled);
|
||||
menu.addCommandItem (commandManager.get(), CommandIDs::buildNow);
|
||||
menu.addCommandItem (commandManager.get(), CommandIDs::toggleContinuousBuild);
|
||||
|
|
@ -429,55 +450,60 @@ void ProjucerApplication::createBuildMenu (PopupMenu& menu)
|
|||
menu.addSeparator();
|
||||
menu.addCommandItem (commandManager.get(), CommandIDs::nextError);
|
||||
menu.addCommandItem (commandManager.get(), CommandIDs::prevError);
|
||||
return menu;
|
||||
}
|
||||
|
||||
void ProjucerApplication::createColourSchemeItems (PopupMenu& menu)
|
||||
{
|
||||
PopupMenu colourSchemeMenu;
|
||||
|
||||
colourSchemeMenu.addItem (PopupMenu::Item ("Dark")
|
||||
.setTicked (selectedColourSchemeIndex == 0)
|
||||
.setAction ([this] { setColourScheme (0, true); updateEditorColourSchemeIfNeeded(); }));
|
||||
|
||||
colourSchemeMenu.addItem (PopupMenu::Item ("Grey")
|
||||
.setTicked (selectedColourSchemeIndex == 1)
|
||||
.setAction ([this] { setColourScheme (1, true); updateEditorColourSchemeIfNeeded(); }));
|
||||
|
||||
colourSchemeMenu.addItem (PopupMenu::Item ("Light")
|
||||
.setTicked (selectedColourSchemeIndex == 2)
|
||||
.setAction ([this] { setColourScheme (2, true); updateEditorColourSchemeIfNeeded(); }));
|
||||
|
||||
menu.addSubMenu ("Colour Scheme", colourSchemeMenu);
|
||||
|
||||
//==============================================================================
|
||||
PopupMenu editorColourSchemeMenu;
|
||||
|
||||
auto& appearanceSettings = getAppSettings().appearance;
|
||||
|
||||
appearanceSettings.refreshPresetSchemeList();
|
||||
auto schemes = appearanceSettings.getPresetSchemes();
|
||||
|
||||
auto i = 0;
|
||||
|
||||
for (auto& s : schemes)
|
||||
{
|
||||
editorColourSchemeMenu.addItem (PopupMenu::Item (s)
|
||||
.setEnabled (editorColourSchemeWindow == nullptr)
|
||||
.setTicked (selectedEditorColourSchemeIndex == i)
|
||||
.setAction ([this, i] { setEditorColourScheme (i, true); }));
|
||||
++i;
|
||||
PopupMenu colourSchemeMenu;
|
||||
|
||||
colourSchemeMenu.addItem (PopupMenu::Item ("Dark")
|
||||
.setTicked (selectedColourSchemeIndex == 0)
|
||||
.setAction ([this] { setColourScheme (0, true); updateEditorColourSchemeIfNeeded(); }));
|
||||
|
||||
colourSchemeMenu.addItem (PopupMenu::Item ("Grey")
|
||||
.setTicked (selectedColourSchemeIndex == 1)
|
||||
.setAction ([this] { setColourScheme (1, true); updateEditorColourSchemeIfNeeded(); }));
|
||||
|
||||
colourSchemeMenu.addItem (PopupMenu::Item ("Light")
|
||||
.setTicked (selectedColourSchemeIndex == 2)
|
||||
.setAction ([this] { setColourScheme (2, true); updateEditorColourSchemeIfNeeded(); }));
|
||||
|
||||
menu.addSubMenu ("Colour Scheme", colourSchemeMenu);
|
||||
}
|
||||
|
||||
editorColourSchemeMenu.addSeparator();
|
||||
editorColourSchemeMenu.addItem (PopupMenu::Item ("Create...")
|
||||
.setEnabled (editorColourSchemeWindow == nullptr)
|
||||
.setAction ([this] { showEditorColourSchemeWindow(); }));
|
||||
{
|
||||
PopupMenu editorColourSchemeMenu;
|
||||
|
||||
menu.addSubMenu ("Editor Colour Scheme", editorColourSchemeMenu);
|
||||
auto& appearanceSettings = getAppSettings().appearance;
|
||||
|
||||
appearanceSettings.refreshPresetSchemeList();
|
||||
auto schemes = appearanceSettings.getPresetSchemes();
|
||||
|
||||
auto i = 0;
|
||||
|
||||
for (auto& s : schemes)
|
||||
{
|
||||
editorColourSchemeMenu.addItem (PopupMenu::Item (s)
|
||||
.setEnabled (editorColourSchemeWindow == nullptr)
|
||||
.setTicked (selectedEditorColourSchemeIndex == i)
|
||||
.setAction ([this, i] { setEditorColourScheme (i, true); }));
|
||||
++i;
|
||||
}
|
||||
|
||||
editorColourSchemeMenu.addSeparator();
|
||||
editorColourSchemeMenu.addItem (PopupMenu::Item ("Create...")
|
||||
.setEnabled (editorColourSchemeWindow == nullptr)
|
||||
.setAction ([this] { showEditorColourSchemeWindow(); }));
|
||||
|
||||
menu.addSubMenu ("Editor Colour Scheme", editorColourSchemeMenu);
|
||||
}
|
||||
}
|
||||
|
||||
void ProjucerApplication::createWindowMenu (PopupMenu& menu)
|
||||
PopupMenu ProjucerApplication::createWindowMenu()
|
||||
{
|
||||
PopupMenu menu;
|
||||
menu.addCommandItem (commandManager.get(), CommandIDs::goToPreviousWindow);
|
||||
menu.addCommandItem (commandManager.get(), CommandIDs::goToNextWindow);
|
||||
menu.addCommandItem (commandManager.get(), CommandIDs::closeWindow);
|
||||
|
|
@ -486,16 +512,22 @@ void ProjucerApplication::createWindowMenu (PopupMenu& menu)
|
|||
int counter = 0;
|
||||
|
||||
for (auto* window : mainWindowList.windows)
|
||||
{
|
||||
if (window != nullptr)
|
||||
{
|
||||
if (auto* project = window->getProject())
|
||||
menu.addItem (openWindowsBaseID + counter++, project->getProjectNameString());
|
||||
}
|
||||
}
|
||||
|
||||
menu.addSeparator();
|
||||
menu.addCommandItem (commandManager.get(), CommandIDs::closeAllWindows);
|
||||
return menu;
|
||||
}
|
||||
|
||||
void ProjucerApplication::createDocumentMenu (PopupMenu& menu)
|
||||
PopupMenu ProjucerApplication::createDocumentMenu()
|
||||
{
|
||||
PopupMenu menu;
|
||||
menu.addCommandItem (commandManager.get(), CommandIDs::goToPreviousDoc);
|
||||
menu.addCommandItem (commandManager.get(), CommandIDs::goToNextDoc);
|
||||
menu.addCommandItem (commandManager.get(), CommandIDs::goToCounterpart);
|
||||
|
|
@ -511,34 +543,46 @@ void ProjucerApplication::createDocumentMenu (PopupMenu& menu)
|
|||
|
||||
menu.addSeparator();
|
||||
menu.addCommandItem (commandManager.get(), CommandIDs::closeAllDocuments);
|
||||
return menu;
|
||||
}
|
||||
|
||||
void ProjucerApplication::createToolsMenu (PopupMenu& menu)
|
||||
PopupMenu ProjucerApplication::createToolsMenu()
|
||||
{
|
||||
PopupMenu menu;
|
||||
menu.addCommandItem (commandManager.get(), CommandIDs::showUTF8Tool);
|
||||
menu.addCommandItem (commandManager.get(), CommandIDs::showSVGPathTool);
|
||||
menu.addCommandItem (commandManager.get(), CommandIDs::showTranslationTool);
|
||||
menu.addSeparator();
|
||||
menu.addCommandItem (commandManager.get(), CommandIDs::enableLiveBuild);
|
||||
menu.addCommandItem (commandManager.get(), CommandIDs::enableGUIEditor);
|
||||
return menu;
|
||||
}
|
||||
|
||||
void ProjucerApplication::createHelpMenu (PopupMenu& menu)
|
||||
PopupMenu ProjucerApplication::createHelpMenu()
|
||||
{
|
||||
PopupMenu menu;
|
||||
menu.addCommandItem (commandManager.get(), CommandIDs::showForum);
|
||||
menu.addSeparator();
|
||||
menu.addCommandItem (commandManager.get(), CommandIDs::showAPIModules);
|
||||
menu.addCommandItem (commandManager.get(), CommandIDs::showAPIClasses);
|
||||
menu.addCommandItem (commandManager.get(), CommandIDs::showTutorials);
|
||||
return menu;
|
||||
}
|
||||
|
||||
void ProjucerApplication::createExtraAppleMenuItems (PopupMenu& menu)
|
||||
PopupMenu ProjucerApplication::createExtraAppleMenuItems()
|
||||
{
|
||||
PopupMenu menu;
|
||||
menu.addCommandItem (commandManager.get(), CommandIDs::showAboutWindow);
|
||||
menu.addCommandItem (commandManager.get(), CommandIDs::checkForNewVersion);
|
||||
menu.addCommandItem (commandManager.get(), CommandIDs::enableNewVersionCheck);
|
||||
menu.addSeparator();
|
||||
menu.addCommandItem (commandManager.get(), CommandIDs::showGlobalPathsWindow);
|
||||
return menu;
|
||||
}
|
||||
|
||||
void ProjucerApplication::createExamplesPopupMenu (PopupMenu& menu) noexcept
|
||||
PopupMenu ProjucerApplication::createExamplesPopupMenu() noexcept
|
||||
{
|
||||
PopupMenu menu;
|
||||
numExamples = 0;
|
||||
for (auto& dir : getSortedExampleDirectories())
|
||||
{
|
||||
|
|
@ -561,8 +605,21 @@ void ProjucerApplication::createExamplesPopupMenu (PopupMenu& menu) noexcept
|
|||
menu.addSeparator();
|
||||
menu.addCommandItem (commandManager.get(), CommandIDs::launchDemoRunner);
|
||||
}
|
||||
|
||||
return menu;
|
||||
}
|
||||
|
||||
#if JUCE_MAC
|
||||
void ProjucerApplication::rebuildAppleMenu()
|
||||
{
|
||||
auto extraAppleMenuItems = createExtraAppleMenuItems();
|
||||
|
||||
// workaround broken "Open Recent" submenu: not passing the
|
||||
// submenu's title here avoids the defect in JuceMainMenuHandler::addMenuItem
|
||||
MenuBarModel::setMacMainMenu (menuModel.get(), &extraAppleMenuItems); //, "Open Recent");
|
||||
}
|
||||
#endif
|
||||
|
||||
//==============================================================================
|
||||
static File getJUCEExamplesDirectoryPathFromGlobal()
|
||||
{
|
||||
|
|
@ -907,12 +964,16 @@ void ProjucerApplication::getAllCommands (Array <CommandID>& commands)
|
|||
CommandIDs::showGlobalPathsWindow,
|
||||
CommandIDs::showUTF8Tool,
|
||||
CommandIDs::showSVGPathTool,
|
||||
CommandIDs::enableLiveBuild,
|
||||
CommandIDs::enableGUIEditor,
|
||||
CommandIDs::showAboutWindow,
|
||||
CommandIDs::checkForNewVersion,
|
||||
CommandIDs::enableNewVersionCheck,
|
||||
CommandIDs::showForum,
|
||||
CommandIDs::showAPIModules,
|
||||
CommandIDs::showAPIClasses,
|
||||
CommandIDs::showTutorials };
|
||||
CommandIDs::showTutorials,
|
||||
CommandIDs::loginLogout };
|
||||
|
||||
commands.addArray (ids, numElementsInArray (ids));
|
||||
}
|
||||
|
|
@ -990,6 +1051,20 @@ void ProjucerApplication::getCommandInfo (CommandID commandID, ApplicationComman
|
|||
result.setInfo ("SVG Path Converter", "Shows the SVG->Path data conversion utility", CommandCategories::general, 0);
|
||||
break;
|
||||
|
||||
case CommandIDs::enableLiveBuild:
|
||||
result.setInfo ("Live-Build Enabled",
|
||||
"Enables or disables the live-build functionality",
|
||||
CommandCategories::general,
|
||||
(isLiveBuildEnabled() ? ApplicationCommandInfo::isTicked : 0));
|
||||
break;
|
||||
|
||||
case CommandIDs::enableGUIEditor:
|
||||
result.setInfo ("GUI Editor Enabled",
|
||||
"Enables or disables the GUI editor functionality",
|
||||
CommandCategories::general,
|
||||
(isGUIEditorEnabled() ? ApplicationCommandInfo::isTicked : 0));
|
||||
break;
|
||||
|
||||
case CommandIDs::showAboutWindow:
|
||||
result.setInfo ("About Projucer", "Shows the Projucer's 'About' page.", CommandCategories::general, 0);
|
||||
break;
|
||||
|
|
@ -998,6 +1073,13 @@ void ProjucerApplication::getCommandInfo (CommandID commandID, ApplicationComman
|
|||
result.setInfo ("Check for New Version...", "Checks the web server for a new version of JUCE", CommandCategories::general, 0);
|
||||
break;
|
||||
|
||||
case CommandIDs::enableNewVersionCheck:
|
||||
result.setInfo ("Automatically Check for New Versions",
|
||||
"Enables automatic background checking for new versions of JUCE.",
|
||||
CommandCategories::general,
|
||||
(isAutomaticVersionCheckingEnabled() ? ApplicationCommandInfo::isTicked : 0));
|
||||
break;
|
||||
|
||||
case CommandIDs::showForum:
|
||||
result.setInfo ("JUCE Community Forum", "Shows the JUCE community forum in a browser", CommandCategories::general, 0);
|
||||
break;
|
||||
|
|
@ -1014,6 +1096,19 @@ void ProjucerApplication::getCommandInfo (CommandID commandID, ApplicationComman
|
|||
result.setInfo ("JUCE Tutorials", "Shows the JUCE tutorials in a browser", CommandCategories::general, 0);
|
||||
break;
|
||||
|
||||
case CommandIDs::loginLogout:
|
||||
{
|
||||
auto licenseState = licenseController->getCurrentState();
|
||||
|
||||
if (licenseState.isGPL())
|
||||
result.setInfo ("Disable GPL mode", "Disables GPL mode", CommandCategories::general, 0);
|
||||
else
|
||||
result.setInfo (licenseState.isValid() ? String ("Sign out ") + licenseState.username + "..." : String ("Sign in..."),
|
||||
"Log out of your JUCE account",
|
||||
CommandCategories::general, 0);
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
JUCEApplication::getCommandInfo (commandID, result);
|
||||
break;
|
||||
|
|
@ -1031,17 +1126,21 @@ bool ProjucerApplication::perform (const InvocationInfo& info)
|
|||
case CommandIDs::launchDemoRunner: launchDemoRunner(); break;
|
||||
case CommandIDs::saveAll: saveAllDocuments(); break;
|
||||
case CommandIDs::closeAllWindows: closeAllMainWindowsAndQuitIfNeeded(); break;
|
||||
case CommandIDs::closeAllDocuments: closeAllDocuments (true); break;
|
||||
case CommandIDs::closeAllDocuments: closeAllDocuments (OpenDocumentManager::SaveIfNeeded::yes); break;
|
||||
case CommandIDs::clearRecentFiles: clearRecentFiles(); break;
|
||||
case CommandIDs::showUTF8Tool: showUTF8ToolWindow(); break;
|
||||
case CommandIDs::showSVGPathTool: showSVGPathDataToolWindow(); break;
|
||||
case CommandIDs::enableLiveBuild: enableOrDisableLiveBuild(); break;
|
||||
case CommandIDs::enableGUIEditor: enableOrDisableGUIEditor(); break;
|
||||
case CommandIDs::showGlobalPathsWindow: showPathsWindow (false); break;
|
||||
case CommandIDs::showAboutWindow: showAboutWindow(); break;
|
||||
case CommandIDs::checkForNewVersion: LatestVersionCheckerAndUpdater::getInstance()->checkForNewVersion (true); break;
|
||||
case CommandIDs::checkForNewVersion: LatestVersionCheckerAndUpdater::getInstance()->checkForNewVersion (false); break;
|
||||
case CommandIDs::enableNewVersionCheck: setAutomaticVersionCheckingEnabled (! isAutomaticVersionCheckingEnabled()); break;
|
||||
case CommandIDs::showForum: launchForumBrowser(); break;
|
||||
case CommandIDs::showAPIModules: launchModulesBrowser(); break;
|
||||
case CommandIDs::showAPIClasses: launchClassesBrowser(); break;
|
||||
case CommandIDs::showTutorials: launchTutorialsBrowser(); break;
|
||||
case CommandIDs::loginLogout: doLoginOrLogout(); break;
|
||||
default: return JUCEApplication::perform (info);
|
||||
}
|
||||
|
||||
|
|
@ -1104,7 +1203,7 @@ void ProjucerApplication::saveAllDocuments()
|
|||
pcc->refreshProjectTreeFileStatuses();
|
||||
}
|
||||
|
||||
bool ProjucerApplication::closeAllDocuments (bool askUserToSave)
|
||||
bool ProjucerApplication::closeAllDocuments (OpenDocumentManager::SaveIfNeeded askUserToSave)
|
||||
{
|
||||
return openDocumentManager.closeAll (askUserToSave);
|
||||
}
|
||||
|
|
@ -1154,6 +1253,26 @@ void ProjucerApplication::showSVGPathDataToolWindow()
|
|||
500, 500, 300, 300, 1000, 1000);
|
||||
}
|
||||
|
||||
bool ProjucerApplication::isLiveBuildEnabled() const
|
||||
{
|
||||
return getGlobalProperties().getBoolValue (Ids::liveBuildEnabled);
|
||||
}
|
||||
|
||||
void ProjucerApplication::enableOrDisableLiveBuild()
|
||||
{
|
||||
getGlobalProperties().setValue (Ids::liveBuildEnabled, ! isLiveBuildEnabled());
|
||||
}
|
||||
|
||||
bool ProjucerApplication::isGUIEditorEnabled() const
|
||||
{
|
||||
return getGlobalProperties().getBoolValue (Ids::guiEditorEnabled);
|
||||
}
|
||||
|
||||
void ProjucerApplication::enableOrDisableGUIEditor()
|
||||
{
|
||||
getGlobalProperties().setValue (Ids::guiEditorEnabled, ! isGUIEditorEnabled());
|
||||
}
|
||||
|
||||
void ProjucerApplication::showAboutWindow()
|
||||
{
|
||||
if (aboutWindow != nullptr)
|
||||
|
|
@ -1230,6 +1349,26 @@ void ProjucerApplication::launchTutorialsBrowser()
|
|||
tutorialsLink.launchInDefaultBrowser();
|
||||
}
|
||||
|
||||
void ProjucerApplication::doLoginOrLogout()
|
||||
{
|
||||
if (licenseController->getCurrentState().type == LicenseState::Type::none)
|
||||
{
|
||||
if (auto* window = mainWindowList.getMainWindowWithLoginFormOpen())
|
||||
{
|
||||
window->toFront (true);
|
||||
}
|
||||
else
|
||||
{
|
||||
mainWindowList.createWindowIfNoneAreOpen();
|
||||
mainWindowList.getFrontmostWindow()->showLoginFormOverlay();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
licenseController->resetState();
|
||||
}
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
struct FileWithTime
|
||||
{
|
||||
|
|
@ -1286,13 +1425,6 @@ PropertiesFile::Options ProjucerApplication::getPropertyFileOptionsFor (const St
|
|||
return options;
|
||||
}
|
||||
|
||||
void ProjucerApplication::updateAllBuildTabs()
|
||||
{
|
||||
for (int i = 0; i < mainWindowList.windows.size(); ++i)
|
||||
if (ProjectContentComponent* p = mainWindowList.windows.getUnchecked(i)->getProjectContentComponent())
|
||||
p->rebuildProjectTabs();
|
||||
}
|
||||
|
||||
void ProjucerApplication::initCommandManager()
|
||||
{
|
||||
commandManager.reset (new ApplicationCommandManager());
|
||||
|
|
@ -1307,28 +1439,7 @@ void ProjucerApplication::initCommandManager()
|
|||
registerGUIEditorCommands();
|
||||
}
|
||||
|
||||
void ProjucerApplication::showSetJUCEPathAlert()
|
||||
{
|
||||
auto& lf = Desktop::getInstance().getDefaultLookAndFeel();
|
||||
pathAlert.reset (lf.createAlertWindow ("Set JUCE Path", "Your global JUCE path is invalid. This path is used to access the JUCE examples and demo project - "
|
||||
"would you like to set it now?",
|
||||
"Set path", "Cancel", "Don't ask again",
|
||||
AlertWindow::WarningIcon, 3,
|
||||
mainWindowList.getFrontmostWindow (false)));
|
||||
|
||||
pathAlert->enterModalState (true, ModalCallbackFunction::create ([this] (int retVal)
|
||||
{
|
||||
pathAlert.reset (nullptr);
|
||||
|
||||
if (retVal == 1)
|
||||
showPathsWindow (true);
|
||||
else if (retVal == 0)
|
||||
settings->setDontAskAboutJUCEPathAgain();
|
||||
}));
|
||||
|
||||
}
|
||||
|
||||
void rescanModules (AvailableModuleList& list, const Array<File>& paths, bool async)
|
||||
void rescanModules (AvailableModulesList& list, const Array<File>& paths, bool async)
|
||||
{
|
||||
if (async)
|
||||
list.scanPathsAsync (paths);
|
||||
|
|
@ -1338,12 +1449,32 @@ void rescanModules (AvailableModuleList& list, const Array<File>& paths, bool as
|
|||
|
||||
void ProjucerApplication::rescanJUCEPathModules()
|
||||
{
|
||||
rescanModules (jucePathModuleList, { getAppSettings().getStoredPath (Ids::defaultJuceModulePath, TargetOS::getThisOS()).get().toString() }, ! isRunningCommandLine);
|
||||
rescanModules (jucePathModulesList, { getAppSettings().getStoredPath (Ids::defaultJuceModulePath, TargetOS::getThisOS()).get().toString() }, ! isRunningCommandLine);
|
||||
}
|
||||
|
||||
void ProjucerApplication::rescanUserPathModules()
|
||||
{
|
||||
rescanModules (userPathsModuleList, { getAppSettings().getStoredPath (Ids::defaultUserModulePath, TargetOS::getThisOS()).get().toString() }, ! isRunningCommandLine);
|
||||
rescanModules (userPathsModulesList, { getAppSettings().getStoredPath (Ids::defaultUserModulePath, TargetOS::getThisOS()).get().toString() }, ! isRunningCommandLine);
|
||||
}
|
||||
|
||||
bool ProjucerApplication::isAutomaticVersionCheckingEnabled() const
|
||||
{
|
||||
return ! getGlobalProperties().getBoolValue (Ids::dontQueryForUpdate);
|
||||
}
|
||||
|
||||
void ProjucerApplication::setAutomaticVersionCheckingEnabled (bool enabled)
|
||||
{
|
||||
getGlobalProperties().setValue (Ids::dontQueryForUpdate, ! enabled);
|
||||
}
|
||||
|
||||
bool ProjucerApplication::shouldPromptUserAboutIncorrectJUCEPath() const
|
||||
{
|
||||
return ! getGlobalProperties().getBoolValue (Ids::dontAskAboutJUCEPath);
|
||||
}
|
||||
|
||||
void ProjucerApplication::setShouldPromptUserAboutIncorrectJUCEPath (bool shouldPrompt)
|
||||
{
|
||||
getGlobalProperties().setValue (Ids::dontAskAboutJUCEPath, ! shouldPrompt);
|
||||
}
|
||||
|
||||
void ProjucerApplication::selectEditorColourSchemeWithName (const String& schemeName)
|
||||
|
|
@ -1383,7 +1514,7 @@ void ProjucerApplication::setColourScheme (int index, bool saveSetting)
|
|||
|
||||
if (saveSetting)
|
||||
{
|
||||
auto& properties = settings->getGlobalProperties();
|
||||
auto& properties = getGlobalProperties();
|
||||
properties.setValue ("COLOUR SCHEME", index);
|
||||
}
|
||||
|
||||
|
|
@ -1403,7 +1534,7 @@ void ProjucerApplication::setEditorColourScheme (int index, bool saveSetting)
|
|||
|
||||
if (saveSetting)
|
||||
{
|
||||
auto& properties = settings->getGlobalProperties();
|
||||
auto& properties = getGlobalProperties();
|
||||
properties.setValue ("EDITOR COLOUR SCHEME", index);
|
||||
}
|
||||
|
||||
|
|
@ -1412,13 +1543,13 @@ void ProjucerApplication::setEditorColourScheme (int index, bool saveSetting)
|
|||
getCommandManager().commandStatusChanged();
|
||||
}
|
||||
|
||||
bool ProjucerApplication::isEditorColourSchemeADefaultScheme (const StringArray& schemes, int editorColourSchemeIndex)
|
||||
bool isEditorColourSchemeADefaultScheme (const StringArray& schemes, int editorColourSchemeIndex)
|
||||
{
|
||||
auto& schemeName = schemes[editorColourSchemeIndex];
|
||||
return (schemeName == "Default (Dark)" || schemeName == "Default (Light)");
|
||||
}
|
||||
|
||||
int ProjucerApplication::getEditorColourSchemeForGUIColourScheme (const StringArray& schemes, int guiColourSchemeIndex)
|
||||
int getEditorColourSchemeForGUIColourScheme (const StringArray& schemes, int guiColourSchemeIndex)
|
||||
{
|
||||
auto defaultDarkEditorIndex = schemes.indexOf ("Default (Dark)");
|
||||
auto defaultLightEditorIndex = schemes.indexOf ("Default (Light)");
|
||||
|
|
|
|||
|
|
@ -18,8 +18,9 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include "UserAccount/jucer_LicenseController.h"
|
||||
#include "jucer_MainWindow.h"
|
||||
#include "../Project/jucer_Module.h"
|
||||
#include "../Project/Modules/jucer_Modules.h"
|
||||
#include "jucer_AutoUpdater.h"
|
||||
#include "../CodeEditor/jucer_SourceCodeEditor.h"
|
||||
#include "../Utility/UI/jucer_ProjucerLookAndFeel.h"
|
||||
|
|
@ -31,7 +32,7 @@ class ProjucerApplication : public JUCEApplication,
|
|||
private AsyncUpdater
|
||||
{
|
||||
public:
|
||||
ProjucerApplication();
|
||||
ProjucerApplication() = default;
|
||||
|
||||
static ProjucerApplication& getApp();
|
||||
static ApplicationCommandManager& getCommandManager();
|
||||
|
|
@ -42,7 +43,6 @@ public:
|
|||
void systemRequestedQuit() override;
|
||||
void deleteLogger();
|
||||
|
||||
//==============================================================================
|
||||
const String getApplicationName() override { return "Projucer"; }
|
||||
const String getApplicationVersion() override { return ProjectInfo::versionString; }
|
||||
|
||||
|
|
@ -53,67 +53,34 @@ public:
|
|||
|
||||
//==============================================================================
|
||||
MenuBarModel* getMenuModel();
|
||||
StringArray getMenuNames();
|
||||
void createMenu (PopupMenu&, const String& menuName);
|
||||
void createFileMenu (PopupMenu&);
|
||||
void createEditMenu (PopupMenu&);
|
||||
void createViewMenu (PopupMenu&);
|
||||
void createBuildMenu (PopupMenu&);
|
||||
void createColourSchemeItems (PopupMenu&);
|
||||
void createWindowMenu (PopupMenu&);
|
||||
void createDocumentMenu (PopupMenu&);
|
||||
void createToolsMenu (PopupMenu&);
|
||||
void createHelpMenu (PopupMenu&);
|
||||
void createExtraAppleMenuItems (PopupMenu&);
|
||||
void handleMainMenuCommand (int menuItemID);
|
||||
|
||||
//==============================================================================
|
||||
void getAllCommands (Array<CommandID>&) override;
|
||||
void getCommandInfo (CommandID commandID, ApplicationCommandInfo&) override;
|
||||
bool perform (const InvocationInfo&) override;
|
||||
|
||||
bool isLiveBuildEnabled() const;
|
||||
bool isGUIEditorEnabled() const;
|
||||
|
||||
//==============================================================================
|
||||
void createNewProject();
|
||||
void createNewProjectFromClipboard();
|
||||
void createNewPIP();
|
||||
void askUserToOpenFile();
|
||||
bool openFile (const File&);
|
||||
void saveAllDocuments();
|
||||
bool closeAllDocuments (bool askUserToSave);
|
||||
bool closeAllMainWindows();
|
||||
void closeAllMainWindowsAndQuitIfNeeded();
|
||||
void clearRecentFiles();
|
||||
|
||||
PropertiesFile::Options getPropertyFileOptionsFor (const String& filename, bool isProjectSettings);
|
||||
|
||||
//==============================================================================
|
||||
void showUTF8ToolWindow();
|
||||
void showSVGPathDataToolWindow();
|
||||
|
||||
void showAboutWindow();
|
||||
void showPathsWindow (bool highlightJUCEPath = false);
|
||||
void showEditorColourSchemeWindow();
|
||||
|
||||
void showPIPCreatorWindow();
|
||||
|
||||
void launchForumBrowser();
|
||||
void launchModulesBrowser();
|
||||
void launchClassesBrowser();
|
||||
void launchTutorialsBrowser();
|
||||
|
||||
void updateAllBuildTabs();
|
||||
|
||||
//==============================================================================
|
||||
PropertiesFile::Options getPropertyFileOptionsFor (const String& filename, bool isProjectSettings);
|
||||
void selectEditorColourSchemeWithName (const String& schemeName);
|
||||
static bool isEditorColourSchemeADefaultScheme (const StringArray& schemes, int editorColourSchemeIndex);
|
||||
static int getEditorColourSchemeForGUIColourScheme (const StringArray& schemes, int guiColourSchemeIndex);
|
||||
|
||||
//==============================================================================
|
||||
void rescanJUCEPathModules();
|
||||
void rescanUserPathModules();
|
||||
|
||||
AvailableModuleList& getJUCEPathModuleList() { return jucePathModuleList; }
|
||||
AvailableModuleList& getUserPathsModuleList() { return userPathsModuleList; }
|
||||
AvailableModulesList& getJUCEPathModulesList() { return jucePathModulesList; }
|
||||
AvailableModulesList& getUserPathsModulesList() { return userPathsModulesList; }
|
||||
|
||||
LicenseController& getLicenseController() { return *licenseController; }
|
||||
|
||||
bool isAutomaticVersionCheckingEnabled() const;
|
||||
void setAutomaticVersionCheckingEnabled (bool shouldBeEnabled);
|
||||
|
||||
bool shouldPromptUserAboutIncorrectJUCEPath() const;
|
||||
void setShouldPromptUserAboutIncorrectJUCEPath (bool shouldPrompt);
|
||||
|
||||
//==============================================================================
|
||||
ProjucerLookAndFeel lookAndFeel;
|
||||
|
|
@ -128,23 +95,42 @@ public:
|
|||
OpenDocumentManager openDocumentManager;
|
||||
std::unique_ptr<ApplicationCommandManager> commandManager;
|
||||
|
||||
std::unique_ptr<Component> utf8Window, svgPathWindow, aboutWindow, pathsWindow,
|
||||
editorColourSchemeWindow, pipCreatorWindow;
|
||||
|
||||
std::unique_ptr<FileLogger> logger;
|
||||
|
||||
bool isRunningCommandLine;
|
||||
bool isRunningCommandLine = false;
|
||||
std::unique_ptr<ChildProcessCache> childProcessCache;
|
||||
|
||||
private:
|
||||
//==============================================================================
|
||||
void handleAsyncUpdate() override;
|
||||
void initCommandManager();
|
||||
|
||||
void initCommandManager();
|
||||
bool initialiseLogger (const char* filePrefix);
|
||||
void initialiseWindows (const String& commandLine);
|
||||
|
||||
void createExamplesPopupMenu (PopupMenu&) noexcept;
|
||||
void createNewProject();
|
||||
void createNewProjectFromClipboard();
|
||||
void createNewPIP();
|
||||
void askUserToOpenFile();
|
||||
void saveAllDocuments();
|
||||
bool closeAllDocuments (OpenDocumentManager::SaveIfNeeded askUserToSave);
|
||||
bool closeAllMainWindows();
|
||||
void closeAllMainWindowsAndQuitIfNeeded();
|
||||
void clearRecentFiles();
|
||||
|
||||
StringArray getMenuNames();
|
||||
PopupMenu createMenu (const String& menuName);
|
||||
PopupMenu createFileMenu();
|
||||
PopupMenu createEditMenu();
|
||||
PopupMenu createViewMenu();
|
||||
PopupMenu createBuildMenu();
|
||||
void createColourSchemeItems (PopupMenu&);
|
||||
PopupMenu createWindowMenu();
|
||||
PopupMenu createDocumentMenu();
|
||||
PopupMenu createToolsMenu();
|
||||
PopupMenu createHelpMenu();
|
||||
PopupMenu createExtraAppleMenuItems();
|
||||
void handleMainMenuCommand (int menuItemID);
|
||||
PopupMenu createExamplesPopupMenu() noexcept;
|
||||
|
||||
Array<File> getSortedExampleDirectories() noexcept;
|
||||
Array<File> getSortedExampleFilesInDirectory (const File&) const noexcept;
|
||||
bool findWindowAndOpenPIP (const File&);
|
||||
|
|
@ -155,22 +141,74 @@ private:
|
|||
File tryToFindDemoRunnerProject();
|
||||
void launchDemoRunner();
|
||||
|
||||
void showSetJUCEPathAlert();
|
||||
|
||||
void setColourScheme (int index, bool saveSetting);
|
||||
void setEditorColourScheme (int index, bool saveSetting);
|
||||
void updateEditorColourSchemeIfNeeded();
|
||||
|
||||
void showUTF8ToolWindow();
|
||||
void showSVGPathDataToolWindow();
|
||||
void showAboutWindow();
|
||||
void showEditorColourSchemeWindow();
|
||||
void showPIPCreatorWindow();
|
||||
|
||||
void launchForumBrowser();
|
||||
void launchModulesBrowser();
|
||||
void launchClassesBrowser();
|
||||
void launchTutorialsBrowser();
|
||||
|
||||
void doLoginOrLogout();
|
||||
void showLoginForm();
|
||||
|
||||
void enableOrDisableLiveBuild();
|
||||
void enableOrDisableGUIEditor();
|
||||
|
||||
//==============================================================================
|
||||
#if JUCE_MAC
|
||||
class AppleMenuRebuildListener : private MenuBarModel::Listener
|
||||
{
|
||||
public:
|
||||
AppleMenuRebuildListener()
|
||||
{
|
||||
if (auto* model = ProjucerApplication::getApp().getMenuModel())
|
||||
model->addListener (this);
|
||||
}
|
||||
|
||||
~AppleMenuRebuildListener() override
|
||||
{
|
||||
if (auto* model = ProjucerApplication::getApp().getMenuModel())
|
||||
model->removeListener (this);
|
||||
}
|
||||
|
||||
private:
|
||||
void menuBarItemsChanged (MenuBarModel*) override {}
|
||||
|
||||
void menuCommandInvoked (MenuBarModel*,
|
||||
const ApplicationCommandTarget::InvocationInfo& info) override
|
||||
{
|
||||
if (info.commandID == CommandIDs::enableNewVersionCheck)
|
||||
Timer::callAfterDelay (50, [] { ProjucerApplication::getApp().rebuildAppleMenu(); });
|
||||
}
|
||||
};
|
||||
|
||||
void rebuildAppleMenu();
|
||||
|
||||
std::unique_ptr<AppleMenuRebuildListener> appleMenuRebuildListener;
|
||||
#endif
|
||||
|
||||
//==============================================================================
|
||||
std::unique_ptr<LicenseController> licenseController;
|
||||
|
||||
void* server = nullptr;
|
||||
|
||||
std::unique_ptr<TooltipWindow> tooltipWindow;
|
||||
AvailableModulesList jucePathModulesList, userPathsModulesList;
|
||||
|
||||
AvailableModuleList jucePathModuleList, userPathsModuleList;
|
||||
std::unique_ptr<Component> utf8Window, svgPathWindow, aboutWindow, pathsWindow,
|
||||
editorColourSchemeWindow, pipCreatorWindow;
|
||||
|
||||
std::unique_ptr<FileLogger> logger;
|
||||
|
||||
int numExamples = 0;
|
||||
std::unique_ptr<AlertWindow> demoRunnerAlert;
|
||||
std::unique_ptr<AlertWindow> pathAlert;
|
||||
bool hasScannedForDemoRunnerExecutable = false, hasScannedForDemoRunnerProject = false;
|
||||
File lastJUCEPath, lastDemoRunnerExectuableFile, lastDemoRunnerProjectFile;
|
||||
#if JUCE_LINUX
|
||||
|
|
|
|||
|
|
@ -32,11 +32,11 @@ LatestVersionCheckerAndUpdater::~LatestVersionCheckerAndUpdater()
|
|||
clearSingletonInstance();
|
||||
}
|
||||
|
||||
void LatestVersionCheckerAndUpdater::checkForNewVersion (bool showAlerts)
|
||||
void LatestVersionCheckerAndUpdater::checkForNewVersion (bool background)
|
||||
{
|
||||
if (! isThreadRunning())
|
||||
{
|
||||
showAlertWindows = showAlerts;
|
||||
backgroundCheck = background;
|
||||
startThread (3);
|
||||
}
|
||||
}
|
||||
|
|
@ -48,7 +48,7 @@ void LatestVersionCheckerAndUpdater::run()
|
|||
|
||||
if (info == nullptr)
|
||||
{
|
||||
if (showAlertWindows)
|
||||
if (! backgroundCheck)
|
||||
AlertWindow::showMessageBoxAsync (AlertWindow::WarningIcon,
|
||||
"Update Server Communication Error",
|
||||
"Failed to communicate with the JUCE update server.\n"
|
||||
|
|
@ -60,7 +60,7 @@ void LatestVersionCheckerAndUpdater::run()
|
|||
|
||||
if (! info->isNewerVersionThanCurrent())
|
||||
{
|
||||
if (showAlertWindows)
|
||||
if (! backgroundCheck)
|
||||
AlertWindow::showMessageBoxAsync (AlertWindow::InfoIcon,
|
||||
"No New Version Available",
|
||||
"Your JUCE version is up to date.");
|
||||
|
|
@ -99,7 +99,7 @@ void LatestVersionCheckerAndUpdater::run()
|
|||
}
|
||||
}
|
||||
|
||||
if (showAlertWindows)
|
||||
if (! backgroundCheck)
|
||||
AlertWindow::showMessageBoxAsync (AlertWindow::WarningIcon,
|
||||
"Failed to find any new downloads",
|
||||
"Please try again in a few minutes.");
|
||||
|
|
@ -137,15 +137,11 @@ public:
|
|||
addAndMakeVisible (cancelButton);
|
||||
cancelButton.onClick = [this]
|
||||
{
|
||||
if (dontAskAgainButton.getToggleState())
|
||||
getGlobalProperties().setValue (Ids::dontQueryForUpdate.toString(), 1);
|
||||
else
|
||||
getGlobalProperties().removeValue (Ids::dontQueryForUpdate);
|
||||
|
||||
ProjucerApplication::getApp().setAutomaticVersionCheckingEnabled (! dontAskAgainButton.getToggleState());
|
||||
exitModalStateWithResult (-1);
|
||||
};
|
||||
|
||||
dontAskAgainButton.setToggleState (getGlobalProperties().getValue (Ids::dontQueryForUpdate, {}).isNotEmpty(), dontSendNotification);
|
||||
dontAskAgainButton.setToggleState (! ProjucerApplication::getApp().isAutomaticVersionCheckingEnabled(), dontSendNotification);
|
||||
addAndMakeVisible (dontAskAgainButton);
|
||||
|
||||
juceIcon = Drawable::createFromImageData (BinaryData::juce_icon_png,
|
||||
|
|
@ -287,10 +283,21 @@ void LatestVersionCheckerAndUpdater::askUserForLocationToDownload (const Version
|
|||
void LatestVersionCheckerAndUpdater::askUserAboutNewVersion (const String& newVersionString,
|
||||
const String& releaseNotes,
|
||||
const VersionInfo::Asset& asset)
|
||||
{
|
||||
if (backgroundCheck)
|
||||
addNotificationToOpenProjects (asset);
|
||||
else
|
||||
showDialogWindow (newVersionString, releaseNotes, asset);
|
||||
}
|
||||
|
||||
void LatestVersionCheckerAndUpdater::showDialogWindow (const String& newVersionString,
|
||||
const String& releaseNotes,
|
||||
const VersionInfo::Asset& asset)
|
||||
{
|
||||
dialogWindow = UpdateDialog::launchDialog (newVersionString, releaseNotes);
|
||||
|
||||
if (auto* mm = ModalComponentManager::getInstance())
|
||||
{
|
||||
mm->attachCallback (dialogWindow.get(),
|
||||
ModalCallbackFunction::create ([this, asset] (int result)
|
||||
{
|
||||
|
|
@ -299,6 +306,35 @@ void LatestVersionCheckerAndUpdater::askUserAboutNewVersion (const String& newVe
|
|||
|
||||
dialogWindow.reset();
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
||||
void LatestVersionCheckerAndUpdater::addNotificationToOpenProjects (const VersionInfo::Asset& asset)
|
||||
{
|
||||
for (auto* window : ProjucerApplication::getApp().mainWindowList.windows)
|
||||
{
|
||||
if (auto* project = window->getProject())
|
||||
{
|
||||
Component::SafePointer<MainWindow> safeWindow (window);
|
||||
|
||||
auto ignore = [safeWindow]
|
||||
{
|
||||
if (safeWindow != nullptr)
|
||||
safeWindow->getProject()->removeProjectMessage (ProjectMessages::Ids::newVersionAvailable);
|
||||
};
|
||||
|
||||
auto dontAskAgain = [ignore]
|
||||
{
|
||||
ignore();
|
||||
ProjucerApplication::getApp().setAutomaticVersionCheckingEnabled (false);
|
||||
};
|
||||
|
||||
project->addProjectMessage (ProjectMessages::Ids::newVersionAvailable,
|
||||
{ { "Download", [this, asset] { askUserForLocationToDownload (asset); } },
|
||||
{ "Ignore", std::move (ignore) },
|
||||
{ "Don't ask again", std::move (dontAskAgain) } });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
|
|
|
|||
|
|
@ -29,7 +29,7 @@ public:
|
|||
LatestVersionCheckerAndUpdater();
|
||||
~LatestVersionCheckerAndUpdater() override;
|
||||
|
||||
void checkForNewVersion (bool showAlerts);
|
||||
void checkForNewVersion (bool isBackgroundCheck);
|
||||
|
||||
//==============================================================================
|
||||
JUCE_DECLARE_SINGLETON_SINGLETHREADED_MINIMAL (LatestVersionCheckerAndUpdater)
|
||||
|
|
@ -41,8 +41,11 @@ private:
|
|||
void askUserForLocationToDownload (const VersionInfo::Asset&);
|
||||
void downloadAndInstall (const VersionInfo::Asset&, const File&);
|
||||
|
||||
void showDialogWindow (const String&, const String&, const VersionInfo::Asset&);
|
||||
void addNotificationToOpenProjects (const VersionInfo::Asset&);
|
||||
|
||||
//==============================================================================
|
||||
bool showAlertWindows = false;
|
||||
bool backgroundCheck = false;
|
||||
|
||||
std::unique_ptr<DownloadAndInstallThread> installer;
|
||||
std::unique_ptr<Component> dialogWindow;
|
||||
|
|
|
|||
|
|
@ -48,6 +48,9 @@ namespace CommandIDs
|
|||
showSVGPathTool = 0x300023,
|
||||
showAboutWindow = 0x300024,
|
||||
checkForNewVersion = 0x300025,
|
||||
enableNewVersionCheck = 0x300026,
|
||||
enableLiveBuild = 0x300027,
|
||||
enableGUIEditor = 0x300028,
|
||||
|
||||
showProjectSettings = 0x300030,
|
||||
showProjectTab = 0x300031,
|
||||
|
|
@ -91,10 +94,14 @@ namespace CommandIDs
|
|||
nextError = 0x300080,
|
||||
prevError = 0x300081,
|
||||
|
||||
showForum = 0x300090,
|
||||
showAPIModules = 0x300091,
|
||||
showAPIClasses = 0x300092,
|
||||
showTutorials = 0x300093,
|
||||
loginLogout = 0x300090,
|
||||
|
||||
showForum = 0x300100,
|
||||
showAPIModules = 0x300101,
|
||||
showAPIClasses = 0x300102,
|
||||
showTutorials = 0x300103,
|
||||
|
||||
addNewGUIFile = 0x300200,
|
||||
|
||||
lastCommandIDEntry
|
||||
};
|
||||
|
|
|
|||
|
|
@ -90,8 +90,8 @@ namespace
|
|||
if (! justSaveResources)
|
||||
rescanModulePathsIfNecessary();
|
||||
|
||||
auto error = justSaveResources ? project->saveResourcesOnly (project->getFile())
|
||||
: project->saveProject (project->getFile(), true);
|
||||
auto error = justSaveResources ? project->saveResourcesOnly()
|
||||
: project->saveProject();
|
||||
|
||||
project.reset();
|
||||
|
||||
|
|
@ -230,7 +230,7 @@ namespace
|
|||
<< "Name: " << proj.project->getProjectNameString() << std::endl
|
||||
<< "UID: " << proj.project->getProjectUIDString() << std::endl;
|
||||
|
||||
EnabledModuleList& modules = proj.project->getEnabledModules();
|
||||
auto& modules = proj.project->getEnabledModules();
|
||||
|
||||
if (int numModules = modules.getNumModules())
|
||||
{
|
||||
|
|
@ -307,7 +307,7 @@ namespace
|
|||
|
||||
var moduleInfo (new DynamicObject());
|
||||
moduleInfo.getDynamicObject()->setProperty ("file", getModulePackageName (module));
|
||||
moduleInfo.getDynamicObject()->setProperty ("info", module.moduleInfo.moduleInfo);
|
||||
moduleInfo.getDynamicObject()->setProperty ("info", module.moduleInfo.getModuleInfo());
|
||||
infoList.append (moduleInfo);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -22,6 +22,7 @@
|
|||
#include "../CodeEditor/jucer_OpenDocumentManager.h"
|
||||
#include "../CodeEditor/jucer_SourceCodeEditor.h"
|
||||
#include "../Utility/UI/PropertyComponents/jucer_FilePathPropertyComponent.h"
|
||||
#include "../Project/UI/jucer_ProjectContentComponent.h"
|
||||
#include "../Project/UI/Sidebar/jucer_TreeItemTypes.h"
|
||||
#include "Windows/jucer_UTF8WindowComponent.h"
|
||||
#include "Windows/jucer_SVGPathDataWindowComponent.h"
|
||||
|
|
|
|||
|
|
@ -22,6 +22,90 @@
|
|||
#include "../Wizards/jucer_NewProjectWizardClasses.h"
|
||||
#include "../Utility/UI/jucer_JucerTreeViewBase.h"
|
||||
#include "../ProjectSaving/jucer_ProjectSaver.h"
|
||||
#include "UserAccount/jucer_LoginFormComponent.h"
|
||||
#include "../Project/UI/jucer_ProjectContentComponent.h"
|
||||
|
||||
//==============================================================================
|
||||
class BlurOverlayWithComponent : public Component,
|
||||
private ComponentMovementWatcher,
|
||||
private AsyncUpdater
|
||||
{
|
||||
public:
|
||||
BlurOverlayWithComponent (MainWindow& window, std::unique_ptr<Component> comp)
|
||||
: ComponentMovementWatcher (&window),
|
||||
mainWindow (window),
|
||||
componentToShow (std::move (comp))
|
||||
{
|
||||
kernel.createGaussianBlur (1.25f);
|
||||
|
||||
addAndMakeVisible (*componentToShow);
|
||||
|
||||
setAlwaysOnTop (true);
|
||||
setOpaque (true);
|
||||
setVisible (true);
|
||||
|
||||
static_cast<Component&> (mainWindow).addChildComponent (this);
|
||||
componentMovedOrResized (true, true);
|
||||
}
|
||||
|
||||
void resized() override
|
||||
{
|
||||
setBounds (mainWindow.getLocalBounds());
|
||||
componentToShow->centreWithSize (componentToShow->getWidth(), componentToShow->getHeight());
|
||||
refreshBackgroundImage();
|
||||
}
|
||||
|
||||
void paint (Graphics& g) override
|
||||
{
|
||||
g.drawImage (componentImage, getLocalBounds().toFloat());
|
||||
}
|
||||
|
||||
private:
|
||||
void componentPeerChanged() override {}
|
||||
|
||||
void componentVisibilityChanged() override {}
|
||||
using ComponentMovementWatcher::componentVisibilityChanged;
|
||||
|
||||
void componentMovedOrResized (bool, bool) override { triggerAsyncUpdate(); }
|
||||
using ComponentMovementWatcher::componentMovedOrResized;
|
||||
|
||||
void handleAsyncUpdate() override { resized(); }
|
||||
|
||||
void mouseUp (const MouseEvent& event) override
|
||||
{
|
||||
if (event.eventComponent == this)
|
||||
mainWindow.hideLoginFormOverlay();
|
||||
}
|
||||
|
||||
void lookAndFeelChanged() override
|
||||
{
|
||||
refreshBackgroundImage();
|
||||
repaint();
|
||||
}
|
||||
|
||||
void refreshBackgroundImage()
|
||||
{
|
||||
setVisible (false);
|
||||
|
||||
auto parentBounds = mainWindow.getBounds();
|
||||
|
||||
componentImage = mainWindow.createComponentSnapshot (mainWindow.getLocalBounds())
|
||||
.rescaled (roundToInt (parentBounds.getWidth() / 1.75f), roundToInt (parentBounds.getHeight() / 1.75f));
|
||||
|
||||
kernel.applyToImage (componentImage, componentImage, getLocalBounds());
|
||||
|
||||
setVisible (true);
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
MainWindow& mainWindow;
|
||||
std::unique_ptr<Component> componentToShow;
|
||||
|
||||
ImageConvolutionKernel kernel { 3 };
|
||||
Image componentImage;
|
||||
|
||||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (BlurOverlayWithComponent)
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
MainWindow::MainWindow()
|
||||
|
|
@ -32,6 +116,8 @@ MainWindow::MainWindow()
|
|||
false)
|
||||
{
|
||||
setUsingNativeTitleBar (true);
|
||||
setResizable (true, false);
|
||||
setResizeLimits (600, 500, 32000, 32000);
|
||||
|
||||
#if ! JUCE_MAC
|
||||
setMenuBar (ProjucerApplication::getApp().getMenuModel());
|
||||
|
|
@ -39,9 +125,6 @@ MainWindow::MainWindow()
|
|||
|
||||
createProjectContentCompIfNeeded();
|
||||
|
||||
setResizable (true, false);
|
||||
centreWithSize (800, 600);
|
||||
|
||||
auto& commandManager = ProjucerApplication::getCommandManager();
|
||||
|
||||
auto registerAllAppCommands = [&]
|
||||
|
|
@ -65,9 +148,10 @@ MainWindow::MainWindow()
|
|||
|
||||
setWantsKeyboardFocus (false);
|
||||
getLookAndFeel().setColour (ColourSelector::backgroundColourId, Colours::transparentBlack);
|
||||
|
||||
projectNameValue.addListener (this);
|
||||
|
||||
setResizeLimits (600, 500, 32000, 32000);
|
||||
centreWithSize (800, 600);
|
||||
}
|
||||
|
||||
MainWindow::~MainWindow()
|
||||
|
|
@ -77,10 +161,11 @@ MainWindow::~MainWindow()
|
|||
#endif
|
||||
|
||||
removeKeyListener (ProjucerApplication::getCommandManager().getKeyMappings());
|
||||
|
||||
// save the current size and position to our settings file..
|
||||
getGlobalProperties().setValue ("lastMainWindowPos", getWindowStateAsString());
|
||||
|
||||
clearContentComponent();
|
||||
currentProject.reset();
|
||||
}
|
||||
|
||||
void MainWindow::createProjectContentCompIfNeeded()
|
||||
|
|
@ -127,7 +212,7 @@ void MainWindow::closeButtonPressed()
|
|||
ProjucerApplication::getApp().mainWindowList.closeWindow (this);
|
||||
}
|
||||
|
||||
bool MainWindow::closeCurrentProject (bool askUserToSave)
|
||||
bool MainWindow::closeCurrentProject (OpenDocumentManager::SaveIfNeeded askUserToSave)
|
||||
{
|
||||
if (currentProject == nullptr)
|
||||
return true;
|
||||
|
|
@ -144,7 +229,8 @@ bool MainWindow::closeCurrentProject (bool askUserToSave)
|
|||
if (ProjucerApplication::getApp().openDocumentManager
|
||||
.closeAllDocumentsUsingProject (*currentProject, askUserToSave))
|
||||
{
|
||||
if (! askUserToSave || (currentProject->saveIfNeededAndUserAgrees() == FileBasedDocument::savedOk))
|
||||
if (askUserToSave == OpenDocumentManager::SaveIfNeeded::no
|
||||
|| (currentProject->saveIfNeededAndUserAgrees() == FileBasedDocument::savedOk))
|
||||
{
|
||||
setProject (nullptr);
|
||||
return true;
|
||||
|
|
@ -154,19 +240,16 @@ bool MainWindow::closeCurrentProject (bool askUserToSave)
|
|||
return false;
|
||||
}
|
||||
|
||||
void MainWindow::moveProject (File newProjectFileToOpen)
|
||||
void MainWindow::moveProject (File newProjectFileToOpen, OpenInIDE openInIDE)
|
||||
{
|
||||
auto openInIDE = currentProject->shouldOpenInIDEAfterSaving();
|
||||
|
||||
closeCurrentProject (false);
|
||||
closeCurrentProject (OpenDocumentManager::SaveIfNeeded::no);
|
||||
openFile (newProjectFileToOpen);
|
||||
|
||||
if (currentProject != nullptr)
|
||||
{
|
||||
ProjucerApplication::getApp().getCommandManager().invokeDirectly (openInIDE ? CommandIDs::saveAndOpenInIDE
|
||||
: CommandIDs::saveProject,
|
||||
false);
|
||||
}
|
||||
ProjucerApplication::getApp().getCommandManager()
|
||||
.invokeDirectly (openInIDE == OpenInIDE::yes ? CommandIDs::saveAndOpenInIDE
|
||||
: CommandIDs::saveProject,
|
||||
false);
|
||||
}
|
||||
|
||||
void MainWindow::setProject (std::unique_ptr<Project> newProject)
|
||||
|
|
@ -174,7 +257,7 @@ void MainWindow::setProject (std::unique_ptr<Project> newProject)
|
|||
if (newProject == nullptr)
|
||||
{
|
||||
getProjectContentComponent()->setProject (nullptr);
|
||||
projectNameValue.referTo (Value());
|
||||
projectNameValue.referTo ({});
|
||||
|
||||
currentProject.reset();
|
||||
}
|
||||
|
|
@ -222,7 +305,7 @@ bool MainWindow::openFile (const File& file)
|
|||
auto newDoc = std::make_unique<Project> (file);
|
||||
auto result = newDoc->loadFrom (file, true);
|
||||
|
||||
if (result.wasOk() && closeCurrentProject (true))
|
||||
if (result.wasOk() && closeCurrentProject (OpenDocumentManager::SaveIfNeeded::yes))
|
||||
{
|
||||
setProject (std::move (newDoc));
|
||||
currentProject->setChangedFlag (false);
|
||||
|
|
@ -350,7 +433,7 @@ void MainWindow::openPIP (PIPGenerator& generator)
|
|||
{
|
||||
project->setTemporaryDirectory (generator.getOutputDirectory());
|
||||
|
||||
ProjectSaver liveBuildSaver (*project, project->getFile());
|
||||
ProjectSaver liveBuildSaver (*project);
|
||||
liveBuildSaver.saveContentNeededForLiveBuild();
|
||||
|
||||
if (auto* pcc = window->getProjectContentComponent())
|
||||
|
|
@ -440,49 +523,6 @@ void MainWindow::activeWindowStatusChanged()
|
|||
pcc->updateMissingFileStatuses();
|
||||
|
||||
ProjucerApplication::getApp().openDocumentManager.reloadModifiedFiles();
|
||||
|
||||
if (auto* p = getProject())
|
||||
{
|
||||
if (p->hasProjectBeenModified())
|
||||
{
|
||||
Component::SafePointer<Component> safePointer (this);
|
||||
|
||||
MessageManager::callAsync ([=] ()
|
||||
{
|
||||
if (safePointer == nullptr)
|
||||
return; // bail out if the window has been deleted
|
||||
|
||||
auto result = AlertWindow::showOkCancelBox (AlertWindow::QuestionIcon,
|
||||
TRANS ("The .jucer file has been modified since the last save."),
|
||||
TRANS ("Do you want to keep the current project or re-load from disk?"),
|
||||
TRANS ("Keep"),
|
||||
TRANS ("Re-load from disk"));
|
||||
|
||||
if (safePointer == nullptr)
|
||||
return;
|
||||
|
||||
if (result == 0)
|
||||
{
|
||||
if (auto* project = getProject())
|
||||
{
|
||||
auto oldTemporaryDirectory = project->getTemporaryDirectory();
|
||||
|
||||
auto projectFile = project->getFile();
|
||||
setProject (nullptr);
|
||||
openFile (projectFile);
|
||||
|
||||
if (oldTemporaryDirectory != File())
|
||||
if (auto* newProject = getProject())
|
||||
newProject->setTemporaryDirectory (oldTemporaryDirectory);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
ProjucerApplication::getApp().getCommandManager().invokeDirectly (CommandIDs::saveProject, true);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void MainWindow::showStartPage()
|
||||
|
|
@ -498,6 +538,18 @@ void MainWindow::showStartPage()
|
|||
getContentComponent()->grabKeyboardFocus();
|
||||
}
|
||||
|
||||
void MainWindow::showLoginFormOverlay()
|
||||
{
|
||||
blurOverlayComponent = std::make_unique<BlurOverlayWithComponent> (*this, std::make_unique<LoginFormComponent> (*this));
|
||||
loginFormOpen = true;
|
||||
}
|
||||
|
||||
void MainWindow::hideLoginFormOverlay()
|
||||
{
|
||||
blurOverlayComponent.reset();
|
||||
loginFormOpen = false;
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
ApplicationCommandTarget* MainWindow::getNextCommandTarget()
|
||||
{
|
||||
|
|
@ -565,12 +617,11 @@ bool MainWindow::perform (const InvocationInfo& info)
|
|||
return true;
|
||||
}
|
||||
|
||||
void MainWindow::valueChanged (Value&)
|
||||
void MainWindow::valueChanged (Value& value)
|
||||
{
|
||||
if (currentProject != nullptr)
|
||||
setName (currentProject->getProjectNameString() + " - Projucer");
|
||||
else
|
||||
setName ("Projucer");
|
||||
if (value == projectNameValue)
|
||||
setName (currentProject != nullptr ? currentProject->getProjectNameString() + " - Projucer"
|
||||
: "Projucer");
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
|
|
@ -589,7 +640,7 @@ bool MainWindowList::askAllWindowsToClose()
|
|||
|
||||
while (windows.size() > 0)
|
||||
{
|
||||
if (! windows[0]->closeCurrentProject (true))
|
||||
if (! windows[0]->closeCurrentProject (OpenDocumentManager::SaveIfNeeded::yes))
|
||||
return false;
|
||||
|
||||
windows.remove (0);
|
||||
|
|
@ -616,7 +667,7 @@ void MainWindowList::closeWindow (MainWindow* w)
|
|||
else
|
||||
#endif
|
||||
{
|
||||
if (w->closeCurrentProject (true))
|
||||
if (w->closeCurrentProject (OpenDocumentManager::SaveIfNeeded::yes))
|
||||
{
|
||||
windows.removeObject (w);
|
||||
saveCurrentlyOpenProjectList();
|
||||
|
|
@ -766,6 +817,15 @@ MainWindow* MainWindowList::getMainWindowForFile (const File& file)
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
MainWindow* MainWindowList::getMainWindowWithLoginFormOpen()
|
||||
{
|
||||
for (auto* window : windows)
|
||||
if (window->isShowingLoginForm())
|
||||
return window;
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void MainWindowList::checkWindowBounds (MainWindow& windowToCheck)
|
||||
{
|
||||
auto avoidSuperimposedWindows = [&]
|
||||
|
|
|
|||
|
|
@ -18,8 +18,11 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include "../Project/UI/jucer_ProjectContentComponent.h"
|
||||
#include "../Utility/PIPs/jucer_PIPGenerator.h"
|
||||
#include "../Project/jucer_Project.h"
|
||||
#include "../CodeEditor/jucer_OpenDocumentManager.h"
|
||||
|
||||
class ProjectContentComponent;
|
||||
|
||||
//==============================================================================
|
||||
/**
|
||||
|
|
@ -36,6 +39,8 @@ public:
|
|||
MainWindow();
|
||||
~MainWindow() override;
|
||||
|
||||
enum class OpenInIDE { no, yes };
|
||||
|
||||
//==============================================================================
|
||||
void closeButtonPressed() override;
|
||||
|
||||
|
|
@ -50,11 +55,15 @@ public:
|
|||
|
||||
void makeVisible();
|
||||
void restoreWindowPosition();
|
||||
bool closeCurrentProject (bool askToSave);
|
||||
void moveProject (File newProjectFile);
|
||||
bool closeCurrentProject (OpenDocumentManager::SaveIfNeeded askToSave);
|
||||
void moveProject (File newProjectFile, OpenInIDE openInIDE);
|
||||
|
||||
void showStartPage();
|
||||
|
||||
void showLoginFormOverlay();
|
||||
void hideLoginFormOverlay();
|
||||
bool isShowingLoginForm() const noexcept { return loginFormOpen; }
|
||||
|
||||
bool isInterestedInFileDrag (const StringArray& files) override;
|
||||
void filesDropped (const StringArray& filenames, int mouseX, int mouseY) override;
|
||||
|
||||
|
|
@ -71,16 +80,18 @@ public:
|
|||
bool shouldDropFilesWhenDraggedExternally (const DragAndDropTarget::SourceDetails& sourceDetails,
|
||||
StringArray& files, bool& canMoveFiles) override;
|
||||
private:
|
||||
std::unique_ptr<Project> currentProject;
|
||||
Value projectNameValue;
|
||||
void valueChanged (Value&) override;
|
||||
|
||||
static const char* getProjectWindowPosName() { return "projectWindowPos"; }
|
||||
void createProjectContentCompIfNeeded();
|
||||
void setTitleBarIcon();
|
||||
|
||||
void openPIP (PIPGenerator&);
|
||||
|
||||
void valueChanged (Value&) override;
|
||||
std::unique_ptr<Project> currentProject;
|
||||
Value projectNameValue;
|
||||
|
||||
std::unique_ptr<Component> blurOverlayComponent;
|
||||
bool loginFormOpen = false;
|
||||
|
||||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (MainWindow)
|
||||
};
|
||||
|
|
@ -105,6 +116,7 @@ public:
|
|||
MainWindow* getFrontmostWindow (bool createIfNotFound = true);
|
||||
MainWindow* getOrCreateEmptyWindow();
|
||||
MainWindow* getMainWindowForFile (const File&);
|
||||
MainWindow* getMainWindowWithLoginFormOpen();
|
||||
|
||||
Project* getFrontmostProject();
|
||||
|
||||
|
|
|
|||
23
extras/Projucer/Source/BinaryData/Icons/gpl_logo.svg
Normal file
23
extras/Projucer/Source/BinaryData/Icons/gpl_logo.svg
Normal file
File diff suppressed because one or more lines are too long
|
After Width: | Height: | Size: 26 KiB |
|
|
@ -1,50 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Generator: Adobe Illustrator 21.0.2, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||
viewBox="0 0 169.7 205.2" style="enable-background:new 0 0 169.7 205.2;" xml:space="preserve">
|
||||
<style type="text/css">
|
||||
.st0{fill:#A65A95;}
|
||||
.st1{fill:#001946;}
|
||||
</style>
|
||||
<g>
|
||||
<g>
|
||||
<path class="st0" d="M45.2,167.8c-3,0-5.4-1.1-7.8-4.3l3.6-3.1c1.6,2.1,2.7,2.7,4.2,2.7c2.6,0,4.4-2,4.4-5v-17.2h5V158
|
||||
C54.6,163.9,50.7,167.8,45.2,167.8z"/>
|
||||
<path class="st0" d="M70.7,167.8c-5.8,0-10.8-4.2-10.8-11.2v-15.8h5v15.6c0,4.1,2.4,6.7,5.8,6.7c3.4,0,5.8-2.6,5.8-6.7v-15.6h5
|
||||
v15.8C81.5,163.5,76.5,167.8,70.7,167.8z"/>
|
||||
<path class="st0" d="M99,167.8c-7.6,0-13.9-6.1-13.9-13.6c0-7.6,6.3-13.6,13.9-13.6c3.4,0,6.3,1.2,9.1,3.4l-2.9,3.6
|
||||
c-2.6-1.8-4.1-2.4-6.2-2.4c-4.8,0-8.8,3.9-8.8,9c0,5,3.9,9,8.8,9c2,0,3.6-0.6,6.1-2.4l3,3.7C104.6,167,102,167.8,99,167.8z"/>
|
||||
<path class="st0" d="M111.3,167.4v-26.6h16.6v4.5h-11.6v6.4h11.2v4.5h-11.2v6.7h11.6v4.5H111.3z"/>
|
||||
</g>
|
||||
<g>
|
||||
<circle class="st1" cx="84.9" cy="74.9" r="37.4"/>
|
||||
<circle class="st0" cx="84.9" cy="74.9" r="28"/>
|
||||
<circle class="st1" cx="84.9" cy="67.9" r="2.1"/>
|
||||
<circle class="st1" cx="91.4" cy="72.6" r="2.1"/>
|
||||
<circle class="st1" cx="88.9" cy="80.3" r="2.1"/>
|
||||
<circle class="st1" cx="80.8" cy="80.3" r="2.1"/>
|
||||
<circle class="st1" cx="78.3" cy="72.6" r="2.1"/>
|
||||
</g>
|
||||
<g>
|
||||
<path class="st1" d="M48.2,131.7v-4.6h-4.3v4.6h-2V121h2v4.3h4.3V121h2v10.8H48.2z"/>
|
||||
<path class="st1" d="M56.7,131.7v-0.5c-0.5,0.4-1.3,0.7-2.1,0.7c-1.9,0-3.2-1.3-3.2-3.4v-5h2v4.8c0,1.2,0.7,1.8,1.7,1.8
|
||||
c1,0,1.7-0.7,1.7-1.8v-4.8h2v8.3H56.7z"/>
|
||||
<path class="st1" d="M63.8,131.9c-2.4,0-4.3-1.9-4.3-4.3c0-2.4,1.9-4.3,4.3-4.3c1.1,0,2.1,0.4,3.3,1.5l-1.3,1.2
|
||||
c-0.7-0.7-1.3-1-2-1c-1.3,0-2.3,1.1-2.3,2.5c0,1.3,1,2.5,2.3,2.5c0.6,0,1.3-0.2,2-0.9l1.3,1.2C66,131.5,65,131.9,63.8,131.9z"/>
|
||||
<path class="st1" d="M73.8,131.7l-3.9-3.9v3.9h-2v-11.3h2v6.8l3.6-3.7h2.5l-3.9,4l4.3,4.3H73.8z"/>
|
||||
<path class="st1" d="M77.1,131.7v-11.3h2v11.3H77.1z"/>
|
||||
<path class="st1" d="M88.6,128.4h-6.2c0.1,1,1.1,1.7,2.1,1.7c0.7,0,1.5-0.3,2.3-1.1l1.3,1.2c-1.1,1.2-2.3,1.7-3.6,1.7
|
||||
c-2.4,0-4.3-1.9-4.3-4.3c0-2.4,1.9-4.3,4.3-4.3c2.4,0,4.1,1.9,4.1,4.2C88.7,127.9,88.6,128.4,88.6,128.4z M84.5,125.1
|
||||
c-1,0-1.9,0.6-2.1,1.5h4.1C86.3,125.8,85.5,125.1,84.5,125.1z"/>
|
||||
<path class="st1" d="M93.9,131.9c-0.9,0-1.7-0.3-2.3-0.8v0.6h-2v-11.3h2v3.7c0.6-0.5,1.4-0.8,2.3-0.8c2.3,0,4.2,1.9,4.2,4.3
|
||||
C98.1,129.9,96.2,131.9,93.9,131.9z M93.9,125.1c-1.3,0-2.2,1.1-2.2,2.5c0,1.4,1,2.5,2.2,2.5c1.3,0,2.2-1.1,2.2-2.5
|
||||
C96.2,126.2,95.2,125.1,93.9,125.1z"/>
|
||||
<path class="st1" d="M107.4,128.4h-6.2c0.1,1,1.1,1.7,2.1,1.7c0.7,0,1.5-0.3,2.3-1.1l1.3,1.2c-1.1,1.2-2.3,1.7-3.6,1.7
|
||||
c-2.4,0-4.3-1.9-4.3-4.3c0-2.4,1.9-4.3,4.3-4.3c2.4,0,4.1,1.9,4.1,4.2C107.5,127.9,107.4,128.4,107.4,128.4z M103.3,125.1
|
||||
c-1,0-1.9,0.6-2.1,1.5h4.1C105.1,125.8,104.3,125.1,103.3,125.1z"/>
|
||||
<path class="st1" d="M110.4,127.8v3.9h-2v-8.3h2v0.8c0.7-0.6,1.4-0.9,2.6-1v1.8C111,125.4,110.4,126.6,110.4,127.8z"/>
|
||||
<path class="st1" d="M116,127.8v3.9h-2v-8.3h2v0.8c0.7-0.6,1.4-0.9,2.6-1v1.8C116.6,125.4,116,126.6,116,127.8z"/>
|
||||
<path class="st1" d="M122.2,134.6h-2.1l2.2-4.2l-3.4-6.9h2.1l2.4,4.8l2.3-4.8h2.2L122.2,134.6z"/>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 3.3 KiB |
|
|
@ -19,7 +19,7 @@
|
|||
#include "../Application/jucer_Headers.h"
|
||||
#include "jucer_DocumentEditorComponent.h"
|
||||
#include "../Application/jucer_Application.h"
|
||||
|
||||
#include "../Project/UI/jucer_ProjectContentComponent.h"
|
||||
|
||||
//==============================================================================
|
||||
DocumentEditorComponent::DocumentEditorComponent (OpenDocumentManager::Document* doc)
|
||||
|
|
|
|||
|
|
@ -181,11 +181,11 @@ FileBasedDocument::SaveResult OpenDocumentManager::saveIfNeededAndUserAgrees (Op
|
|||
}
|
||||
|
||||
|
||||
bool OpenDocumentManager::closeDocument (int index, bool saveIfNeeded)
|
||||
bool OpenDocumentManager::closeDocument (int index, SaveIfNeeded saveIfNeeded)
|
||||
{
|
||||
if (Document* doc = documents [index])
|
||||
{
|
||||
if (saveIfNeeded)
|
||||
if (saveIfNeeded == SaveIfNeeded::yes)
|
||||
if (saveIfNeededAndUserAgrees (doc) != FileBasedDocument::savedOk)
|
||||
return false;
|
||||
|
||||
|
|
@ -206,12 +206,12 @@ bool OpenDocumentManager::closeDocument (int index, bool saveIfNeeded)
|
|||
return true;
|
||||
}
|
||||
|
||||
bool OpenDocumentManager::closeDocument (Document* document, bool saveIfNeeded)
|
||||
bool OpenDocumentManager::closeDocument (Document* document, SaveIfNeeded saveIfNeeded)
|
||||
{
|
||||
return closeDocument (documents.indexOf (document), saveIfNeeded);
|
||||
}
|
||||
|
||||
void OpenDocumentManager::closeFile (const File& f, bool saveIfNeeded)
|
||||
void OpenDocumentManager::closeFile (const File& f, SaveIfNeeded saveIfNeeded)
|
||||
{
|
||||
for (int i = documents.size(); --i >= 0;)
|
||||
if (Document* d = documents[i])
|
||||
|
|
@ -219,7 +219,7 @@ void OpenDocumentManager::closeFile (const File& f, bool saveIfNeeded)
|
|||
closeDocument (i, saveIfNeeded);
|
||||
}
|
||||
|
||||
bool OpenDocumentManager::closeAll (bool askUserToSave)
|
||||
bool OpenDocumentManager::closeAll (SaveIfNeeded askUserToSave)
|
||||
{
|
||||
for (int i = getNumOpenDocuments(); --i >= 0;)
|
||||
if (! closeDocument (i, askUserToSave))
|
||||
|
|
@ -228,7 +228,7 @@ bool OpenDocumentManager::closeAll (bool askUserToSave)
|
|||
return true;
|
||||
}
|
||||
|
||||
bool OpenDocumentManager::closeAllDocumentsUsingProject (Project& project, bool saveIfNeeded)
|
||||
bool OpenDocumentManager::closeAllDocumentsUsingProject (Project& project, SaveIfNeeded saveIfNeeded)
|
||||
{
|
||||
for (int i = documents.size(); --i >= 0;)
|
||||
if (Document* d = documents[i])
|
||||
|
|
|
|||
|
|
@ -61,13 +61,15 @@ public:
|
|||
Document* getOpenDocument (int index) const;
|
||||
void clear();
|
||||
|
||||
enum class SaveIfNeeded { no, yes };
|
||||
|
||||
bool canOpenFile (const File& file);
|
||||
Document* openFile (Project* project, const File& file);
|
||||
bool closeDocument (int index, bool saveIfNeeded);
|
||||
bool closeDocument (Document* document, bool saveIfNeeded);
|
||||
bool closeAll (bool askUserToSave);
|
||||
bool closeAllDocumentsUsingProject (Project& project, bool saveIfNeeded);
|
||||
void closeFile (const File& f, bool saveIfNeeded);
|
||||
bool closeDocument (int index, SaveIfNeeded saveIfNeeded);
|
||||
bool closeDocument (Document* document, SaveIfNeeded saveIfNeeded);
|
||||
bool closeAll (SaveIfNeeded askUserToSave);
|
||||
bool closeAllDocumentsUsingProject (Project& project, SaveIfNeeded saveIfNeeded);
|
||||
void closeFile (const File& f, SaveIfNeeded saveIfNeeded);
|
||||
bool anyFilesNeedSaving() const;
|
||||
bool saveAll();
|
||||
FileBasedDocument::SaveResult saveIfNeededAndUserAgrees (Document* doc);
|
||||
|
|
|
|||
|
|
@ -1210,11 +1210,14 @@ Image JucerDocumentEditor::createComponentLayerSnapshot() const
|
|||
const int gridSnapMenuItemBase = 0x8723620;
|
||||
const int snapSizes[] = { 2, 3, 4, 5, 6, 8, 10, 12, 16, 20, 24, 32 };
|
||||
|
||||
void createGUIEditorMenu (PopupMenu&);
|
||||
void createGUIEditorMenu (PopupMenu& menu)
|
||||
PopupMenu createGUIEditorMenu()
|
||||
{
|
||||
PopupMenu menu;
|
||||
auto* commandManager = &ProjucerApplication::getCommandManager();
|
||||
|
||||
menu.addCommandItem (commandManager, CommandIDs::addNewGUIFile);
|
||||
menu.addSeparator();
|
||||
|
||||
menu.addCommandItem (commandManager, JucerCommandIDs::editCompLayout);
|
||||
menu.addCommandItem (commandManager, JucerCommandIDs::editCompGraphics);
|
||||
menu.addSeparator();
|
||||
|
|
@ -1283,6 +1286,7 @@ void createGUIEditorMenu (PopupMenu& menu)
|
|||
|
||||
menu.addSubMenu ("Component Overlay", overlays, holder != nullptr);
|
||||
}
|
||||
return menu;
|
||||
}
|
||||
|
||||
void handleGUIEditorMenuCommand (int);
|
||||
|
|
|
|||
|
|
@ -697,7 +697,7 @@ public:
|
|||
{
|
||||
if (header->save())
|
||||
{
|
||||
odm.closeFile (getFile().withFileExtension(".h"), false);
|
||||
odm.closeFile (getFile().withFileExtension(".h"), OpenDocumentManager::SaveIfNeeded::no);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
@ -707,10 +707,13 @@ public:
|
|||
|
||||
Component* createEditor() override
|
||||
{
|
||||
std::unique_ptr<JucerDocument> jucerDoc (JucerDocument::createForCppFile (getProject(), getFile()));
|
||||
if (ProjucerApplication::getApp().isGUIEditorEnabled())
|
||||
{
|
||||
std::unique_ptr<JucerDocument> jucerDoc (JucerDocument::createForCppFile (getProject(), getFile()));
|
||||
|
||||
if (jucerDoc != nullptr)
|
||||
return new JucerDocumentEditor (jucerDoc.release());
|
||||
if (jucerDoc != nullptr)
|
||||
return new JucerDocumentEditor (jucerDoc.release());
|
||||
}
|
||||
|
||||
return SourceCodeDocument::createEditor();
|
||||
}
|
||||
|
|
@ -766,8 +769,8 @@ struct NewGUIComponentWizard : public NewFileWizard::Type
|
|||
|
||||
cpp->save();
|
||||
header->save();
|
||||
odm.closeDocument (cpp, true);
|
||||
odm.closeDocument (header, true);
|
||||
odm.closeDocument (cpp, OpenDocumentManager::SaveIfNeeded::yes);
|
||||
odm.closeDocument (header, OpenDocumentManager::SaveIfNeeded::yes);
|
||||
|
||||
parent.addFileRetainingSortOrder (headerFile, true);
|
||||
parent.addFileRetainingSortOrder (cppFile, true);
|
||||
|
|
|
|||
|
|
@ -81,13 +81,10 @@ namespace MessageTypes
|
|||
{
|
||||
inline bool send (MessageHandler& target, const ValueTree& v)
|
||||
{
|
||||
//DBG ("Send: " << v.getType().toString());
|
||||
bool result = target.sendMessage (v);
|
||||
|
||||
if (! result)
|
||||
{
|
||||
DBG ("*** Message failed: " << v.getType().toString());
|
||||
}
|
||||
Logger::outputDebugString ("*** Message failed: " + v.getType().toString());
|
||||
|
||||
return result;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -29,6 +29,7 @@
|
|||
#include "jucer_CompileEngineClient.h"
|
||||
#include "jucer_CompileEngineServer.h"
|
||||
#include "jucer_CompileEngineSettings.h"
|
||||
#include "../Project/UI/jucer_ProjectContentComponent.h"
|
||||
|
||||
#ifndef RUN_CLANG_IN_CHILD_PROCESS
|
||||
#error
|
||||
|
|
@ -208,8 +209,6 @@ public:
|
|||
|
||||
if (isRunningApp && server != nullptr)
|
||||
server->killServerWithoutMercy();
|
||||
|
||||
server.reset();
|
||||
}
|
||||
|
||||
void restartServer()
|
||||
|
|
@ -511,9 +510,6 @@ CompileEngineChildProcess::CompileEngineChildProcess (Project& p)
|
|||
CompileEngineChildProcess::~CompileEngineChildProcess()
|
||||
{
|
||||
ProjucerApplication::getApp().openDocumentManager.removeListener (this);
|
||||
|
||||
process.reset();
|
||||
lastComponentList.clear();
|
||||
}
|
||||
|
||||
void CompileEngineChildProcess::createProcess()
|
||||
|
|
|
|||
|
|
@ -18,10 +18,11 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#define DECLARE_ID(name) static const Identifier name (#name)
|
||||
|
||||
namespace MessageTypes
|
||||
{
|
||||
#define DECLARE_ID(name) const Identifier name (#name)
|
||||
|
||||
DECLARE_ID (PING);
|
||||
DECLARE_ID (BUILDINFO);
|
||||
DECLARE_ID (COMPILEUNIT);
|
||||
|
|
@ -50,6 +51,6 @@ namespace MessageTypes
|
|||
DECLARE_ID (LAUNCH_APP);
|
||||
DECLARE_ID (FOREGROUND);
|
||||
DECLARE_ID (QUIT_SERVER);
|
||||
}
|
||||
|
||||
#undef DECLARE_ID
|
||||
#undef DECLARE_ID
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,195 @@
|
|||
/*
|
||||
==============================================================================
|
||||
|
||||
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
|
||||
|
||||
#include "jucer_ModuleDescription.h"
|
||||
|
||||
//==============================================================================
|
||||
class AvailableModulesList
|
||||
{
|
||||
public:
|
||||
using ModuleIDAndFolder = std::pair<String, File>;
|
||||
using ModuleIDAndFolderList = std::vector<ModuleIDAndFolder>;
|
||||
|
||||
AvailableModulesList() = default;
|
||||
|
||||
//==============================================================================
|
||||
void scanPaths (const Array<File>& paths)
|
||||
{
|
||||
auto job = createScannerJob (paths);
|
||||
auto& ref = *job;
|
||||
|
||||
removePendingAndAddJob (std::move (job));
|
||||
scanPool.waitForJobToFinish (&ref, -1);
|
||||
}
|
||||
|
||||
void scanPathsAsync (const Array<File>& paths)
|
||||
{
|
||||
removePendingAndAddJob (createScannerJob (paths));
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
ModuleIDAndFolderList getAllModules() const
|
||||
{
|
||||
const ScopedLock readLock (lock);
|
||||
return modulesList;
|
||||
}
|
||||
|
||||
ModuleIDAndFolder getModuleWithID (const String& id) const
|
||||
{
|
||||
const ScopedLock readLock (lock);
|
||||
|
||||
for (auto& mod : modulesList)
|
||||
if (mod.first == id)
|
||||
return mod;
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
void removeDuplicates (const ModuleIDAndFolderList& other)
|
||||
{
|
||||
const ScopedLock readLock (lock);
|
||||
|
||||
const auto predicate = [&] (const ModuleIDAndFolder& entry)
|
||||
{
|
||||
return std::find (other.begin(), other.end(), entry) != other.end();
|
||||
};
|
||||
|
||||
modulesList.erase (std::remove_if (modulesList.begin(), modulesList.end(), predicate),
|
||||
modulesList.end());
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
struct Listener
|
||||
{
|
||||
virtual ~Listener() = default;
|
||||
virtual void availableModulesChanged (AvailableModulesList* listThatHasChanged) = 0;
|
||||
};
|
||||
|
||||
void addListener (Listener* listenerToAdd) { listeners.add (listenerToAdd); }
|
||||
void removeListener (Listener* listenerToRemove) { listeners.remove (listenerToRemove); }
|
||||
|
||||
private:
|
||||
//==============================================================================
|
||||
struct ModuleScannerJob : public ThreadPoolJob
|
||||
{
|
||||
ModuleScannerJob (const Array<File>& paths,
|
||||
std::function<void (const ModuleIDAndFolderList&)>&& callback)
|
||||
: ThreadPoolJob ("ModuleScannerJob"),
|
||||
pathsToScan (paths),
|
||||
completionCallback (std::move (callback))
|
||||
{
|
||||
}
|
||||
|
||||
JobStatus runJob() override
|
||||
{
|
||||
ModuleIDAndFolderList list;
|
||||
|
||||
for (auto& p : pathsToScan)
|
||||
addAllModulesInFolder (p, list);
|
||||
|
||||
if (! shouldExit())
|
||||
{
|
||||
std::sort (list.begin(), list.end(), [] (const ModuleIDAndFolder& m1,
|
||||
const ModuleIDAndFolder& m2)
|
||||
{
|
||||
return m1.first.compareIgnoreCase (m2.first) < 0;
|
||||
});
|
||||
|
||||
completionCallback (list);
|
||||
}
|
||||
|
||||
return jobHasFinished;
|
||||
}
|
||||
|
||||
static bool tryToAddModuleFromFolder (const File& path, ModuleIDAndFolderList& list)
|
||||
{
|
||||
ModuleDescription m (path);
|
||||
|
||||
if (m.isValid())
|
||||
{
|
||||
list.push_back ({ m.getID(), path });
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static void addAllModulesInSubfoldersRecursively (const File& path, int depth, ModuleIDAndFolderList& list)
|
||||
{
|
||||
if (depth > 0)
|
||||
{
|
||||
for (const auto& iter : RangedDirectoryIterator (path, false, "*", File::findDirectories))
|
||||
{
|
||||
if (auto* job = ThreadPoolJob::getCurrentThreadPoolJob())
|
||||
if (job->shouldExit())
|
||||
return;
|
||||
|
||||
auto childPath = iter.getFile();
|
||||
|
||||
if (! tryToAddModuleFromFolder (childPath, list))
|
||||
addAllModulesInSubfoldersRecursively (childPath, depth - 1, list);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void addAllModulesInFolder (const File& path, ModuleIDAndFolderList& list)
|
||||
{
|
||||
if (! tryToAddModuleFromFolder (path, list))
|
||||
{
|
||||
constexpr int subfolders = 3;
|
||||
addAllModulesInSubfoldersRecursively (path, subfolders, list);
|
||||
}
|
||||
}
|
||||
|
||||
Array<File> pathsToScan;
|
||||
std::function<void (const ModuleIDAndFolderList&)> completionCallback;
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
std::unique_ptr<ThreadPoolJob> createScannerJob (const Array<File>& paths)
|
||||
{
|
||||
return std::make_unique<ModuleScannerJob> (paths, [this] (ModuleIDAndFolderList scannedModulesList)
|
||||
{
|
||||
{
|
||||
const ScopedLock swapLock (lock);
|
||||
modulesList.swap (scannedModulesList);
|
||||
}
|
||||
|
||||
listeners.call ([this] (Listener& l) { MessageManager::callAsync ([&] { l.availableModulesChanged (this); }); });
|
||||
});
|
||||
}
|
||||
|
||||
void removePendingAndAddJob (std::unique_ptr<ThreadPoolJob> jobToAdd)
|
||||
{
|
||||
scanPool.removeAllJobs (false, 100);
|
||||
scanPool.addJob (jobToAdd.release(), true);
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
ThreadPool scanPool { 1 };
|
||||
|
||||
ModuleIDAndFolderList modulesList;
|
||||
ListenerList<Listener> listeners;
|
||||
CriticalSection lock;
|
||||
|
||||
//==============================================================================
|
||||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (AvailableModulesList)
|
||||
};
|
||||
|
|
@ -0,0 +1,86 @@
|
|||
/*
|
||||
==============================================================================
|
||||
|
||||
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
|
||||
|
||||
|
||||
//==============================================================================
|
||||
class ModuleDescription
|
||||
{
|
||||
public:
|
||||
ModuleDescription() = default;
|
||||
|
||||
ModuleDescription (const File& folder)
|
||||
: moduleFolder (folder),
|
||||
moduleInfo (parseJUCEHeaderMetadata (getHeader()))
|
||||
{
|
||||
}
|
||||
|
||||
bool isValid() const { return getID().isNotEmpty(); }
|
||||
|
||||
String getID() const { return moduleInfo [Ids::ID_uppercase].toString(); }
|
||||
String getVendor() const { return moduleInfo [Ids::vendor].toString(); }
|
||||
String getVersion() const { return moduleInfo [Ids::version].toString(); }
|
||||
String getName() const { return moduleInfo [Ids::name].toString(); }
|
||||
String getDescription() const { return moduleInfo [Ids::description].toString(); }
|
||||
String getLicense() const { return moduleInfo [Ids::license].toString(); }
|
||||
String getMinimumCppStandard() const { return moduleInfo [Ids::minimumCppStandard].toString(); }
|
||||
String getPreprocessorDefs() const { return moduleInfo [Ids::defines].toString(); }
|
||||
String getExtraSearchPaths() const { return moduleInfo [Ids::searchpaths].toString(); }
|
||||
var getModuleInfo() const { return moduleInfo; }
|
||||
File getModuleFolder() const { return moduleFolder; }
|
||||
|
||||
File getFolder() const
|
||||
{
|
||||
jassert (moduleFolder != File());
|
||||
|
||||
return moduleFolder;
|
||||
}
|
||||
|
||||
File getHeader() const
|
||||
{
|
||||
if (moduleFolder != File())
|
||||
{
|
||||
static const char* extensions[] = { ".h", ".hpp", ".hxx" };
|
||||
|
||||
for (auto e : extensions)
|
||||
{
|
||||
auto header = moduleFolder.getChildFile (moduleFolder.getFileName() + e);
|
||||
|
||||
if (header.existsAsFile())
|
||||
return header;
|
||||
}
|
||||
}
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
StringArray getDependencies() const
|
||||
{
|
||||
auto moduleDependencies = StringArray::fromTokens (moduleInfo ["dependencies"].toString(), " \t;,", "\"'");
|
||||
moduleDependencies.trim();
|
||||
moduleDependencies.removeEmptyStrings();
|
||||
|
||||
return moduleDependencies;
|
||||
}
|
||||
|
||||
private:
|
||||
File moduleFolder;
|
||||
var moduleInfo;
|
||||
URL url;
|
||||
};
|
||||
|
|
@ -16,182 +16,10 @@
|
|||
==============================================================================
|
||||
*/
|
||||
|
||||
#include "../Application/jucer_Headers.h"
|
||||
#include "../ProjectSaving/jucer_ProjectSaver.h"
|
||||
#include "../ProjectSaving/jucer_ProjectExport_Xcode.h"
|
||||
#include "../Application/jucer_Application.h"
|
||||
|
||||
//==============================================================================
|
||||
ModuleDescription::ModuleDescription (const File& folder)
|
||||
: moduleFolder (folder),
|
||||
moduleInfo (parseJUCEHeaderMetadata (getHeader()))
|
||||
{
|
||||
}
|
||||
|
||||
File ModuleDescription::getHeader() const
|
||||
{
|
||||
if (moduleFolder != File())
|
||||
{
|
||||
static const char* extensions[] = { ".h", ".hpp", ".hxx" };
|
||||
|
||||
for (auto e : extensions)
|
||||
{
|
||||
auto header = moduleFolder.getChildFile (moduleFolder.getFileName() + e);
|
||||
|
||||
if (header.existsAsFile())
|
||||
return header;
|
||||
}
|
||||
}
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
StringArray ModuleDescription::getDependencies() const
|
||||
{
|
||||
auto moduleDependencies = StringArray::fromTokens (moduleInfo ["dependencies"].toString(), " \t;,", "\"'");
|
||||
moduleDependencies.trim();
|
||||
moduleDependencies.removeEmptyStrings();
|
||||
|
||||
return moduleDependencies;
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
static bool tryToAddModuleFromFolder (const File& path, AvailableModuleList::ModuleIDAndFolderList& list)
|
||||
{
|
||||
ModuleDescription m (path);
|
||||
|
||||
if (m.isValid())
|
||||
{
|
||||
list.push_back ({ m.getID(), path });
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static void addAllModulesInSubfoldersRecursively (const File& path, int depth, AvailableModuleList::ModuleIDAndFolderList& list)
|
||||
{
|
||||
if (depth > 0)
|
||||
{
|
||||
for (const auto& iter : RangedDirectoryIterator (path, false, "*", File::findDirectories))
|
||||
{
|
||||
if (auto* job = ThreadPoolJob::getCurrentThreadPoolJob())
|
||||
if (job->shouldExit())
|
||||
return;
|
||||
|
||||
auto childPath = iter.getFile();
|
||||
|
||||
if (! tryToAddModuleFromFolder (childPath, list))
|
||||
addAllModulesInSubfoldersRecursively (childPath, depth - 1, list);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void addAllModulesInFolder (const File& path, AvailableModuleList::ModuleIDAndFolderList& list)
|
||||
{
|
||||
if (! tryToAddModuleFromFolder (path, list))
|
||||
{
|
||||
static constexpr int subfolders = 3;
|
||||
addAllModulesInSubfoldersRecursively (path, subfolders, list);
|
||||
}
|
||||
}
|
||||
|
||||
struct ModuleScannerJob : public ThreadPoolJob
|
||||
{
|
||||
ModuleScannerJob (const Array<File>& paths,
|
||||
std::function<void (const AvailableModuleList::ModuleIDAndFolderList&)>&& callback)
|
||||
: ThreadPoolJob ("ModuleScannerJob"),
|
||||
pathsToScan (paths),
|
||||
completionCallback (std::move (callback))
|
||||
{
|
||||
}
|
||||
|
||||
JobStatus runJob() override
|
||||
{
|
||||
AvailableModuleList::ModuleIDAndFolderList list;
|
||||
|
||||
for (auto& p : pathsToScan)
|
||||
addAllModulesInFolder (p, list);
|
||||
|
||||
if (! shouldExit())
|
||||
{
|
||||
std::sort (list.begin(), list.end(), [] (const AvailableModuleList::ModuleIDAndFolder& m1,
|
||||
const AvailableModuleList::ModuleIDAndFolder& m2)
|
||||
{
|
||||
return m1.first.compareIgnoreCase (m2.first) < 0;
|
||||
});
|
||||
|
||||
completionCallback (list);
|
||||
}
|
||||
|
||||
return jobHasFinished;
|
||||
}
|
||||
|
||||
Array<File> pathsToScan;
|
||||
std::function<void (const AvailableModuleList::ModuleIDAndFolderList&)> completionCallback;
|
||||
};
|
||||
|
||||
ThreadPoolJob* AvailableModuleList::createScannerJob (const Array<File>& paths)
|
||||
{
|
||||
return new ModuleScannerJob (paths, [this] (AvailableModuleList::ModuleIDAndFolderList scannedModuleList)
|
||||
{
|
||||
{
|
||||
const ScopedLock swapLock (lock);
|
||||
moduleList.swap (scannedModuleList);
|
||||
}
|
||||
|
||||
listeners.call ([] (Listener& l) { MessageManager::callAsync ([&] { l.availableModulesChanged(); }); });
|
||||
});
|
||||
}
|
||||
|
||||
void AvailableModuleList::removePendingAndAddJob (ThreadPoolJob* jobToAdd)
|
||||
{
|
||||
scanPool.removeAllJobs (false, 100);
|
||||
scanPool.addJob (jobToAdd, true);
|
||||
}
|
||||
|
||||
void AvailableModuleList::scanPaths (const Array<File>& paths)
|
||||
{
|
||||
auto* job = createScannerJob (paths);
|
||||
|
||||
removePendingAndAddJob (job);
|
||||
scanPool.waitForJobToFinish (job, -1);
|
||||
}
|
||||
|
||||
void AvailableModuleList::scanPathsAsync (const Array<File>& paths)
|
||||
{
|
||||
removePendingAndAddJob (createScannerJob (paths));
|
||||
}
|
||||
|
||||
AvailableModuleList::ModuleIDAndFolderList AvailableModuleList::getAllModules() const
|
||||
{
|
||||
const ScopedLock readLock (lock);
|
||||
return moduleList;
|
||||
}
|
||||
|
||||
AvailableModuleList::ModuleIDAndFolder AvailableModuleList::getModuleWithID (const String& id) const
|
||||
{
|
||||
const ScopedLock readLock (lock);
|
||||
|
||||
for (auto& mod : moduleList)
|
||||
if (mod.first == id)
|
||||
return mod;
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
void AvailableModuleList::removeDuplicates (const ModuleIDAndFolderList& other)
|
||||
{
|
||||
const ScopedLock readLock (lock);
|
||||
|
||||
for (auto& m : other)
|
||||
{
|
||||
auto pos = std::find (moduleList.begin(), moduleList.end(), m);
|
||||
|
||||
if (pos != moduleList.end())
|
||||
moduleList.erase (pos);
|
||||
}
|
||||
}
|
||||
#include "../../Application/jucer_Headers.h"
|
||||
#include "../../ProjectSaving/jucer_ProjectSaver.h"
|
||||
#include "../../ProjectSaving/jucer_ProjectExport_Xcode.h"
|
||||
#include "../../Application/jucer_Application.h"
|
||||
|
||||
//==============================================================================
|
||||
LibraryModule::LibraryModule (const ModuleDescription& d)
|
||||
|
|
@ -201,7 +29,7 @@ LibraryModule::LibraryModule (const ModuleDescription& d)
|
|||
|
||||
void LibraryModule::writeIncludes (ProjectSaver& projectSaver, OutputStream& out)
|
||||
{
|
||||
auto& project = projectSaver.project;
|
||||
auto& project = projectSaver.getProject();
|
||||
auto& modules = project.getEnabledModules();
|
||||
|
||||
auto moduleID = getID();
|
||||
|
|
@ -215,7 +43,7 @@ void LibraryModule::writeIncludes (ProjectSaver& projectSaver, OutputStream& out
|
|||
projectSaver.copyFolder (juceModuleFolder, localModuleFolder);
|
||||
}
|
||||
|
||||
out << "#include <" << moduleInfo.moduleFolder.getFileName() << "/"
|
||||
out << "#include <" << moduleInfo.getModuleFolder().getFileName() << "/"
|
||||
<< moduleInfo.getHeader().getFileName()
|
||||
<< ">" << newLine;
|
||||
}
|
||||
|
|
@ -300,26 +128,26 @@ void LibraryModule::addLibsToExporter (ProjectExporter& exporter) const
|
|||
xcodeExporter.xcodeFrameworks.add ("AudioUnit");
|
||||
}
|
||||
|
||||
auto frameworks = moduleInfo.moduleInfo [xcodeExporter.isOSX() ? "OSXFrameworks" : "iOSFrameworks"].toString();
|
||||
auto frameworks = moduleInfo.getModuleInfo() [xcodeExporter.isOSX() ? "OSXFrameworks" : "iOSFrameworks"].toString();
|
||||
xcodeExporter.xcodeFrameworks.addTokens (frameworks, ", ", {});
|
||||
|
||||
parseAndAddLibsToList (xcodeExporter.xcodeLibs, moduleInfo.moduleInfo [exporter.isOSX() ? "OSXLibs" : "iOSLibs"].toString());
|
||||
parseAndAddLibsToList (xcodeExporter.xcodeLibs, moduleInfo.getModuleInfo() [exporter.isOSX() ? "OSXLibs" : "iOSLibs"].toString());
|
||||
}
|
||||
else if (exporter.isLinux())
|
||||
{
|
||||
parseAndAddLibsToList (exporter.linuxLibs, moduleInfo.moduleInfo ["linuxLibs"].toString());
|
||||
parseAndAddLibsToList (exporter.linuxPackages, moduleInfo.moduleInfo ["linuxPackages"].toString());
|
||||
parseAndAddLibsToList (exporter.linuxLibs, moduleInfo.getModuleInfo() ["linuxLibs"].toString());
|
||||
parseAndAddLibsToList (exporter.linuxPackages, moduleInfo.getModuleInfo() ["linuxPackages"].toString());
|
||||
}
|
||||
else if (exporter.isWindows())
|
||||
{
|
||||
if (exporter.isCodeBlocks())
|
||||
parseAndAddLibsToList (exporter.mingwLibs, moduleInfo.moduleInfo ["mingwLibs"].toString());
|
||||
parseAndAddLibsToList (exporter.mingwLibs, moduleInfo.getModuleInfo() ["mingwLibs"].toString());
|
||||
else
|
||||
parseAndAddLibsToList (exporter.windowsLibs, moduleInfo.moduleInfo ["windowsLibs"].toString());
|
||||
parseAndAddLibsToList (exporter.windowsLibs, moduleInfo.getModuleInfo() ["windowsLibs"].toString());
|
||||
}
|
||||
else if (exporter.isAndroid())
|
||||
{
|
||||
parseAndAddLibsToList (exporter.androidLibs, moduleInfo.moduleInfo ["androidLibs"].toString());
|
||||
parseAndAddLibsToList (exporter.androidLibs, moduleInfo.getModuleInfo() ["androidLibs"].toString());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -544,12 +372,12 @@ void LibraryModule::addBrowseableCode (ProjectExporter& exporter, const Array<Fi
|
|||
}
|
||||
|
||||
//==============================================================================
|
||||
EnabledModuleList::EnabledModuleList (Project& p, const ValueTree& s)
|
||||
EnabledModulesList::EnabledModulesList (Project& p, const ValueTree& s)
|
||||
: project (p), state (s)
|
||||
{
|
||||
}
|
||||
|
||||
StringArray EnabledModuleList::getAllModules() const
|
||||
StringArray EnabledModulesList::getAllModules() const
|
||||
{
|
||||
StringArray moduleIDs;
|
||||
|
||||
|
|
@ -559,13 +387,13 @@ StringArray EnabledModuleList::getAllModules() const
|
|||
return moduleIDs;
|
||||
}
|
||||
|
||||
void EnabledModuleList::createRequiredModules (OwnedArray<LibraryModule>& modules)
|
||||
void EnabledModulesList::createRequiredModules (OwnedArray<LibraryModule>& modules)
|
||||
{
|
||||
for (int i = 0; i < getNumModules(); ++i)
|
||||
modules.add (new LibraryModule (getModuleInfo (getModuleID (i))));
|
||||
}
|
||||
|
||||
void EnabledModuleList::sortAlphabetically()
|
||||
void EnabledModulesList::sortAlphabetically()
|
||||
{
|
||||
struct ModuleTreeSorter
|
||||
{
|
||||
|
|
@ -579,14 +407,14 @@ void EnabledModuleList::sortAlphabetically()
|
|||
state.sort (sorter, getUndoManager(), false);
|
||||
}
|
||||
|
||||
File EnabledModuleList::getDefaultModulesFolder() const
|
||||
File EnabledModulesList::getDefaultModulesFolder() const
|
||||
{
|
||||
File globalPath (getAppSettings().getStoredPath (Ids::defaultJuceModulePath, TargetOS::getThisOS()).get().toString());
|
||||
|
||||
if (globalPath.exists())
|
||||
return globalPath;
|
||||
|
||||
for (auto& exporterPathModule : project.getExporterPathsModuleList().getAllModules())
|
||||
for (auto& exporterPathModule : project.getExporterPathsModulesList().getAllModules())
|
||||
{
|
||||
auto f = exporterPathModule.second;
|
||||
|
||||
|
|
@ -597,12 +425,12 @@ File EnabledModuleList::getDefaultModulesFolder() const
|
|||
return File::getCurrentWorkingDirectory();
|
||||
}
|
||||
|
||||
ModuleDescription EnabledModuleList::getModuleInfo (const String& moduleID)
|
||||
ModuleDescription EnabledModulesList::getModuleInfo (const String& moduleID) const
|
||||
{
|
||||
return ModuleDescription (project.getModuleWithID (moduleID).second);
|
||||
}
|
||||
|
||||
bool EnabledModuleList::isModuleEnabled (const String& moduleID) const
|
||||
bool EnabledModulesList::isModuleEnabled (const String& moduleID) const
|
||||
{
|
||||
return state.getChildWithProperty (Ids::ID, moduleID).isValid();
|
||||
}
|
||||
|
|
@ -621,7 +449,7 @@ static void getDependencies (Project& project, const String& moduleID, StringArr
|
|||
}
|
||||
}
|
||||
|
||||
StringArray EnabledModuleList::getExtraDependenciesNeeded (const String& moduleID) const
|
||||
StringArray EnabledModulesList::getExtraDependenciesNeeded (const String& moduleID) const
|
||||
{
|
||||
StringArray dependencies, extraDepsNeeded;
|
||||
getDependencies (project, moduleID, dependencies);
|
||||
|
|
@ -633,11 +461,31 @@ StringArray EnabledModuleList::getExtraDependenciesNeeded (const String& moduleI
|
|||
return extraDepsNeeded;
|
||||
}
|
||||
|
||||
bool EnabledModuleList::doesModuleHaveHigherCppStandardThanProject (const String& moduleID)
|
||||
bool EnabledModulesList::tryToFixMissingDependencies (const String& moduleID)
|
||||
{
|
||||
auto copyLocally = areMostModulesCopiedLocally();
|
||||
auto useGlobalPath = areMostModulesUsingGlobalPath();
|
||||
|
||||
StringArray missing;
|
||||
|
||||
for (auto missingModule : getExtraDependenciesNeeded (moduleID))
|
||||
{
|
||||
auto mod = project.getModuleWithID (missingModule);
|
||||
|
||||
if (mod.second != File())
|
||||
addModule (mod.second, copyLocally, useGlobalPath);
|
||||
else
|
||||
missing.add (missingModule);
|
||||
}
|
||||
|
||||
return (missing.size() == 0);
|
||||
}
|
||||
|
||||
bool EnabledModulesList::doesModuleHaveHigherCppStandardThanProject (const String& moduleID) const
|
||||
{
|
||||
auto projectCppStandard = project.getCppStandardString();
|
||||
|
||||
if (projectCppStandard == "latest")
|
||||
if (projectCppStandard == Project::getCppStandardVars().getLast().toString())
|
||||
return false;
|
||||
|
||||
auto moduleCppStandard = getModuleInfo (moduleID).getMinimumCppStandard();
|
||||
|
|
@ -645,40 +493,40 @@ bool EnabledModuleList::doesModuleHaveHigherCppStandardThanProject (const String
|
|||
return (moduleCppStandard.getIntValue() > projectCppStandard.getIntValue());
|
||||
}
|
||||
|
||||
bool EnabledModuleList::shouldUseGlobalPath (const String& moduleID) const
|
||||
bool EnabledModulesList::shouldUseGlobalPath (const String& moduleID) const
|
||||
{
|
||||
return (bool) shouldUseGlobalPathValue (moduleID).getValue();
|
||||
}
|
||||
|
||||
Value EnabledModuleList::shouldUseGlobalPathValue (const String& moduleID) const
|
||||
Value EnabledModulesList::shouldUseGlobalPathValue (const String& moduleID) const
|
||||
{
|
||||
return state.getChildWithProperty (Ids::ID, moduleID)
|
||||
.getPropertyAsValue (Ids::useGlobalPath, getUndoManager());
|
||||
}
|
||||
|
||||
bool EnabledModuleList::shouldShowAllModuleFilesInProject (const String& moduleID) const
|
||||
bool EnabledModulesList::shouldShowAllModuleFilesInProject (const String& moduleID) const
|
||||
{
|
||||
return (bool) shouldShowAllModuleFilesInProjectValue (moduleID).getValue();
|
||||
}
|
||||
|
||||
Value EnabledModuleList::shouldShowAllModuleFilesInProjectValue (const String& moduleID) const
|
||||
Value EnabledModulesList::shouldShowAllModuleFilesInProjectValue (const String& moduleID) const
|
||||
{
|
||||
return state.getChildWithProperty (Ids::ID, moduleID)
|
||||
.getPropertyAsValue (Ids::showAllCode, getUndoManager());
|
||||
}
|
||||
|
||||
bool EnabledModuleList::shouldCopyModuleFilesLocally (const String& moduleID) const
|
||||
bool EnabledModulesList::shouldCopyModuleFilesLocally (const String& moduleID) const
|
||||
{
|
||||
return (bool) shouldCopyModuleFilesLocallyValue (moduleID).getValue();
|
||||
}
|
||||
|
||||
Value EnabledModuleList::shouldCopyModuleFilesLocallyValue (const String& moduleID) const
|
||||
Value EnabledModulesList::shouldCopyModuleFilesLocallyValue (const String& moduleID) const
|
||||
{
|
||||
return state.getChildWithProperty (Ids::ID, moduleID)
|
||||
.getPropertyAsValue (Ids::useLocalCopy, getUndoManager());
|
||||
}
|
||||
|
||||
bool EnabledModuleList::areMostModulesUsingGlobalPath() const
|
||||
bool EnabledModulesList::areMostModulesUsingGlobalPath() const
|
||||
{
|
||||
int numYes = 0, numNo = 0;
|
||||
|
||||
|
|
@ -693,7 +541,7 @@ bool EnabledModuleList::areMostModulesUsingGlobalPath() const
|
|||
return numYes > numNo;
|
||||
}
|
||||
|
||||
bool EnabledModuleList::areMostModulesCopiedLocally() const
|
||||
bool EnabledModulesList::areMostModulesCopiedLocally() const
|
||||
{
|
||||
int numYes = 0, numNo = 0;
|
||||
|
||||
|
|
@ -708,7 +556,47 @@ bool EnabledModuleList::areMostModulesCopiedLocally() const
|
|||
return numYes > numNo;
|
||||
}
|
||||
|
||||
void EnabledModuleList::addModule (const File& moduleFolder, bool copyLocally, bool useGlobalPath)
|
||||
StringArray EnabledModulesList::getModulesWithHigherCppStandardThanProject() const
|
||||
{
|
||||
StringArray list;
|
||||
|
||||
for (auto& module : getAllModules())
|
||||
if (doesModuleHaveHigherCppStandardThanProject (module))
|
||||
list.add (module);
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
StringArray EnabledModulesList::getModulesWithMissingDependencies() const
|
||||
{
|
||||
StringArray list;
|
||||
|
||||
for (auto& module : getAllModules())
|
||||
if (getExtraDependenciesNeeded (module).size() > 0)
|
||||
list.add (module);
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
String EnabledModulesList::getHighestModuleCppStandard() const
|
||||
{
|
||||
auto highestCppStandard = Project::getCppStandardVars()[0].toString();
|
||||
|
||||
for (auto& mod : getAllModules())
|
||||
{
|
||||
auto moduleCppStandard = getModuleInfo (mod).getMinimumCppStandard();
|
||||
|
||||
if (moduleCppStandard == "latest")
|
||||
return moduleCppStandard;
|
||||
|
||||
if (moduleCppStandard.getIntValue() > highestCppStandard.getIntValue())
|
||||
highestCppStandard = moduleCppStandard;
|
||||
}
|
||||
|
||||
return highestCppStandard;
|
||||
}
|
||||
|
||||
void EnabledModulesList::addModule (const File& moduleFolder, bool copyLocally, bool useGlobalPath)
|
||||
{
|
||||
ModuleDescription info (moduleFolder);
|
||||
|
||||
|
|
@ -741,7 +629,7 @@ void EnabledModuleList::addModule (const File& moduleFolder, bool copyLocally, b
|
|||
}
|
||||
}
|
||||
|
||||
void EnabledModuleList::addModuleInteractive (const String& moduleID)
|
||||
void EnabledModulesList::addModuleInteractive (const String& moduleID)
|
||||
{
|
||||
auto f = project.getModuleWithID (moduleID).second;
|
||||
|
||||
|
|
@ -754,7 +642,7 @@ void EnabledModuleList::addModuleInteractive (const String& moduleID)
|
|||
addModuleFromUserSelectedFile();
|
||||
}
|
||||
|
||||
void EnabledModuleList::addModuleFromUserSelectedFile()
|
||||
void EnabledModulesList::addModuleFromUserSelectedFile()
|
||||
{
|
||||
auto lastLocation = getDefaultModulesFolder();
|
||||
|
||||
|
|
@ -767,7 +655,7 @@ void EnabledModuleList::addModuleFromUserSelectedFile()
|
|||
}
|
||||
}
|
||||
|
||||
void EnabledModuleList::addModuleOfferingToCopy (const File& f, bool isFromUserSpecifiedFolder)
|
||||
void EnabledModulesList::addModuleOfferingToCopy (const File& f, bool isFromUserSpecifiedFolder)
|
||||
{
|
||||
ModuleDescription m (f);
|
||||
|
||||
|
|
@ -785,11 +673,11 @@ void EnabledModuleList::addModuleOfferingToCopy (const File& f, bool isFromUserS
|
|||
return;
|
||||
}
|
||||
|
||||
addModule (m.moduleFolder, areMostModulesCopiedLocally(),
|
||||
addModule (m.getModuleFolder(), areMostModulesCopiedLocally(),
|
||||
isFromUserSpecifiedFolder ? false : areMostModulesUsingGlobalPath());
|
||||
}
|
||||
|
||||
void EnabledModuleList::removeModule (String moduleID) // must be pass-by-value, and not a const ref!
|
||||
void EnabledModulesList::removeModule (String moduleID) // must be pass-by-value, and not a const ref!
|
||||
{
|
||||
for (auto i = state.getNumChildren(); --i >= 0;)
|
||||
if (state.getChild(i) [Ids::ID] == moduleID)
|
||||
|
|
@ -18,37 +18,11 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include "jucer_Project.h"
|
||||
#include "../jucer_Project.h"
|
||||
|
||||
class ProjectExporter;
|
||||
class ProjectSaver;
|
||||
|
||||
//==============================================================================
|
||||
struct ModuleDescription
|
||||
{
|
||||
ModuleDescription() = default;
|
||||
ModuleDescription (const File& folder);
|
||||
|
||||
bool isValid() const { return getID().isNotEmpty(); }
|
||||
|
||||
String getID() const { return moduleInfo [Ids::ID_uppercase].toString(); }
|
||||
String getVendor() const { return moduleInfo [Ids::vendor].toString(); }
|
||||
String getVersion() const { return moduleInfo [Ids::version].toString(); }
|
||||
String getName() const { return moduleInfo [Ids::name].toString(); }
|
||||
String getDescription() const { return moduleInfo [Ids::description].toString(); }
|
||||
String getLicense() const { return moduleInfo [Ids::license].toString(); }
|
||||
String getMinimumCppStandard() const { return moduleInfo [Ids::minimumCppStandard].toString(); }
|
||||
String getPreprocessorDefs() const { return moduleInfo [Ids::defines].toString(); }
|
||||
String getExtraSearchPaths() const { return moduleInfo [Ids::searchpaths].toString(); }
|
||||
StringArray getDependencies() const;
|
||||
|
||||
File getFolder() const { jassert (moduleFolder != File()); return moduleFolder; }
|
||||
File getHeader() const;
|
||||
|
||||
File moduleFolder;
|
||||
var moduleInfo;
|
||||
URL url;
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
class LibraryModule
|
||||
{
|
||||
|
|
@ -102,51 +76,10 @@ private:
|
|||
};
|
||||
|
||||
//==============================================================================
|
||||
class AvailableModuleList
|
||||
class EnabledModulesList
|
||||
{
|
||||
public:
|
||||
using ModuleIDAndFolder = std::pair<String, File>;
|
||||
using ModuleIDAndFolderList = std::vector<ModuleIDAndFolder>;
|
||||
|
||||
AvailableModuleList() = default;
|
||||
|
||||
void scanPaths (const Array<File>&);
|
||||
void scanPathsAsync (const Array<File>&);
|
||||
|
||||
ModuleIDAndFolderList getAllModules() const;
|
||||
ModuleIDAndFolder getModuleWithID (const String&) const;
|
||||
|
||||
void removeDuplicates (const ModuleIDAndFolderList& other);
|
||||
|
||||
//==============================================================================
|
||||
struct Listener
|
||||
{
|
||||
virtual ~Listener() {}
|
||||
|
||||
virtual void availableModulesChanged() = 0;
|
||||
};
|
||||
|
||||
void addListener (Listener* listenerToAdd) { listeners.add (listenerToAdd); }
|
||||
void removeListener (Listener* listenerToRemove) { listeners.remove (listenerToRemove); }
|
||||
|
||||
private:
|
||||
ThreadPoolJob* createScannerJob (const Array<File>&);
|
||||
void removePendingAndAddJob (ThreadPoolJob*);
|
||||
|
||||
ThreadPool scanPool { 1 };
|
||||
|
||||
ModuleIDAndFolderList moduleList;
|
||||
ListenerList<Listener> listeners;
|
||||
CriticalSection lock;
|
||||
|
||||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (AvailableModuleList)
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
class EnabledModuleList
|
||||
{
|
||||
public:
|
||||
EnabledModuleList (Project&, const ValueTree&);
|
||||
EnabledModulesList (Project&, const ValueTree&);
|
||||
|
||||
//==============================================================================
|
||||
ValueTree getState() const { return state; }
|
||||
|
|
@ -160,11 +93,14 @@ public:
|
|||
int getNumModules() const { return state.getNumChildren(); }
|
||||
String getModuleID (int index) const { return state.getChild (index) [Ids::ID].toString(); }
|
||||
|
||||
ModuleDescription getModuleInfo (const String& moduleID);
|
||||
ModuleDescription getModuleInfo (const String& moduleID) const;
|
||||
|
||||
bool isModuleEnabled (const String& moduleID) const;
|
||||
|
||||
StringArray getExtraDependenciesNeeded (const String& moduleID) const;
|
||||
bool doesModuleHaveHigherCppStandardThanProject (const String& moduleID);
|
||||
bool tryToFixMissingDependencies (const String& moduleID);
|
||||
|
||||
bool doesModuleHaveHigherCppStandardThanProject (const String& moduleID) const;
|
||||
|
||||
bool shouldUseGlobalPath (const String& moduleID) const;
|
||||
Value shouldUseGlobalPathValue (const String& moduleID) const;
|
||||
|
|
@ -178,6 +114,11 @@ public:
|
|||
bool areMostModulesUsingGlobalPath() const;
|
||||
bool areMostModulesCopiedLocally() const;
|
||||
|
||||
StringArray getModulesWithHigherCppStandardThanProject() const;
|
||||
StringArray getModulesWithMissingDependencies() const;
|
||||
|
||||
String getHighestModuleCppStandard() const;
|
||||
|
||||
//==============================================================================
|
||||
void addModule (const File& moduleManifestFile, bool copyLocally, bool useGlobalPath);
|
||||
void addModuleInteractive (const String& moduleID);
|
||||
|
|
@ -192,5 +133,5 @@ private:
|
|||
Project& project;
|
||||
ValueTree state;
|
||||
|
||||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (EnabledModuleList)
|
||||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (EnabledModulesList)
|
||||
};
|
||||
|
|
@ -108,18 +108,11 @@ public:
|
|||
void handlePopupMenuResult (int resultCode) override
|
||||
{
|
||||
if (resultCode == 1)
|
||||
{
|
||||
exporter->addNewConfiguration (false);
|
||||
}
|
||||
else if (resultCode == 2)
|
||||
{
|
||||
const ScopedValueSetter<String> valueSetter (project.specifiedExporterToSave, exporter->getName(), {});
|
||||
project.save (true, true);
|
||||
}
|
||||
project.saveProject (exporter.get());
|
||||
else if (resultCode == 3)
|
||||
{
|
||||
deleteAllSelectedItems();
|
||||
}
|
||||
}
|
||||
|
||||
var getDragSourceDescription() override
|
||||
|
|
|
|||
|
|
@ -110,7 +110,7 @@ public:
|
|||
{
|
||||
auto f = filesToTrash.getUnchecked(i);
|
||||
|
||||
om.closeFile (f, false);
|
||||
om.closeFile (f, OpenDocumentManager::SaveIfNeeded::no);
|
||||
|
||||
if (! f.moveToTrash())
|
||||
{
|
||||
|
|
@ -129,7 +129,7 @@ public:
|
|||
pcc->hideEditor();
|
||||
}
|
||||
|
||||
om.closeFile (itemToRemove->getFile(), false);
|
||||
om.closeFile (itemToRemove->getFile(), OpenDocumentManager::SaveIfNeeded::no);
|
||||
itemToRemove->deleteItem();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -61,9 +61,8 @@ class LiveBuildTab : public Component,
|
|||
public:
|
||||
LiveBuildTab (const CompileEngineChildProcess::Ptr& child, String lastErrorMessage)
|
||||
{
|
||||
settingsButton.reset (new IconButton ("Settings", &getIcons().settings));
|
||||
addAndMakeVisible (settingsButton.get());
|
||||
settingsButton->onClick = [this]
|
||||
addAndMakeVisible (settingsButton);
|
||||
settingsButton.onClick = [this]
|
||||
{
|
||||
if (auto* pcc = findParentComponentOfClass<ProjectContentComponent>())
|
||||
pcc->showLiveBuildSettings();
|
||||
|
|
@ -122,9 +121,9 @@ public:
|
|||
{
|
||||
auto bounds = getLocalBounds();
|
||||
|
||||
settingsButton->setBounds (bounds.removeFromBottom (25)
|
||||
.removeFromRight (25)
|
||||
.reduced (3));
|
||||
settingsButton.setBounds (bounds.removeFromBottom (25)
|
||||
.removeFromRight (25)
|
||||
.reduced (3));
|
||||
|
||||
if (errorMessageLabel != nullptr)
|
||||
{
|
||||
|
|
@ -155,7 +154,7 @@ public:
|
|||
private:
|
||||
OwnedArray<ConcertinaHeader> headers;
|
||||
ConcertinaPanel concertinaPanel;
|
||||
std::unique_ptr<IconButton> settingsButton;
|
||||
IconButton settingsButton { "Settings", getIcons().settings };
|
||||
|
||||
std::unique_ptr<TextButton> downloadButton, enableButton;
|
||||
std::unique_ptr<Label> errorMessageLabel;
|
||||
|
|
|
|||
|
|
@ -361,17 +361,21 @@ private:
|
|||
|
||||
void fixDependencies()
|
||||
{
|
||||
if (! tryToFix())
|
||||
auto& enabledModules = project.getEnabledModules();
|
||||
|
||||
if (enabledModules.tryToFixMissingDependencies (moduleID))
|
||||
{
|
||||
missingDependencies.clear();
|
||||
}
|
||||
else
|
||||
{
|
||||
missingDependencies = enabledModules.getExtraDependenciesNeeded (moduleID);
|
||||
|
||||
AlertWindow::showMessageBoxAsync (AlertWindow::WarningIcon,
|
||||
"Adding Missing Dependencies",
|
||||
"Couldn't locate some of these modules - you'll need to find their "
|
||||
"folders manually and add them to the list.");
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
refreshAndReselectItem();
|
||||
}
|
||||
|
||||
void resized() override
|
||||
|
|
@ -381,59 +385,11 @@ private:
|
|||
|
||||
private:
|
||||
Project& project;
|
||||
|
||||
String moduleID;
|
||||
StringArray missingDependencies;
|
||||
TextButton fixButton { "Add Required Modules" };
|
||||
|
||||
bool tryToFix()
|
||||
{
|
||||
auto& enabledModules = project.getEnabledModules();
|
||||
|
||||
auto copyLocally = enabledModules.areMostModulesCopiedLocally();
|
||||
auto useGlobalPath = enabledModules.areMostModulesUsingGlobalPath();
|
||||
|
||||
StringArray missing;
|
||||
|
||||
for (auto missingModule : missingDependencies)
|
||||
{
|
||||
auto mod = project.getModuleWithID (missingModule);
|
||||
|
||||
if (mod.second != File())
|
||||
enabledModules.addModule (mod.second, copyLocally, useGlobalPath);
|
||||
else
|
||||
missing.add (missingModule);
|
||||
}
|
||||
|
||||
missingDependencies.swapWith (missing);
|
||||
return (missingDependencies.size() == 0);
|
||||
}
|
||||
|
||||
void refreshAndReselectItem()
|
||||
{
|
||||
if (auto* settingsPanel = findParentComponentOfClass<ModuleSettingsPanel>())
|
||||
{
|
||||
if (settingsPanel->modulesTree == nullptr)
|
||||
return;
|
||||
|
||||
auto* rootItem = settingsPanel->modulesTree->getRootItem();
|
||||
|
||||
if (rootItem == nullptr)
|
||||
return;
|
||||
|
||||
for (int i = 0; i < rootItem->getNumSubItems(); ++i)
|
||||
{
|
||||
if (auto* subItem = dynamic_cast<ProjectTreeItemBase*> (rootItem->getSubItem (i)))
|
||||
{
|
||||
if (subItem->getDisplayName() == moduleID)
|
||||
{
|
||||
subItem->setSelected (true, true);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (MissingDependenciesComponent)
|
||||
};
|
||||
|
||||
|
|
@ -468,28 +424,30 @@ private:
|
|||
//==============================================================================
|
||||
class EnabledModulesItem : public ProjectTreeItemBase,
|
||||
private Value::Listener,
|
||||
private AvailableModuleList::Listener
|
||||
private AvailableModulesList::Listener
|
||||
{
|
||||
public:
|
||||
EnabledModulesItem (Project& p)
|
||||
: project (p),
|
||||
moduleListTree (project.getEnabledModules().getState())
|
||||
modulesListTree (project.getEnabledModules().getState())
|
||||
{
|
||||
moduleListTree.addListener (this);
|
||||
modulesListTree.addListener (this);
|
||||
|
||||
projectCppStandardValue.referTo (project.getProjectValue (Ids::cppLanguageStandard));
|
||||
projectCppStandardValue.addListener (this);
|
||||
|
||||
ProjucerApplication::getApp().getJUCEPathModuleList().addListener (this);
|
||||
ProjucerApplication::getApp().getUserPathsModuleList().addListener (this);
|
||||
project.getExporterPathsModuleList().addListener (this);
|
||||
ProjucerApplication::getApp().getJUCEPathModulesList().addListener (this);
|
||||
ProjucerApplication::getApp().getUserPathsModulesList().addListener (this);
|
||||
|
||||
project.getExporterPathsModulesList().addListener (this);
|
||||
}
|
||||
|
||||
~EnabledModulesItem() override
|
||||
{
|
||||
ProjucerApplication::getApp().getJUCEPathModuleList().removeListener (this);
|
||||
ProjucerApplication::getApp().getUserPathsModuleList().removeListener (this);
|
||||
project.getExporterPathsModuleList().removeListener (this);
|
||||
ProjucerApplication::getApp().getJUCEPathModulesList().removeListener (this);
|
||||
ProjucerApplication::getApp().getUserPathsModulesList().removeListener (this);
|
||||
|
||||
project.getExporterPathsModulesList().removeListener (this);
|
||||
}
|
||||
|
||||
int getItemHeight() const override { return 22; }
|
||||
|
|
@ -539,7 +497,7 @@ public:
|
|||
}
|
||||
|
||||
for (int i = 0; i < modules.size(); ++i)
|
||||
project.getEnabledModules().addModule (modules.getReference(i).moduleFolder,
|
||||
project.getEnabledModules().addModule (modules.getReference (i).getModuleFolder(),
|
||||
project.getEnabledModules().areMostModulesCopiedLocally(),
|
||||
project.getEnabledModules().areMostModulesUsingGlobalPath());
|
||||
}
|
||||
|
|
@ -560,7 +518,7 @@ public:
|
|||
// JUCE path
|
||||
PopupMenu jucePathModules;
|
||||
|
||||
for (auto& mod : ProjucerApplication::getApp().getJUCEPathModuleList().getAllModules())
|
||||
for (auto& mod : ProjucerApplication::getApp().getJUCEPathModulesList().getAllModules())
|
||||
jucePathModules.addItem (index++, mod.first, ! enabledModules.isModuleEnabled (mod.first));
|
||||
|
||||
jucePathModules.addSeparator();
|
||||
|
|
@ -572,7 +530,7 @@ public:
|
|||
index = 200;
|
||||
PopupMenu userPathModules;
|
||||
|
||||
for (auto& mod : ProjucerApplication::getApp().getUserPathsModuleList().getAllModules())
|
||||
for (auto& mod : ProjucerApplication::getApp().getUserPathsModulesList().getAllModules())
|
||||
userPathModules.addItem (index++, mod.first, ! enabledModules.isModuleEnabled (mod.first));
|
||||
|
||||
userPathModules.addSeparator();
|
||||
|
|
@ -584,7 +542,7 @@ public:
|
|||
index = 300;
|
||||
PopupMenu exporterPathModules;
|
||||
|
||||
for (auto& mod : project.getExporterPathsModuleList().getAllModules())
|
||||
for (auto& mod : project.getExporterPathsModulesList().getAllModules())
|
||||
exporterPathModules.addItem (index++, mod.first, ! enabledModules.isModuleEnabled (mod.first));
|
||||
|
||||
exporterPathModules.addSeparator();
|
||||
|
|
@ -615,22 +573,22 @@ public:
|
|||
}
|
||||
else if (resultCode > 0)
|
||||
{
|
||||
std::vector<AvailableModuleList::ModuleIDAndFolder> list;
|
||||
std::vector<AvailableModulesList::ModuleIDAndFolder> list;
|
||||
int offset = -1;
|
||||
|
||||
if (resultCode < 200)
|
||||
{
|
||||
list = ProjucerApplication::getApp().getJUCEPathModuleList().getAllModules();
|
||||
list = ProjucerApplication::getApp().getJUCEPathModulesList().getAllModules();
|
||||
offset = 100;
|
||||
}
|
||||
else if (resultCode < 300)
|
||||
{
|
||||
list = ProjucerApplication::getApp().getUserPathsModuleList().getAllModules();
|
||||
list = ProjucerApplication::getApp().getUserPathsModulesList().getAllModules();
|
||||
offset = 200;
|
||||
}
|
||||
else if (resultCode < 400)
|
||||
{
|
||||
list = project.getExporterPathsModuleList().getAllModules();
|
||||
list = project.getExporterPathsModulesList().getAllModules();
|
||||
offset = 300;
|
||||
}
|
||||
|
||||
|
|
@ -646,13 +604,20 @@ public:
|
|||
|
||||
void refreshIfNeeded (ValueTree& changedTree)
|
||||
{
|
||||
if (changedTree == moduleListTree)
|
||||
if (changedTree == modulesListTree)
|
||||
{
|
||||
auto selectedID = getSelectedItemID();
|
||||
|
||||
refreshSubItems();
|
||||
|
||||
if (selectedID.isNotEmpty())
|
||||
setSelectedItem (selectedID);
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
Project& project;
|
||||
ValueTree moduleListTree;
|
||||
ValueTree modulesListTree;
|
||||
Value projectCppStandardValue;
|
||||
|
||||
//==============================================================================
|
||||
|
|
@ -676,22 +641,47 @@ private:
|
|||
|
||||
void removeDuplicateModules()
|
||||
{
|
||||
auto jucePathModuleList = ProjucerApplication::getApp().getJUCEPathModuleList().getAllModules();
|
||||
auto jucePathModulesList = ProjucerApplication::getApp().getJUCEPathModulesList().getAllModules();
|
||||
|
||||
auto& userPathModules = ProjucerApplication::getApp().getUserPathsModuleList();
|
||||
userPathModules.removeDuplicates (jucePathModuleList);
|
||||
auto& userPathModules = ProjucerApplication::getApp().getUserPathsModulesList();
|
||||
userPathModules.removeDuplicates (jucePathModulesList);
|
||||
|
||||
auto& exporterPathModules = project.getExporterPathsModuleList();
|
||||
exporterPathModules.removeDuplicates (jucePathModuleList);
|
||||
auto& exporterPathModules = project.getExporterPathsModulesList();
|
||||
exporterPathModules.removeDuplicates (jucePathModulesList);
|
||||
exporterPathModules.removeDuplicates (userPathModules.getAllModules());
|
||||
}
|
||||
|
||||
void availableModulesChanged() override
|
||||
void availableModulesChanged (AvailableModulesList*) override
|
||||
{
|
||||
removeDuplicateModules();
|
||||
refreshSubItems();
|
||||
}
|
||||
|
||||
String getSelectedItemID() const
|
||||
{
|
||||
for (int i = 0; i < getNumSubItems(); ++i)
|
||||
if (auto* item = getSubItem (i))
|
||||
if (item->isSelected())
|
||||
return item->getUniqueName();
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
void setSelectedItem (const String& itemID)
|
||||
{
|
||||
for (int i = 0; i < getNumSubItems(); ++i)
|
||||
{
|
||||
if (auto* item = getSubItem (i))
|
||||
{
|
||||
if (item->getUniqueName() == itemID)
|
||||
{
|
||||
item->setSelected (true, true);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (EnabledModulesItem)
|
||||
};
|
||||
|
|
|
|||
|
|
@ -165,35 +165,27 @@ public:
|
|||
{
|
||||
if (hasAddButton)
|
||||
{
|
||||
addButton.reset (new IconButton ("Add", &getIcons().plus));
|
||||
addButton = std::make_unique<IconButton> ("Add", getIcons().plus);
|
||||
addAndMakeVisible (addButton.get());
|
||||
addButton->onClick = [this] { showAddMenu(); };
|
||||
}
|
||||
|
||||
if (hasSettingsButton)
|
||||
{
|
||||
settingsButton.reset (new IconButton ("Settings", &getIcons().settings));
|
||||
settingsButton = std::make_unique<IconButton> ("Settings", getIcons().settings);
|
||||
addAndMakeVisible (settingsButton.get());
|
||||
settingsButton->onClick = [this] { showSettings(); };
|
||||
}
|
||||
|
||||
if (hasFindPanel)
|
||||
{
|
||||
findPanel.reset (new FindPanel ([this] (const String& filter) { treeToDisplay->rootItem->setSearchFilter (filter); }));
|
||||
findPanel = std::make_unique<FindPanel> ([this] (const String& filter) { treeToDisplay->rootItem->setSearchFilter (filter); });
|
||||
addAndMakeVisible (findPanel.get());
|
||||
}
|
||||
|
||||
addAndMakeVisible (treeToDisplay.get());
|
||||
}
|
||||
|
||||
~ConcertinaTreeComponent() override
|
||||
{
|
||||
treeToDisplay.reset();
|
||||
addButton.reset();
|
||||
findPanel.reset();
|
||||
settingsButton.reset();
|
||||
}
|
||||
|
||||
void resized() override
|
||||
{
|
||||
auto bounds = getLocalBounds();
|
||||
|
|
|
|||
|
|
@ -30,17 +30,19 @@
|
|||
#include "../../LiveBuildEngine/jucer_CompileEngineClient.h"
|
||||
|
||||
//==============================================================================
|
||||
HeaderComponent::HeaderComponent()
|
||||
HeaderComponent::HeaderComponent (ProjectContentComponent* pcc)
|
||||
: projectContentComponent (pcc)
|
||||
{
|
||||
addAndMakeVisible (configLabel);
|
||||
addAndMakeVisible (exporterBox);
|
||||
|
||||
exporterBox.onChange = [this] { updateExporterButton(); };
|
||||
|
||||
juceIcon.reset (new ImageComponent ("icon"));
|
||||
addAndMakeVisible (juceIcon.get());
|
||||
juceIcon->setImage (ImageCache::getFromMemory (BinaryData::juce_icon_png, BinaryData::juce_icon_pngSize),
|
||||
RectanglePlacement::centred);
|
||||
juceIcon.setImage (ImageCache::getFromMemory (BinaryData::juce_icon_png, BinaryData::juce_icon_pngSize), RectanglePlacement::centred);
|
||||
addAndMakeVisible (juceIcon);
|
||||
|
||||
addAndMakeVisible (userAvatar);
|
||||
userAvatar.addChangeListener (this);
|
||||
|
||||
projectNameLabel.setText ({}, dontSendNotification);
|
||||
addAndMakeVisible (projectNameLabel);
|
||||
|
|
@ -52,7 +54,7 @@ HeaderComponent::~HeaderComponent()
|
|||
{
|
||||
if (childProcess != nullptr)
|
||||
{
|
||||
childProcess->activityList.removeChangeListener(this);
|
||||
childProcess->activityList.removeChangeListener (this);
|
||||
childProcess->errorList.removeChangeListener (this);
|
||||
}
|
||||
}
|
||||
|
|
@ -63,33 +65,36 @@ void HeaderComponent::resized()
|
|||
auto bounds = getLocalBounds();
|
||||
configLabel.setFont ({ bounds.getHeight() / 3.0f });
|
||||
|
||||
//==============================================================================
|
||||
{
|
||||
auto headerBounds = bounds.removeFromLeft (tabsWidth);
|
||||
|
||||
const int buttonSize = 25;
|
||||
auto buttonBounds = headerBounds.removeFromRight (buttonSize);
|
||||
|
||||
projectSettingsButton->setBounds (buttonBounds.removeFromBottom (buttonSize).reduced (2));
|
||||
projectSettingsButton.setBounds (buttonBounds.removeFromBottom (buttonSize).reduced (2));
|
||||
|
||||
juceIcon->setBounds (headerBounds.removeFromLeft (headerBounds.getHeight()).reduced (2));
|
||||
juceIcon.setBounds (headerBounds.removeFromLeft (headerBounds.getHeight()).reduced (2));
|
||||
|
||||
headerBounds.removeFromRight (5);
|
||||
projectNameLabel.setBounds (headerBounds);
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
auto exporterWidth = jmin (400, bounds.getWidth() / 2);
|
||||
Rectangle<int> exporterBounds (0, 0, exporterWidth, bounds.getHeight());
|
||||
{
|
||||
auto exporterWidth = jmin (400, bounds.getWidth() / 2);
|
||||
Rectangle<int> exporterBounds (0, 0, exporterWidth, bounds.getHeight());
|
||||
|
||||
exporterBounds.setCentre (bounds.getCentre());
|
||||
exporterBounds.setCentre (bounds.getCentre());
|
||||
|
||||
runAppButton->setBounds (exporterBounds.removeFromRight (exporterBounds.getHeight()).reduced (2));
|
||||
saveAndOpenInIDEButton->setBounds (exporterBounds.removeFromRight (exporterBounds.getHeight()).reduced (2));
|
||||
runAppButton.setBounds (exporterBounds.removeFromRight (exporterBounds.getHeight()).reduced (2));
|
||||
saveAndOpenInIDEButton.setBounds (exporterBounds.removeFromRight (exporterBounds.getHeight()).reduced (2));
|
||||
|
||||
exporterBounds.removeFromRight (5);
|
||||
exporterBox.setBounds (exporterBounds.removeFromBottom (roundToInt (exporterBounds.getHeight() / 1.8f)));
|
||||
configLabel.setBounds (exporterBounds);
|
||||
exporterBounds.removeFromRight (5);
|
||||
exporterBox.setBounds (exporterBounds.removeFromBottom (roundToInt (exporterBounds.getHeight() / 1.8f)));
|
||||
configLabel.setBounds (exporterBounds);
|
||||
}
|
||||
|
||||
userAvatar.setBounds (bounds.removeFromRight (userAvatar.isDisplaingGPLLogo() ? roundToInt (bounds.getHeight() * 1.9f)
|
||||
: bounds.getHeight()).reduced (2));
|
||||
}
|
||||
|
||||
void HeaderComponent::paint (Graphics& g)
|
||||
|
|
@ -98,48 +103,53 @@ void HeaderComponent::paint (Graphics& g)
|
|||
|
||||
if (isBuilding)
|
||||
getLookAndFeel().drawSpinningWaitAnimation (g, findColour (treeIconColourId),
|
||||
runAppButton->getX(), runAppButton->getY(),
|
||||
runAppButton->getWidth(), runAppButton->getHeight());
|
||||
runAppButton.getX(), runAppButton.getY(),
|
||||
runAppButton.getWidth(), runAppButton.getHeight());
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
void HeaderComponent::setCurrentProject (Project* p) noexcept
|
||||
void HeaderComponent::setCurrentProject (Project* newProject)
|
||||
{
|
||||
project = p;
|
||||
|
||||
exportersTree = project->getExporters();
|
||||
exportersTree.addListener (this);
|
||||
updateExporters();
|
||||
|
||||
projectNameValue.referTo (project->getProjectValue (Ids::name));
|
||||
projectNameValue.addListener (this);
|
||||
updateName();
|
||||
|
||||
isBuilding = false;
|
||||
stopTimer();
|
||||
repaint();
|
||||
|
||||
childProcess = ProjucerApplication::getApp().childProcessCache->getExisting (*project);
|
||||
projectNameLabel.setText ({}, dontSendNotification);
|
||||
|
||||
if (childProcess != nullptr)
|
||||
{
|
||||
childProcess->activityList.addChangeListener (this);
|
||||
childProcess->errorList.addChangeListener (this);
|
||||
project = newProject;
|
||||
|
||||
runAppButton->setTooltip ({});
|
||||
runAppButton->setEnabled (true);
|
||||
}
|
||||
else
|
||||
if (project != nullptr)
|
||||
{
|
||||
runAppButton->setTooltip ("Enable live-build engine to launch application");
|
||||
runAppButton->setEnabled (false);
|
||||
exportersTree = project->getExporters();
|
||||
exportersTree.addListener (this);
|
||||
updateExporters();
|
||||
|
||||
projectNameValue.referTo (project->getProjectValue (Ids::name));
|
||||
projectNameValue.addListener (this);
|
||||
updateName();
|
||||
|
||||
childProcess = ProjucerApplication::getApp().childProcessCache->getExisting (*project);
|
||||
|
||||
if (childProcess != nullptr)
|
||||
{
|
||||
childProcess->activityList.addChangeListener (this);
|
||||
childProcess->errorList.addChangeListener (this);
|
||||
|
||||
runAppButton.setTooltip ({});
|
||||
runAppButton.setEnabled (true);
|
||||
}
|
||||
else
|
||||
{
|
||||
runAppButton.setTooltip ("Enable live-build engine to launch application");
|
||||
runAppButton.setEnabled (false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
void HeaderComponent::updateExporters() noexcept
|
||||
void HeaderComponent::updateExporters()
|
||||
{
|
||||
auto selectedName = getSelectedExporterName();
|
||||
auto selectedExporter = getSelectedExporter();
|
||||
|
||||
exporterBox.clear();
|
||||
auto preferredExporterIndex = -1;
|
||||
|
|
@ -149,7 +159,7 @@ void HeaderComponent::updateExporters() noexcept
|
|||
{
|
||||
exporterBox.addItem (exporter->getName(), i + 1);
|
||||
|
||||
if (selectedName == exporter->getName())
|
||||
if (selectedExporter != nullptr && exporter->getName() == selectedExporter->getName())
|
||||
exporterBox.setSelectedId (i + 1);
|
||||
|
||||
if (exporter->getName().contains (ProjectExporter::getCurrentPlatformExporterName()) && preferredExporterIndex == -1)
|
||||
|
|
@ -177,31 +187,56 @@ void HeaderComponent::updateExporters() noexcept
|
|||
updateExporterButton();
|
||||
}
|
||||
|
||||
String HeaderComponent::getSelectedExporterName() const noexcept
|
||||
std::unique_ptr<ProjectExporter> HeaderComponent::getSelectedExporter() const
|
||||
{
|
||||
return exporterBox.getItemText (exporterBox.getSelectedItemIndex());
|
||||
if (project != nullptr)
|
||||
{
|
||||
int i = 0;
|
||||
auto selectedIndex = exporterBox.getSelectedItemIndex();
|
||||
|
||||
for (Project::ExporterIterator exporter (*project); exporter.next();)
|
||||
if (i++ == selectedIndex)
|
||||
return std::move (exporter.exporter);
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
bool HeaderComponent::canCurrentExporterLaunchProject() const noexcept
|
||||
bool HeaderComponent::canCurrentExporterLaunchProject() const
|
||||
{
|
||||
for (Project::ExporterIterator exporter (*project); exporter.next();)
|
||||
if (exporter->getName() == getSelectedExporterName() && exporter->canLaunchProject())
|
||||
return true;
|
||||
if (project != nullptr)
|
||||
{
|
||||
if (auto selectedExporter = getSelectedExporter())
|
||||
{
|
||||
for (Project::ExporterIterator exporter (*project); exporter.next();)
|
||||
if (exporter->canLaunchProject() && exporter->getName() == selectedExporter->getName())
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
void HeaderComponent::sidebarTabsWidthChanged (int newWidth) noexcept
|
||||
void HeaderComponent::sidebarTabsWidthChanged (int newWidth)
|
||||
{
|
||||
tabsWidth = newWidth;
|
||||
resized();
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
void HeaderComponent::changeListenerCallback (ChangeBroadcaster*)
|
||||
void HeaderComponent::liveBuildEnablementChanged (bool isEnabled)
|
||||
{
|
||||
if (childProcess != nullptr)
|
||||
runAppButton.setVisible (isEnabled);
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
void HeaderComponent::changeListenerCallback (ChangeBroadcaster* source)
|
||||
{
|
||||
if (source == &userAvatar)
|
||||
{
|
||||
resized();
|
||||
}
|
||||
else if (childProcess != nullptr && source == &childProcess->activityList)
|
||||
{
|
||||
if (childProcess->activityList.getNumActivities() > 0)
|
||||
buildPing();
|
||||
|
|
@ -221,30 +256,37 @@ void HeaderComponent::timerCallback()
|
|||
}
|
||||
|
||||
//==============================================================================
|
||||
void HeaderComponent::initialiseButtons() noexcept
|
||||
void HeaderComponent::initialiseButtons()
|
||||
{
|
||||
auto& icons = getIcons();
|
||||
addAndMakeVisible (projectSettingsButton);
|
||||
projectSettingsButton.onClick = [this] { projectContentComponent->showProjectSettings(); };
|
||||
|
||||
projectSettingsButton.reset (new IconButton ("Project Settings", &icons.settings));
|
||||
addAndMakeVisible (projectSettingsButton.get());
|
||||
projectSettingsButton->onClick = [this]
|
||||
addAndMakeVisible (saveAndOpenInIDEButton);
|
||||
saveAndOpenInIDEButton.setBackgroundColour (Colours::white);
|
||||
saveAndOpenInIDEButton.setIconInset (7);
|
||||
saveAndOpenInIDEButton.onClick = [this]
|
||||
{
|
||||
if (auto* pcc = findParentComponentOfClass<ProjectContentComponent>())
|
||||
pcc->showProjectSettings();
|
||||
if (project != nullptr)
|
||||
{
|
||||
if (project->hasIncompatibleLicenseTypeAndSplashScreenSetting())
|
||||
{
|
||||
auto child = project->getProjectMessages().getChildWithName (ProjectMessages::Ids::warning)
|
||||
.getChildWithName (ProjectMessages::Ids::incompatibleLicense);
|
||||
|
||||
if (child.isValid())
|
||||
child.setProperty (ProjectMessages::Ids::isVisible, true, nullptr);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (auto exporter = getSelectedExporter())
|
||||
project->openProjectInIDE (*exporter, true);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
saveAndOpenInIDEButton.reset (new IconButton ("Save and Open in IDE", nullptr));
|
||||
addAndMakeVisible (saveAndOpenInIDEButton.get());
|
||||
saveAndOpenInIDEButton->isIDEButton = true;
|
||||
saveAndOpenInIDEButton->onClick = [this]
|
||||
{
|
||||
if (auto* pcc = findParentComponentOfClass<ProjectContentComponent>())
|
||||
pcc->openInSelectedIDE (true);
|
||||
};
|
||||
|
||||
runAppButton.reset (new IconButton ("Run Application", &icons.play));
|
||||
addAndMakeVisible (runAppButton.get());
|
||||
runAppButton->onClick = [this]
|
||||
addAndMakeVisible (runAppButton);
|
||||
runAppButton.setIconInset (7);
|
||||
runAppButton.onClick = [this]
|
||||
{
|
||||
if (childProcess != nullptr)
|
||||
childProcess->launchApp();
|
||||
|
|
@ -253,22 +295,26 @@ void HeaderComponent::initialiseButtons() noexcept
|
|||
updateExporterButton();
|
||||
}
|
||||
|
||||
void HeaderComponent::updateName() noexcept
|
||||
void HeaderComponent::updateName()
|
||||
{
|
||||
projectNameLabel.setText (project->getDocumentTitle(), dontSendNotification);
|
||||
if (project != nullptr)
|
||||
projectNameLabel.setText (project->getDocumentTitle(), dontSendNotification);
|
||||
}
|
||||
|
||||
void HeaderComponent::updateExporterButton() noexcept
|
||||
void HeaderComponent::updateExporterButton()
|
||||
{
|
||||
auto currentExporterName = getSelectedExporterName();
|
||||
|
||||
for (auto info : ProjectExporter::getExporterTypes())
|
||||
if (auto selectedExporter = getSelectedExporter())
|
||||
{
|
||||
if (currentExporterName.contains (info.name))
|
||||
auto selectedName = selectedExporter->getName();
|
||||
|
||||
for (auto info : ProjectExporter::getExporterTypes())
|
||||
{
|
||||
saveAndOpenInIDEButton->iconImage = info.getIcon();
|
||||
saveAndOpenInIDEButton->repaint();
|
||||
saveAndOpenInIDEButton->setEnabled (canCurrentExporterLaunchProject());
|
||||
if (selectedName.contains (info.name))
|
||||
{
|
||||
saveAndOpenInIDEButton.setImage (info.getIcon());
|
||||
saveAndOpenInIDEButton.repaint();
|
||||
saveAndOpenInIDEButton.setEnabled (canCurrentExporterLaunchProject());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -279,8 +325,8 @@ void HeaderComponent::buildPing()
|
|||
if (! isTimerRunning())
|
||||
{
|
||||
isBuilding = true;
|
||||
runAppButton->setEnabled (false);
|
||||
runAppButton->setTooltip ("Building...");
|
||||
runAppButton.setEnabled (false);
|
||||
runAppButton.setTooltip ("Building...");
|
||||
|
||||
startTimer (50);
|
||||
}
|
||||
|
|
@ -306,23 +352,23 @@ void HeaderComponent::setRunAppButtonState (bool buildWasSuccessful)
|
|||
{
|
||||
if (childProcess->isAppRunning() || (! childProcess->isAppRunning() && childProcess->canLaunchApp()))
|
||||
{
|
||||
runAppButton->setTooltip ("Launch application");
|
||||
runAppButton.setTooltip ("Launch application");
|
||||
shouldEnableButton = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
runAppButton->setTooltip ("Application can't be launched");
|
||||
runAppButton.setTooltip ("Application can't be launched");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
runAppButton->setTooltip ("Enable live-build engine to launch application");
|
||||
runAppButton.setTooltip ("Enable live-build engine to launch application");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
runAppButton->setTooltip ("Error building application");
|
||||
runAppButton.setTooltip ("Error building application");
|
||||
}
|
||||
|
||||
runAppButton->setEnabled (shouldEnableButton);
|
||||
runAppButton.setEnabled (shouldEnableButton);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -20,8 +20,11 @@
|
|||
|
||||
#include "../../Application/jucer_Headers.h"
|
||||
#include "../../Utility/UI/jucer_IconButton.h"
|
||||
#include "jucer_UserAvatarComponent.h"
|
||||
|
||||
class Project;
|
||||
class ProjectContentComponent;
|
||||
class ProjectExporter;
|
||||
class CompileEngineChildProcess;
|
||||
|
||||
//==============================================================================
|
||||
|
|
@ -32,7 +35,7 @@ class HeaderComponent : public Component,
|
|||
private Timer
|
||||
{
|
||||
public:
|
||||
HeaderComponent();
|
||||
HeaderComponent (ProjectContentComponent* projectContentComponent);
|
||||
~HeaderComponent() override;
|
||||
|
||||
//==============================================================================
|
||||
|
|
@ -40,13 +43,14 @@ public:
|
|||
void paint (Graphics&) override;
|
||||
|
||||
//==============================================================================
|
||||
void setCurrentProject (Project*) noexcept;
|
||||
void setCurrentProject (Project*);
|
||||
|
||||
void updateExporters() noexcept;
|
||||
String getSelectedExporterName() const noexcept;
|
||||
bool canCurrentExporterLaunchProject() const noexcept;
|
||||
void updateExporters();
|
||||
std::unique_ptr<ProjectExporter> getSelectedExporter() const;
|
||||
bool canCurrentExporterLaunchProject() const;
|
||||
|
||||
void sidebarTabsWidthChanged (int newWidth) noexcept;
|
||||
void sidebarTabsWidthChanged (int newWidth);
|
||||
void liveBuildEnablementChanged (bool isEnabled);
|
||||
|
||||
private:
|
||||
//==============================================================================
|
||||
|
|
@ -59,17 +63,17 @@ private:
|
|||
void valueTreeChildRemoved (ValueTree& parentTree, ValueTree&, int) override { updateIfNeeded (parentTree); }
|
||||
void valueTreeChildOrderChanged (ValueTree& parentTree, int, int) override { updateIfNeeded (parentTree); }
|
||||
|
||||
void updateIfNeeded (ValueTree tree) noexcept
|
||||
void updateIfNeeded (ValueTree tree)
|
||||
{
|
||||
if (tree == exportersTree)
|
||||
updateExporters();
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
void initialiseButtons() noexcept;
|
||||
void initialiseButtons();
|
||||
|
||||
void updateName() noexcept;
|
||||
void updateExporterButton() noexcept;
|
||||
void updateName();
|
||||
void updateExporterButton();
|
||||
|
||||
//==============================================================================
|
||||
void buildPing();
|
||||
|
|
@ -80,17 +84,21 @@ private:
|
|||
int tabsWidth = 200;
|
||||
bool isBuilding = false;
|
||||
|
||||
ProjectContentComponent* projectContentComponent = nullptr;
|
||||
Project* project = nullptr;
|
||||
ValueTree exportersTree;
|
||||
|
||||
Value projectNameValue;
|
||||
|
||||
ComboBox exporterBox;
|
||||
Label configLabel { "Config Label", "Selected exporter" },
|
||||
projectNameLabel;
|
||||
Label configLabel { "Config Label", "Selected exporter" }, projectNameLabel;
|
||||
|
||||
std::unique_ptr<ImageComponent> juceIcon;
|
||||
std::unique_ptr<IconButton> projectSettingsButton, saveAndOpenInIDEButton, runAppButton;
|
||||
ImageComponent juceIcon;
|
||||
UserAvatarComponent userAvatar { true, true };
|
||||
|
||||
IconButton projectSettingsButton { "Project Settings", getIcons().settings },
|
||||
saveAndOpenInIDEButton { "Save and Open in IDE", Image() },
|
||||
runAppButton { "Run Application", getIcons().play };
|
||||
|
||||
ReferenceCountedObjectPtr<CompileEngineChildProcess> childProcess;
|
||||
|
||||
|
|
|
|||
|
|
@ -275,13 +275,13 @@ private:
|
|||
m.addItem (PopupMenu::Item ("Copy the paths from the module '" + moduleToCopy + "' to all other modules")
|
||||
.setAction ([this, moduleToCopy]
|
||||
{
|
||||
auto& moduleList = project.getEnabledModules();
|
||||
auto& modulesList = project.getEnabledModules();
|
||||
|
||||
for (Project::ExporterIterator exporter (project); exporter.next();)
|
||||
{
|
||||
for (int i = 0; i < moduleList.getNumModules(); ++i)
|
||||
for (int i = 0; i < modulesList.getNumModules(); ++i)
|
||||
{
|
||||
auto modID = moduleList.getModuleID (i);
|
||||
auto modID = modulesList.getModuleID (i);
|
||||
|
||||
if (modID != moduleToCopy)
|
||||
exporter->getPathForModuleValue (modID) = exporter->getPathForModuleValue (moduleToCopy).get();
|
||||
|
|
|
|||
|
|
@ -21,44 +21,50 @@
|
|||
#include "../../LiveBuildEngine/jucer_DownloadCompileEngineThread.h"
|
||||
#include "../../LiveBuildEngine/jucer_CompileEngineSettings.h"
|
||||
|
||||
#include "jucer_HeaderComponent.h"
|
||||
#include "Sidebar/jucer_TabComponents.h"
|
||||
#include "Sidebar/jucer_ProjectTab.h"
|
||||
#include "Sidebar/jucer_LiveBuildTab.h"
|
||||
|
||||
NewFileWizard::Type* createGUIComponentWizard();
|
||||
|
||||
//==============================================================================
|
||||
struct LogoComponent : public Component
|
||||
ProjectContentComponent::LogoComponent::LogoComponent()
|
||||
{
|
||||
LogoComponent()
|
||||
{
|
||||
if (auto svg = parseXML (BinaryData::background_logo_svg))
|
||||
logo = Drawable::createFromSVG (*svg);
|
||||
else
|
||||
jassertfalse;
|
||||
}
|
||||
if (auto svg = parseXML (BinaryData::background_logo_svg))
|
||||
logo = Drawable::createFromSVG (*svg);
|
||||
}
|
||||
|
||||
void paint (Graphics& g) override
|
||||
{
|
||||
g.setColour (findColour (defaultTextColourId));
|
||||
void ProjectContentComponent::LogoComponent::paint (Graphics& g)
|
||||
{
|
||||
g.setColour (findColour (defaultTextColourId));
|
||||
|
||||
auto r = getLocalBounds();
|
||||
auto r = getLocalBounds();
|
||||
|
||||
g.setFont (15.0f);
|
||||
g.drawFittedText (getVersionInfo(), r.removeFromBottom (50), Justification::centredBottom, 3);
|
||||
g.setFont (15.0f);
|
||||
g.drawFittedText (getVersionInfo(), r.removeFromBottom (50), Justification::centredBottom, 3);
|
||||
|
||||
logo->drawWithin (g, r.withTrimmedBottom (r.getHeight() / 4).toFloat(),
|
||||
RectanglePlacement (RectanglePlacement::centred), 1.0f);
|
||||
}
|
||||
logo->drawWithin (g, r.withTrimmedBottom (r.getHeight() / 4).toFloat(),
|
||||
RectanglePlacement (RectanglePlacement::centred), 1.0f);
|
||||
}
|
||||
|
||||
static String getVersionInfo()
|
||||
{
|
||||
return SystemStats::getJUCEVersion()
|
||||
+ newLine
|
||||
+ ProjucerApplication::getApp().getVersionDescription();
|
||||
}
|
||||
String ProjectContentComponent::LogoComponent::getVersionInfo()
|
||||
{
|
||||
return SystemStats::getJUCEVersion()
|
||||
+ newLine
|
||||
+ ProjucerApplication::getApp().getVersionDescription();
|
||||
}
|
||||
|
||||
std::unique_ptr<Drawable> logo;
|
||||
};
|
||||
//==============================================================================
|
||||
ProjectContentComponent::ContentViewport::ContentViewport (Component* content)
|
||||
{
|
||||
addAndMakeVisible (viewport);
|
||||
viewport.setViewedComponent (content, true);
|
||||
}
|
||||
|
||||
void ProjectContentComponent::ContentViewport::resized()
|
||||
{
|
||||
viewport.setBounds (getLocalBounds());
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
ProjectContentComponent::ProjectContentComponent()
|
||||
|
|
@ -66,15 +72,12 @@ ProjectContentComponent::ProjectContentComponent()
|
|||
setOpaque (true);
|
||||
setWantsKeyboardFocus (true);
|
||||
|
||||
logo.reset (new LogoComponent());
|
||||
addAndMakeVisible (logo.get());
|
||||
addAndMakeVisible (logoComponent);
|
||||
addAndMakeVisible (headerComponent);
|
||||
addAndMakeVisible (projectMessagesComponent);
|
||||
|
||||
header.reset (new HeaderComponent());
|
||||
addAndMakeVisible (header.get());
|
||||
|
||||
fileNameLabel.reset (new Label());
|
||||
addAndMakeVisible (fileNameLabel.get());
|
||||
fileNameLabel->setJustificationType (Justification::centred);
|
||||
addAndMakeVisible (fileNameLabel);
|
||||
fileNameLabel.setJustificationType (Justification::centred);
|
||||
|
||||
sidebarSizeConstrainer.setMinimumWidth (200);
|
||||
sidebarSizeConstrainer.setMaximumWidth (500);
|
||||
|
|
@ -84,6 +87,10 @@ ProjectContentComponent::ProjectContentComponent()
|
|||
|
||||
ProjucerApplication::getApp().openDocumentManager.addListener (this);
|
||||
|
||||
isLiveBuildEnabled = getGlobalProperties().getBoolValue (Ids::liveBuildEnabled);
|
||||
getGlobalProperties().addChangeListener (this);
|
||||
liveBuildEnablementChanged (isLiveBuildEnabled);
|
||||
|
||||
Desktop::getInstance().addFocusChangeListener (this);
|
||||
startTimer (1600);
|
||||
}
|
||||
|
|
@ -93,15 +100,11 @@ ProjectContentComponent::~ProjectContentComponent()
|
|||
Desktop::getInstance().removeFocusChangeListener (this);
|
||||
killChildProcess();
|
||||
|
||||
getGlobalProperties().removeChangeListener (this);
|
||||
ProjucerApplication::getApp().openDocumentManager.removeListener (this);
|
||||
|
||||
logo.reset();
|
||||
header.reset();
|
||||
setProject (nullptr);
|
||||
contentView.reset();
|
||||
fileNameLabel.reset();
|
||||
removeChildComponent (&bubbleMessage);
|
||||
jassert (getNumChildComponents() <= 1);
|
||||
}
|
||||
|
||||
void ProjectContentComponent::paint (Graphics& g)
|
||||
|
|
@ -115,11 +118,10 @@ void ProjectContentComponent::resized()
|
|||
|
||||
r.removeFromRight (10);
|
||||
r.removeFromLeft (15);
|
||||
r.removeFromBottom (40);
|
||||
r.removeFromTop (5);
|
||||
|
||||
if (header != nullptr)
|
||||
header->setBounds (r.removeFromTop (40));
|
||||
projectMessagesComponent.setBounds (r.removeFromBottom (40).withWidth (100).reduced (0, 5));
|
||||
headerComponent.setBounds (r.removeFromTop (40));
|
||||
|
||||
r.removeFromTop (10);
|
||||
|
||||
|
|
@ -132,19 +134,15 @@ void ProjectContentComponent::resized()
|
|||
if (resizerBar != nullptr)
|
||||
resizerBar->setBounds (r.withWidth (4));
|
||||
|
||||
if (auto* h = dynamic_cast<HeaderComponent*> (header.get()))
|
||||
h->sidebarTabsWidthChanged (sidebarTabs.getWidth());
|
||||
headerComponent.sidebarTabsWidthChanged (sidebarTabs.getWidth());
|
||||
|
||||
if (contentView != nullptr)
|
||||
{
|
||||
if (fileNameLabel != nullptr && fileNameLabel->isVisible())
|
||||
fileNameLabel->setBounds (r.removeFromTop (15));
|
||||
|
||||
fileNameLabel.setBounds (r.removeFromTop (15));
|
||||
contentView->setBounds (r);
|
||||
}
|
||||
|
||||
if (logo != nullptr)
|
||||
logo->setBounds (r.reduced (r.getWidth() / 6, r.getHeight() / 6));
|
||||
logoComponent.setBounds (r.reduced (r.getWidth() / 6, r.getHeight() / 6));
|
||||
}
|
||||
|
||||
void ProjectContentComponent::lookAndFeelChanged()
|
||||
|
|
@ -165,7 +163,7 @@ void ProjectContentComponent::setProject (Project* newProject)
|
|||
{
|
||||
if (project != newProject)
|
||||
{
|
||||
lastCrashMessage = String();
|
||||
lastCrashMessage = {};
|
||||
killChildProcess();
|
||||
|
||||
if (project != nullptr)
|
||||
|
|
@ -179,6 +177,8 @@ void ProjectContentComponent::setProject (Project* newProject)
|
|||
|
||||
if (project != nullptr)
|
||||
rebuildProjectTabs();
|
||||
|
||||
projectMessagesComponent.setProject (newProject);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -201,20 +201,21 @@ void ProjectContentComponent::createProjectTabs()
|
|||
|
||||
auto tabColour = Colours::transparentBlack;
|
||||
|
||||
auto* pTab = new ProjectTab (project);
|
||||
sidebarTabs.addTab ("Project", tabColour, pTab, true);
|
||||
sidebarTabs.addTab (getProjectTabName(), tabColour, new ProjectTab (project), true);
|
||||
|
||||
CompileEngineChildProcess::Ptr childProc (getChildProcess());
|
||||
|
||||
sidebarTabs.addTab ("Build", tabColour, new LiveBuildTab (childProc, lastCrashMessage), true);
|
||||
|
||||
if (childProc != nullptr)
|
||||
if (isLiveBuildEnabled)
|
||||
{
|
||||
childProc->crashHandler = [this] (const String& m) { this->handleCrash (m); };
|
||||
CompileEngineChildProcess::Ptr childProc (getChildProcess());
|
||||
sidebarTabs.addTab (getBuildTabName(), tabColour, new LiveBuildTab (childProc, lastCrashMessage), true);
|
||||
|
||||
sidebarTabs.getTabbedButtonBar().getTabButton (1)->setExtraComponent (new BuildStatusTabComp (childProc->errorList,
|
||||
childProc->activityList),
|
||||
TabBarButton::afterText);
|
||||
if (childProc != nullptr)
|
||||
{
|
||||
childProc->crashHandler = [this] (const String& m) { this->handleCrash (m); };
|
||||
|
||||
sidebarTabs.getTabbedButtonBar().getTabButton (1)->setExtraComponent (new BuildStatusTabComp (childProc->errorList,
|
||||
childProc->activityList),
|
||||
TabBarButton::afterText);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -255,7 +256,12 @@ void ProjectContentComponent::rebuildProjectTabs()
|
|||
|
||||
sidebarTabs.setBounds (0, 0, lastTreeWidth, getHeight());
|
||||
|
||||
sidebarTabs.setCurrentTabIndex (settings.getValue ("lastViewedTabIndex", "0").getIntValue());
|
||||
auto lastTabIndex = settings.getValue ("lastViewedTabIndex", "0").getIntValue();
|
||||
|
||||
if (lastTabIndex >= sidebarTabs.getNumTabs())
|
||||
lastTabIndex = 0;
|
||||
|
||||
sidebarTabs.setCurrentTabIndex (lastTabIndex);
|
||||
|
||||
auto* projectTab = getProjectTab();
|
||||
for (int i = 2; i >= 0; --i)
|
||||
|
|
@ -272,16 +278,13 @@ void ProjectContentComponent::rebuildProjectTabs()
|
|||
|
||||
updateMissingFileStatuses();
|
||||
|
||||
if (auto* h = dynamic_cast<HeaderComponent*> (header.get()))
|
||||
{
|
||||
h->setVisible (true);
|
||||
h->setCurrentProject (project);
|
||||
}
|
||||
headerComponent.setVisible (true);
|
||||
headerComponent.setCurrentProject (project);
|
||||
}
|
||||
else
|
||||
{
|
||||
sidebarTabs.setVisible (false);
|
||||
header->setVisible (false);
|
||||
headerComponent.setVisible (false);
|
||||
}
|
||||
|
||||
resized();
|
||||
|
|
@ -320,9 +323,19 @@ bool ProjectContentComponent::documentAboutToClose (OpenDocumentManager::Documen
|
|||
return true;
|
||||
}
|
||||
|
||||
void ProjectContentComponent::changeListenerCallback (ChangeBroadcaster*)
|
||||
void ProjectContentComponent::changeListenerCallback (ChangeBroadcaster* broadcaster)
|
||||
{
|
||||
updateMissingFileStatuses();
|
||||
if (broadcaster == project)
|
||||
{
|
||||
updateMissingFileStatuses();
|
||||
}
|
||||
else if (broadcaster == &getGlobalProperties())
|
||||
{
|
||||
auto isEnabled = ProjucerApplication::getApp().isLiveBuildEnabled();
|
||||
|
||||
if (isLiveBuildEnabled != isEnabled)
|
||||
liveBuildEnablementChanged (isEnabled);
|
||||
}
|
||||
}
|
||||
|
||||
void ProjectContentComponent::refreshProjectTreeFileStatuses()
|
||||
|
|
@ -344,8 +357,7 @@ bool ProjectContentComponent::showEditorForFile (const File& f, bool grabFocus)
|
|||
if (getCurrentFile() == f
|
||||
|| showDocument (ProjucerApplication::getApp().openDocumentManager.openFile (project, f), grabFocus))
|
||||
{
|
||||
fileNameLabel->setText (f.getFileName(), dontSendNotification);
|
||||
|
||||
fileNameLabel.setText (f.getFileName(), dontSendNotification);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
@ -394,8 +406,7 @@ void ProjectContentComponent::hideEditor()
|
|||
currentDocument = nullptr;
|
||||
contentView.reset();
|
||||
|
||||
if (fileNameLabel != nullptr)
|
||||
fileNameLabel->setVisible (false);
|
||||
fileNameLabel.setVisible (false);
|
||||
|
||||
ProjucerApplication::getCommandManager().commandStatusChanged();
|
||||
resized();
|
||||
|
|
@ -425,7 +436,7 @@ bool ProjectContentComponent::setEditorComponent (Component* editor,
|
|||
|
||||
contentView.reset (viewport);
|
||||
currentDocument = nullptr;
|
||||
fileNameLabel->setVisible (false);
|
||||
fileNameLabel.setVisible (false);
|
||||
|
||||
addAndMakeVisible (viewport);
|
||||
}
|
||||
|
|
@ -433,8 +444,8 @@ bool ProjectContentComponent::setEditorComponent (Component* editor,
|
|||
{
|
||||
contentView.reset (editor);
|
||||
currentDocument = doc;
|
||||
fileNameLabel->setText (doc->getFile().getFileName(), dontSendNotification);
|
||||
fileNameLabel->setVisible (true);
|
||||
fileNameLabel.setText (doc->getFile().getFileName(), dontSendNotification);
|
||||
fileNameLabel.setVisible (true);
|
||||
|
||||
addAndMakeVisible (editor);
|
||||
}
|
||||
|
|
@ -460,7 +471,8 @@ Component* ProjectContentComponent::getEditorComponentContent() const
|
|||
void ProjectContentComponent::closeDocument()
|
||||
{
|
||||
if (currentDocument != nullptr)
|
||||
ProjucerApplication::getApp().openDocumentManager.closeDocument (currentDocument, true);
|
||||
ProjucerApplication::getApp().openDocumentManager
|
||||
.closeDocument (currentDocument, OpenDocumentManager::SaveIfNeeded::yes);
|
||||
else if (contentView != nullptr)
|
||||
if (! goToPreviousFile())
|
||||
hideEditor();
|
||||
|
|
@ -534,15 +546,10 @@ bool ProjectContentComponent::goToCounterpart()
|
|||
return false;
|
||||
}
|
||||
|
||||
bool ProjectContentComponent::saveProject (bool shouldWait, bool openInIDE)
|
||||
bool ProjectContentComponent::saveProject()
|
||||
{
|
||||
if (project != nullptr)
|
||||
{
|
||||
const ScopedValueSetter<bool> valueSetter (project->shouldWaitAfterSaving, shouldWait, false);
|
||||
project->setOpenInIDEAfterSaving (openInIDE);
|
||||
|
||||
return (project->save (true, true) == FileBasedDocument::savedOk);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
|
@ -550,7 +557,7 @@ bool ProjectContentComponent::saveProject (bool shouldWait, bool openInIDE)
|
|||
void ProjectContentComponent::closeProject()
|
||||
{
|
||||
if (auto* mw = findParentComponentOfClass<MainWindow>())
|
||||
mw->closeCurrentProject (true);
|
||||
mw->closeCurrentProject (OpenDocumentManager::SaveIfNeeded::yes);
|
||||
}
|
||||
|
||||
void ProjectContentComponent::showProjectSettings()
|
||||
|
|
@ -560,8 +567,8 @@ void ProjectContentComponent::showProjectSettings()
|
|||
|
||||
void ProjectContentComponent::showCurrentExporterSettings()
|
||||
{
|
||||
if (auto* h = dynamic_cast<HeaderComponent*> (header.get()))
|
||||
showExporterSettings (h->getSelectedExporterName());
|
||||
if (auto selected = headerComponent.getSelectedExporter())
|
||||
showExporterSettings (selected->getName());
|
||||
}
|
||||
|
||||
void ProjectContentComponent::showExporterSettings (const String& exporterName)
|
||||
|
|
@ -573,7 +580,7 @@ void ProjectContentComponent::showExporterSettings (const String& exporterName)
|
|||
|
||||
if (auto* exportersPanel = getProjectTab()->getExportersTreePanel())
|
||||
{
|
||||
if (auto* exporters = dynamic_cast<TreeItemTypes::ExportersTreeRoot*>(exportersPanel->rootItem.get()))
|
||||
if (auto* exporters = dynamic_cast<TreeItemTypes::ExportersTreeRoot*> (exportersPanel->rootItem.get()))
|
||||
{
|
||||
for (auto i = exporters->getNumSubItems(); i >= 0; --i)
|
||||
{
|
||||
|
|
@ -637,29 +644,8 @@ StringArray ProjectContentComponent::getExportersWhichCanLaunch() const
|
|||
void ProjectContentComponent::openInSelectedIDE (bool saveFirst)
|
||||
{
|
||||
if (project != nullptr)
|
||||
{
|
||||
if (auto* headerComp = dynamic_cast<HeaderComponent*> (header.get()))
|
||||
{
|
||||
auto selectedIDE = headerComp->getSelectedExporterName();
|
||||
|
||||
for (Project::ExporterIterator exporter (*project); exporter.next();)
|
||||
{
|
||||
if (exporter->canLaunchProject() && exporter->getName().contains (selectedIDE))
|
||||
{
|
||||
auto tempProject = project->isTemporaryProject(); // store this before saving as it will always be false after
|
||||
|
||||
if (saveFirst && ! saveProject (exporter->isXcode(), true))
|
||||
return;
|
||||
|
||||
if (tempProject)
|
||||
return;
|
||||
|
||||
exporter->launchProject();
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (auto selectedExporter = headerComponent.getSelectedExporter())
|
||||
project->openProjectInIDE (*selectedExporter, saveFirst);
|
||||
}
|
||||
|
||||
static void newExporterMenuCallback (int result, ProjectContentComponent* comp)
|
||||
|
|
@ -801,7 +787,8 @@ void ProjectContentComponent::getAllCommands (Array <CommandID>& commands)
|
|||
CommandIDs::reinstantiateComp,
|
||||
CommandIDs::showWarnings,
|
||||
CommandIDs::nextError,
|
||||
CommandIDs::prevError });
|
||||
CommandIDs::prevError,
|
||||
CommandIDs::addNewGUIFile });
|
||||
}
|
||||
|
||||
void ProjectContentComponent::getCommandInfo (const CommandID commandID, ApplicationCommandInfo& result)
|
||||
|
|
@ -822,7 +809,7 @@ void ProjectContentComponent::getCommandInfo (const CommandID commandID, Applica
|
|||
result.setInfo ("Save Project",
|
||||
"Saves the current project",
|
||||
CommandCategories::general, 0);
|
||||
result.setActive (project != nullptr && ! project->isCurrentlySaving());
|
||||
result.setActive (project != nullptr && ! project->isSaveAndExportDisabled() && ! project->isCurrentlySaving());
|
||||
result.defaultKeypresses.add ({ 'p', ModifierKeys::commandModifier, 0 });
|
||||
break;
|
||||
|
||||
|
|
@ -901,7 +888,7 @@ void ProjectContentComponent::getCommandInfo (const CommandID commandID, Applica
|
|||
result.setInfo ("Show Build Tab",
|
||||
"Shows the tab containing the build panel",
|
||||
CommandCategories::general, 0);
|
||||
result.setActive (project != nullptr);
|
||||
result.setActive (project != nullptr && isLiveBuildEnabled);
|
||||
result.defaultKeypresses.add ({ 'b', cmdCtrl, 0 });
|
||||
break;
|
||||
|
||||
|
|
@ -941,14 +928,14 @@ void ProjectContentComponent::getCommandInfo (const CommandID commandID, Applica
|
|||
result.setInfo ("Open in IDE...",
|
||||
"Launches the project in an external IDE",
|
||||
CommandCategories::general, 0);
|
||||
result.setActive (ProjectExporter::canProjectBeLaunched (project));
|
||||
result.setActive (ProjectExporter::canProjectBeLaunched (project) && ! project->isSaveAndExportDisabled());
|
||||
break;
|
||||
|
||||
case CommandIDs::saveAndOpenInIDE:
|
||||
result.setInfo ("Save Project and Open in IDE...",
|
||||
"Saves the project and launches it in an external IDE",
|
||||
CommandCategories::general, 0);
|
||||
result.setActive (ProjectExporter::canProjectBeLaunched (project) && ! project->isCurrentlySaving());
|
||||
result.setActive (ProjectExporter::canProjectBeLaunched (project) && ! project->isSaveAndExportDisabled() && ! project->isCurrentlySaving());
|
||||
result.defaultKeypresses.add ({ 'l', ModifierKeys::commandModifier | ModifierKeys::shiftModifier, 0 });
|
||||
break;
|
||||
|
||||
|
|
@ -1055,6 +1042,13 @@ void ProjectContentComponent::getCommandInfo (const CommandID commandID, Applica
|
|||
result.setActive (childProcess != nullptr && ! childProcess->errorList.isEmpty());
|
||||
break;
|
||||
|
||||
case CommandIDs::addNewGUIFile:
|
||||
result.setInfo ("Add new GUI Component...",
|
||||
"Adds a new GUI Component file to the project",
|
||||
CommandCategories::general,
|
||||
(! ProjucerApplication::getApp().isGUIEditorEnabled() ? ApplicationCommandInfo::isDisabled : 0));
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
|
@ -1131,6 +1125,8 @@ bool ProjectContentComponent::perform (const InvocationInfo& info)
|
|||
case CommandIDs::nextError: showNextError(); break;
|
||||
case CommandIDs::prevError: showPreviousError(); break;
|
||||
|
||||
case CommandIDs::addNewGUIFile: addNewGUIFile(); break;
|
||||
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
|
|
@ -1175,7 +1171,7 @@ void ProjectContentComponent::setBuildEnabled (bool isEnabled, bool displayError
|
|||
|
||||
void ProjectContentComponent::cleanAll()
|
||||
{
|
||||
lastCrashMessage = String();
|
||||
lastCrashMessage = {};
|
||||
|
||||
if (childProcess != nullptr)
|
||||
childProcess->cleanAll();
|
||||
|
|
@ -1204,9 +1200,11 @@ bool ProjectContentComponent::isBuildEnabled() const
|
|||
void ProjectContentComponent::refreshTabsIfBuildStatusChanged()
|
||||
{
|
||||
if (project != nullptr
|
||||
&& (sidebarTabs.getNumTabs() < 2
|
||||
|| isBuildEnabled() != isBuildTabEnabled()))
|
||||
&& isLiveBuildEnabled
|
||||
&& (sidebarTabs.getNumTabs() < 2 || isBuildEnabled() != isBuildTabEnabled()))
|
||||
{
|
||||
rebuildProjectTabs();
|
||||
}
|
||||
}
|
||||
|
||||
bool ProjectContentComponent::areWarningsEnabled() const
|
||||
|
|
@ -1261,6 +1259,15 @@ void ProjectContentComponent::reinstantiateLivePreviewWindows()
|
|||
childProcess->reinstantiatePreviews();
|
||||
}
|
||||
|
||||
void ProjectContentComponent::addNewGUIFile()
|
||||
{
|
||||
if (project != nullptr)
|
||||
{
|
||||
std::unique_ptr<NewFileWizard::Type> wizard (createGUIComponentWizard());
|
||||
wizard->createNewFile (*project, project->getMainGroup());
|
||||
}
|
||||
}
|
||||
|
||||
void ProjectContentComponent::launchApp()
|
||||
{
|
||||
if (childProcess != nullptr)
|
||||
|
|
@ -1301,6 +1308,17 @@ void ProjectContentComponent::timerCallback()
|
|||
refreshTabsIfBuildStatusChanged();
|
||||
}
|
||||
|
||||
void ProjectContentComponent::liveBuildEnablementChanged (bool isEnabled)
|
||||
{
|
||||
isLiveBuildEnabled = isEnabled;
|
||||
|
||||
if (! isLiveBuildEnabled)
|
||||
killChildProcess();
|
||||
|
||||
rebuildProjectTabs();
|
||||
headerComponent.liveBuildEnablementChanged (isLiveBuildEnabled);
|
||||
}
|
||||
|
||||
bool ProjectContentComponent::isContinuousRebuildEnabled()
|
||||
{
|
||||
return project != nullptr && project->getCompileEngineSettings().isContinuousRebuildEnabled();
|
||||
|
|
|
|||
|
|
@ -19,11 +19,12 @@
|
|||
#pragma once
|
||||
|
||||
#include "../../CodeEditor/jucer_OpenDocumentManager.h"
|
||||
#include "jucer_HeaderComponent.h"
|
||||
#include "jucer_ProjectMessagesComponent.h"
|
||||
|
||||
class CompileEngineChildProcess;
|
||||
class ProjectTab;
|
||||
class LiveBuildTab;
|
||||
class HeaderComponent;
|
||||
|
||||
//==============================================================================
|
||||
class ProjectContentComponent : public Component,
|
||||
|
|
@ -39,7 +40,7 @@ public:
|
|||
~ProjectContentComponent() override;
|
||||
|
||||
Project* getProject() const noexcept { return project; }
|
||||
virtual void setProject (Project*);
|
||||
void setProject (Project*);
|
||||
|
||||
void saveTreeViewState();
|
||||
void saveOpenDocumentList();
|
||||
|
|
@ -67,14 +68,14 @@ public:
|
|||
bool canGoToCounterpart() const;
|
||||
bool goToCounterpart();
|
||||
|
||||
bool saveProject (bool shouldWait = false, bool openInIDE = false);
|
||||
bool saveProject();
|
||||
void closeProject();
|
||||
void openInSelectedIDE (bool saveFirst);
|
||||
void showNewExporterMenu();
|
||||
|
||||
void showProjectTab() { sidebarTabs.setCurrentTabIndex (0); }
|
||||
void showBuildTab() { sidebarTabs.setCurrentTabIndex (1); }
|
||||
int getCurrentTabIndex() { return sidebarTabs.getCurrentTabIndex(); }
|
||||
void showProjectTab() { sidebarTabs.setCurrentTabIndex (0); }
|
||||
void showBuildTab() { sidebarTabs.setCurrentTabIndex (1); }
|
||||
int getCurrentTabIndex() { return sidebarTabs.getCurrentTabIndex(); }
|
||||
|
||||
void showFilesPanel() { showProjectPanel (0); }
|
||||
void showModulesPanel() { showProjectPanel (1); }
|
||||
|
|
@ -99,6 +100,7 @@ public:
|
|||
void showNextError();
|
||||
void showPreviousError();
|
||||
void reinstantiateLivePreviewWindows();
|
||||
void addNewGUIFile();
|
||||
|
||||
void showBubbleMessage (Rectangle<int>, const String&);
|
||||
|
||||
|
|
@ -129,28 +131,31 @@ public:
|
|||
void childBoundsChanged (Component*) override;
|
||||
void lookAndFeelChanged() override;
|
||||
|
||||
String lastCrashMessage;
|
||||
ProjectMessagesComponent& getProjectMessagesComponent() { return projectMessagesComponent; }
|
||||
|
||||
static String getProjectTabName() { return "Project"; }
|
||||
static String getBuildTabName() { return "Build"; }
|
||||
|
||||
private:
|
||||
friend HeaderComponent;
|
||||
|
||||
//==============================================================================
|
||||
Project* project = nullptr;
|
||||
OpenDocumentManager::Document* currentDocument = nullptr;
|
||||
RecentDocumentList recentDocumentList;
|
||||
std::unique_ptr<Component> logo, translationTool, contentView, header;
|
||||
struct LogoComponent : public Component
|
||||
{
|
||||
LogoComponent();
|
||||
void paint (Graphics& g) override;
|
||||
static String getVersionInfo();
|
||||
|
||||
TabbedComponent sidebarTabs { TabbedButtonBar::TabsAtTop };
|
||||
std::unique_ptr<ResizableEdgeComponent> resizerBar;
|
||||
ComponentBoundsConstrainer sidebarSizeConstrainer;
|
||||
std::unique_ptr<Drawable> logo;
|
||||
};
|
||||
|
||||
BubbleMessageComponent bubbleMessage;
|
||||
ReferenceCountedObjectPtr<CompileEngineChildProcess> childProcess;
|
||||
bool isForeground = false;
|
||||
struct ContentViewport : public Component
|
||||
{
|
||||
ContentViewport (Component* content);
|
||||
void resized() override;
|
||||
|
||||
std::unique_ptr<Label> fileNameLabel;
|
||||
Viewport viewport;
|
||||
|
||||
int lastViewedTab = 0;
|
||||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (ContentViewport)
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
bool documentAboutToClose (OpenDocumentManager::Document*) override;
|
||||
|
|
@ -160,6 +165,8 @@ private:
|
|||
void globalFocusChanged (Component*) override;
|
||||
void timerCallback() override;
|
||||
|
||||
void liveBuildEnablementChanged (bool isEnabled);
|
||||
|
||||
bool isContinuousRebuildEnabled();
|
||||
void setContinuousRebuildEnabled (bool b);
|
||||
|
||||
|
|
@ -178,23 +185,26 @@ private:
|
|||
bool canSelectedProjectBeLaunch();
|
||||
|
||||
//==============================================================================
|
||||
struct ContentViewport : public Component
|
||||
{
|
||||
ContentViewport (Component* content)
|
||||
{
|
||||
addAndMakeVisible (viewport);
|
||||
viewport.setViewedComponent (content, true);
|
||||
}
|
||||
Project* project = nullptr;
|
||||
OpenDocumentManager::Document* currentDocument = nullptr;
|
||||
RecentDocumentList recentDocumentList;
|
||||
|
||||
void resized() override
|
||||
{
|
||||
viewport.setBounds (getLocalBounds());
|
||||
}
|
||||
LogoComponent logoComponent;
|
||||
HeaderComponent headerComponent { this };
|
||||
ProjectMessagesComponent projectMessagesComponent;
|
||||
Label fileNameLabel;
|
||||
TabbedComponent sidebarTabs { TabbedButtonBar::TabsAtTop };
|
||||
std::unique_ptr<ResizableEdgeComponent> resizerBar;
|
||||
ComponentBoundsConstrainer sidebarSizeConstrainer;
|
||||
std::unique_ptr<Component> translationTool, contentView;
|
||||
BubbleMessageComponent bubbleMessage;
|
||||
|
||||
Viewport viewport;
|
||||
ReferenceCountedObjectPtr<CompileEngineChildProcess> childProcess;
|
||||
String lastCrashMessage;
|
||||
|
||||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (ContentViewport)
|
||||
};
|
||||
bool isForeground = false, isLiveBuildEnabled = false;
|
||||
int lastViewedTab = 0;
|
||||
|
||||
//==============================================================================
|
||||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (ProjectContentComponent)
|
||||
};
|
||||
|
|
|
|||
|
|
@ -0,0 +1,544 @@
|
|||
/*
|
||||
==============================================================================
|
||||
|
||||
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
|
||||
|
||||
#include "../../Application/jucer_CommonHeaders.h"
|
||||
#include "../../Application/jucer_Application.h"
|
||||
|
||||
//==============================================================================
|
||||
class MessagesPopupWindow : public Component,
|
||||
private ComponentMovementWatcher
|
||||
{
|
||||
public:
|
||||
MessagesPopupWindow (Component& target, Component& parent, Project& project)
|
||||
: ComponentMovementWatcher (&parent),
|
||||
targetComponent (target),
|
||||
parentComponent (parent),
|
||||
messagesListComponent (*this, project)
|
||||
{
|
||||
parentComponent.addAndMakeVisible (this);
|
||||
setAlwaysOnTop (true);
|
||||
|
||||
addAndMakeVisible (viewport);
|
||||
viewport.setScrollBarsShown (true, false);
|
||||
viewport.setViewedComponent (&messagesListComponent, false);
|
||||
|
||||
setOpaque (true);
|
||||
}
|
||||
|
||||
void paint (Graphics& g) override
|
||||
{
|
||||
g.fillAll (findColour (secondaryBackgroundColourId));
|
||||
}
|
||||
|
||||
void resized() override
|
||||
{
|
||||
viewport.setBounds (getLocalBounds());
|
||||
}
|
||||
|
||||
bool isListShowing() const
|
||||
{
|
||||
return messagesListComponent.getRequiredHeight() > 0;
|
||||
}
|
||||
|
||||
void updateBounds (bool animate)
|
||||
{
|
||||
auto targetBounds = parentComponent.getLocalArea (&targetComponent, targetComponent.getLocalBounds());
|
||||
|
||||
auto height = jmin (messagesListComponent.getRequiredHeight(), maxHeight);
|
||||
auto yPos = jmax (indent, targetBounds.getY() - height);
|
||||
|
||||
Rectangle<int> bounds (targetBounds.getX(), yPos,
|
||||
jmin (width, parentComponent.getWidth() - targetBounds.getX() - indent), targetBounds.getY() - yPos);
|
||||
|
||||
auto& animator = Desktop::getInstance().getAnimator();
|
||||
|
||||
if (animate)
|
||||
{
|
||||
setBounds (bounds.withY (targetBounds.getY()));
|
||||
animator.animateComponent (this, bounds, 1.0f, 150, false, 1.0, 1.0);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (animator.isAnimating (this))
|
||||
animator.cancelAnimation (this, false);
|
||||
|
||||
setBounds (bounds);
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
//==============================================================================
|
||||
class MessagesListComponent : public Component,
|
||||
private ValueTree::Listener,
|
||||
private AsyncUpdater
|
||||
{
|
||||
public:
|
||||
MessagesListComponent (MessagesPopupWindow& o, Project& currentProject)
|
||||
: owner (o),
|
||||
project (currentProject)
|
||||
{
|
||||
messagesTree = project.getProjectMessages();
|
||||
messagesTree.addListener (this);
|
||||
|
||||
setOpaque (true);
|
||||
|
||||
messagesChanged();
|
||||
}
|
||||
|
||||
void resized() override
|
||||
{
|
||||
auto bounds = getLocalBounds();
|
||||
auto numMessages = messages.size();
|
||||
|
||||
for (size_t i = 0; i < numMessages; ++i)
|
||||
{
|
||||
messages[i]->setBounds (bounds.removeFromTop (messageHeight));
|
||||
|
||||
if (numMessages > 1 && i != (numMessages - 1))
|
||||
bounds.removeFromTop (messageSpacing);
|
||||
}
|
||||
}
|
||||
|
||||
void paint (Graphics& g) override
|
||||
{
|
||||
g.fillAll (findColour (backgroundColourId).contrasting (0.2f));
|
||||
}
|
||||
|
||||
int getRequiredHeight() const
|
||||
{
|
||||
auto numMessages = (int) messages.size();
|
||||
|
||||
if (numMessages > 0)
|
||||
return (numMessages * messageHeight) + ((numMessages - 1) * messageSpacing);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void updateSize (int parentWidth)
|
||||
{
|
||||
setSize (parentWidth, getRequiredHeight());
|
||||
}
|
||||
|
||||
private:
|
||||
static constexpr int messageHeight = 65;
|
||||
static constexpr int messageSpacing = 2;
|
||||
|
||||
//==============================================================================
|
||||
struct MessageComponent : public Component
|
||||
{
|
||||
MessageComponent (MessagesListComponent& listComponent,
|
||||
const Identifier& messageToDisplay,
|
||||
std::vector<ProjectMessages::MessageAction> messageActions)
|
||||
: message (messageToDisplay)
|
||||
{
|
||||
for (auto& action : messageActions)
|
||||
{
|
||||
auto button = std::make_unique<TextButton> (action.first);
|
||||
addAndMakeVisible (*button);
|
||||
button->onClick = action.second;
|
||||
|
||||
buttons.push_back (std::move (button));
|
||||
}
|
||||
|
||||
icon = (ProjectMessages::getTypeForMessage (message) == ProjectMessages::Ids::warning ? getIcons().warning : getIcons().info);
|
||||
|
||||
messageTitleLabel.setText (ProjectMessages::getTitleForMessage (message), dontSendNotification);
|
||||
messageTitleLabel.setFont (Font (11.0f).boldened());
|
||||
addAndMakeVisible (messageTitleLabel);
|
||||
|
||||
messageDescriptionLabel.setText (ProjectMessages::getDescriptionForMessage (message), dontSendNotification);
|
||||
messageDescriptionLabel.setFont (Font (11.0f));
|
||||
messageDescriptionLabel.setJustificationType (Justification::topLeft);
|
||||
addAndMakeVisible (messageDescriptionLabel);
|
||||
|
||||
dismissButton.setShape (getLookAndFeel().getCrossShape (1.0f), false, true, false);
|
||||
addAndMakeVisible (dismissButton);
|
||||
|
||||
dismissButton.onClick = [this, &listComponent]
|
||||
{
|
||||
listComponent.messagesTree.getChildWithName (ProjectMessages::getTypeForMessage (message))
|
||||
.getChildWithName (message)
|
||||
.setProperty (ProjectMessages::Ids::isVisible, false, nullptr);
|
||||
};
|
||||
}
|
||||
|
||||
void paint (Graphics& g) override
|
||||
{
|
||||
g.fillAll (findColour (secondaryBackgroundColourId).contrasting (0.1f));
|
||||
|
||||
auto bounds = getLocalBounds().reduced (5);
|
||||
|
||||
g.setColour (findColour (defaultIconColourId));
|
||||
g.fillPath (icon, icon.getTransformToScaleToFit (bounds.removeFromTop (messageTitleHeight)
|
||||
.removeFromLeft (messageTitleHeight).toFloat(), true));
|
||||
}
|
||||
|
||||
void resized() override
|
||||
{
|
||||
auto bounds = getLocalBounds().reduced (5);
|
||||
|
||||
auto topSlice = bounds.removeFromTop (messageTitleHeight);
|
||||
|
||||
topSlice.removeFromLeft (messageTitleHeight + 5);
|
||||
topSlice.removeFromRight (5);
|
||||
|
||||
dismissButton.setBounds (topSlice.removeFromRight (messageTitleHeight));
|
||||
messageTitleLabel.setBounds (topSlice);
|
||||
bounds.removeFromTop (5);
|
||||
|
||||
auto numButtons = (int) buttons.size();
|
||||
|
||||
if (numButtons > 0)
|
||||
{
|
||||
auto buttonBounds = bounds.removeFromBottom (buttonHeight);
|
||||
|
||||
auto buttonWidth = roundToInt (buttonBounds.getWidth() / 3.5f);
|
||||
auto requiredWidth = (numButtons * buttonWidth) + ((numButtons - 1) * buttonSpacing);
|
||||
buttonBounds.reduce ((buttonBounds.getWidth() - requiredWidth) / 2, 0);
|
||||
|
||||
for (auto& b : buttons)
|
||||
{
|
||||
b->setBounds (buttonBounds.removeFromLeft (buttonWidth));
|
||||
buttonBounds.removeFromLeft (buttonSpacing);
|
||||
}
|
||||
|
||||
bounds.removeFromBottom (5);
|
||||
}
|
||||
|
||||
messageDescriptionLabel.setBounds (bounds);
|
||||
}
|
||||
|
||||
static constexpr int messageTitleHeight = 11;
|
||||
static constexpr int buttonHeight = messageHeight / 4;
|
||||
static constexpr int buttonSpacing = 5;
|
||||
|
||||
Identifier message;
|
||||
|
||||
Path icon;
|
||||
Label messageTitleLabel, messageDescriptionLabel;
|
||||
std::vector<std::unique_ptr<TextButton>> buttons;
|
||||
ShapeButton dismissButton { {},
|
||||
findColour (treeIconColourId),
|
||||
findColour (treeIconColourId).overlaidWith (findColour (defaultHighlightedTextColourId).withAlpha (0.2f)),
|
||||
findColour (treeIconColourId).overlaidWith (findColour (defaultHighlightedTextColourId).withAlpha (0.4f)) };
|
||||
|
||||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (MessageComponent)
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
void valueTreePropertyChanged (ValueTree&, const Identifier&) override { triggerAsyncUpdate(); }
|
||||
void valueTreeChildAdded (ValueTree&, ValueTree&) override { triggerAsyncUpdate(); }
|
||||
void valueTreeChildRemoved (ValueTree&, ValueTree&, int) override { triggerAsyncUpdate(); }
|
||||
void valueTreeChildOrderChanged (ValueTree&, int, int) override { triggerAsyncUpdate(); }
|
||||
void valueTreeParentChanged (ValueTree&) override { triggerAsyncUpdate(); }
|
||||
void valueTreeRedirected (ValueTree&) override { triggerAsyncUpdate(); }
|
||||
|
||||
void handleAsyncUpdate() override
|
||||
{
|
||||
messagesChanged();
|
||||
}
|
||||
|
||||
void messagesChanged()
|
||||
{
|
||||
auto listWasShowing = (getHeight() > 0);
|
||||
|
||||
auto warningsTree = messagesTree.getChildWithName (ProjectMessages::Ids::warning);
|
||||
auto notificationsTree = messagesTree.getChildWithName (ProjectMessages::Ids::notification);
|
||||
|
||||
auto removePredicate = [warningsTree, notificationsTree] (std::unique_ptr<MessageComponent>& messageComponent)
|
||||
{
|
||||
for (int i = 0; i < warningsTree.getNumChildren(); ++i)
|
||||
{
|
||||
auto child = warningsTree.getChild (i);
|
||||
|
||||
if (child.getType() == messageComponent->message
|
||||
&& child.getProperty (ProjectMessages::Ids::isVisible))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < notificationsTree.getNumChildren(); ++i)
|
||||
{
|
||||
auto child = notificationsTree.getChild (i);
|
||||
|
||||
if (child.getType() == messageComponent->message
|
||||
&& child.getProperty (ProjectMessages::Ids::isVisible))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
};
|
||||
|
||||
messages.erase (std::remove_if (std::begin (messages), std::end (messages), removePredicate),
|
||||
std::end (messages));
|
||||
|
||||
for (int i = 0; i < warningsTree.getNumChildren(); ++i)
|
||||
{
|
||||
auto child = warningsTree.getChild (i);
|
||||
|
||||
if (! child.getProperty (ProjectMessages::Ids::isVisible))
|
||||
continue;
|
||||
|
||||
if (std::find_if (std::begin (messages), std::end (messages),
|
||||
[child] (const std::unique_ptr<MessageComponent>& messageComponent) { return messageComponent->message == child.getType(); })
|
||||
== std::end (messages))
|
||||
{
|
||||
messages.push_back (std::make_unique<MessageComponent> (*this, child.getType(), project.getMessageActions (child.getType())));
|
||||
addAndMakeVisible (*messages.back());
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < notificationsTree.getNumChildren(); ++i)
|
||||
{
|
||||
auto child = notificationsTree.getChild (i);
|
||||
|
||||
if (! child.getProperty (ProjectMessages::Ids::isVisible))
|
||||
continue;
|
||||
|
||||
if (std::find_if (std::begin (messages), std::end (messages),
|
||||
[child] (const std::unique_ptr<MessageComponent>& messageComponent) { return messageComponent->message == child.getType(); })
|
||||
== std::end (messages))
|
||||
{
|
||||
messages.push_back (std::make_unique<MessageComponent> (*this, child.getType(), project.getMessageActions (child.getType())));
|
||||
addAndMakeVisible (*messages.back());
|
||||
}
|
||||
}
|
||||
|
||||
auto isNowShowing = (messages.size() > 0);
|
||||
|
||||
owner.updateBounds (isNowShowing != listWasShowing);
|
||||
updateSize (owner.getWidth());
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
MessagesPopupWindow& owner;
|
||||
Project& project;
|
||||
|
||||
ValueTree messagesTree;
|
||||
std::vector<std::unique_ptr<MessageComponent>> messages;
|
||||
|
||||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (MessagesListComponent)
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
void componentMovedOrResized (bool, bool) override
|
||||
{
|
||||
if (isListShowing())
|
||||
updateBounds (false);
|
||||
}
|
||||
|
||||
using ComponentMovementWatcher::componentMovedOrResized;
|
||||
|
||||
void componentPeerChanged() override
|
||||
{
|
||||
if (isListShowing())
|
||||
updateBounds (false);
|
||||
}
|
||||
|
||||
void componentVisibilityChanged() override
|
||||
{
|
||||
if (isListShowing())
|
||||
updateBounds (false);
|
||||
}
|
||||
|
||||
using ComponentMovementWatcher::componentVisibilityChanged;
|
||||
|
||||
//==============================================================================
|
||||
static constexpr int maxHeight = 500, width = 350, indent = 20;
|
||||
|
||||
Component& targetComponent;
|
||||
Component& parentComponent;
|
||||
|
||||
Viewport viewport;
|
||||
MessagesListComponent messagesListComponent;
|
||||
|
||||
//==============================================================================
|
||||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (MessagesPopupWindow)
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
class ProjectMessagesComponent : public Component
|
||||
{
|
||||
public:
|
||||
ProjectMessagesComponent()
|
||||
{
|
||||
addAndMakeVisible (warningsComponent);
|
||||
addAndMakeVisible (notificationsComponent);
|
||||
|
||||
warningsComponent.addMouseListener (this, true);
|
||||
notificationsComponent.addMouseListener (this, true);
|
||||
|
||||
setOpaque (true);
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
void resized() override
|
||||
{
|
||||
auto b = getLocalBounds();
|
||||
|
||||
warningsComponent.setBounds (b.removeFromLeft (b.getWidth() / 2).reduced (5));
|
||||
notificationsComponent.setBounds (b.reduced (5));
|
||||
}
|
||||
|
||||
void paint (Graphics& g) override
|
||||
{
|
||||
auto backgroundColour = findColour (backgroundColourId);
|
||||
|
||||
if (isMouseDown || isMouseOver)
|
||||
backgroundColour = backgroundColour.overlaidWith (findColour (defaultHighlightColourId)
|
||||
.withAlpha (isMouseDown ? 1.0f : 0.8f));
|
||||
|
||||
g.fillAll (backgroundColour);
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
void mouseEnter (const MouseEvent&) override
|
||||
{
|
||||
isMouseOver = true;
|
||||
repaint();
|
||||
}
|
||||
|
||||
void mouseExit (const MouseEvent&) override
|
||||
{
|
||||
isMouseOver = false;
|
||||
repaint();
|
||||
}
|
||||
|
||||
void mouseDown (const MouseEvent&) override
|
||||
{
|
||||
isMouseDown = true;
|
||||
repaint();
|
||||
}
|
||||
|
||||
void mouseUp (const MouseEvent&) override
|
||||
{
|
||||
isMouseDown = false;
|
||||
repaint();
|
||||
|
||||
if (messagesWindow != nullptr)
|
||||
showOrHideAllMessages (! messagesWindow->isListShowing());
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
void setProject (Project* newProject)
|
||||
{
|
||||
if (currentProject != newProject)
|
||||
{
|
||||
currentProject = newProject;
|
||||
|
||||
if (currentProject != nullptr)
|
||||
{
|
||||
auto* projectWindow = ProjucerApplication::getApp().mainWindowList.getMainWindowForFile (currentProject->getFile());
|
||||
jassert (projectWindow != nullptr);
|
||||
messagesWindow = std::make_unique<MessagesPopupWindow> (*this, *projectWindow, *currentProject);
|
||||
|
||||
auto projectMessagesTree = currentProject->getProjectMessages();
|
||||
|
||||
warningsComponent.setTree (projectMessagesTree.getChildWithName (ProjectMessages::Ids::warning));
|
||||
notificationsComponent.setTree (projectMessagesTree.getChildWithName (ProjectMessages::Ids::notification));
|
||||
}
|
||||
else
|
||||
{
|
||||
warningsComponent.setTree ({});
|
||||
notificationsComponent.setTree ({});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
//==============================================================================
|
||||
struct MessageCountComponent : public Component,
|
||||
public ValueTree::Listener
|
||||
{
|
||||
MessageCountComponent (ProjectMessagesComponent& o, Path pathToUse)
|
||||
: owner (o),
|
||||
path (pathToUse)
|
||||
{
|
||||
setInterceptsMouseClicks (false, false);
|
||||
}
|
||||
|
||||
void paint (Graphics& g) override
|
||||
{
|
||||
auto b = getLocalBounds().toFloat();
|
||||
|
||||
g.setColour (findColour ((owner.isMouseDown || owner.isMouseOver) ? defaultHighlightedTextColourId : treeIconColourId));
|
||||
g.fillPath (path, path.getTransformToScaleToFit (b.removeFromLeft (b.getWidth() / 2.0f), true));
|
||||
|
||||
b.removeFromLeft (5);
|
||||
g.drawFittedText (String (numMessages), b.getSmallestIntegerContainer(), Justification::centredLeft, 1);
|
||||
}
|
||||
|
||||
void setTree (ValueTree tree)
|
||||
{
|
||||
messagesTree = tree;
|
||||
|
||||
if (messagesTree.isValid())
|
||||
messagesTree.addListener (this);
|
||||
|
||||
updateNumMessages();
|
||||
}
|
||||
|
||||
void valueTreeChildAdded (ValueTree&, ValueTree&) override { updateNumMessages(); }
|
||||
void valueTreeChildRemoved (ValueTree&, ValueTree&, int) override { updateNumMessages(); }
|
||||
|
||||
void updateNumMessages()
|
||||
{
|
||||
numMessages = messagesTree.getNumChildren();
|
||||
repaint();
|
||||
}
|
||||
|
||||
ProjectMessagesComponent& owner;
|
||||
ValueTree messagesTree;
|
||||
|
||||
Path path;
|
||||
int numMessages = 0;
|
||||
};
|
||||
|
||||
void showOrHideAllMessages (bool shouldBeVisible)
|
||||
{
|
||||
if (currentProject != nullptr)
|
||||
{
|
||||
auto messagesTree = currentProject->getProjectMessages();
|
||||
|
||||
auto setVisible = [shouldBeVisible] (ValueTree subTree)
|
||||
{
|
||||
for (int i = 0; i < subTree.getNumChildren(); ++i)
|
||||
subTree.getChild (i).setProperty (ProjectMessages::Ids::isVisible, shouldBeVisible, nullptr);
|
||||
};
|
||||
|
||||
setVisible (messagesTree.getChildWithName (ProjectMessages::Ids::warning));
|
||||
setVisible (messagesTree.getChildWithName (ProjectMessages::Ids::notification));
|
||||
}
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
Project* currentProject = nullptr;
|
||||
bool isMouseOver = false, isMouseDown = false;
|
||||
|
||||
MessageCountComponent warningsComponent { *this, getIcons().warning },
|
||||
notificationsComponent { *this, getIcons().info };
|
||||
|
||||
std::unique_ptr<MessagesPopupWindow> messagesWindow;
|
||||
|
||||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (ProjectMessagesComponent)
|
||||
};
|
||||
123
extras/Projucer/Source/Project/UI/jucer_UserAvatarComponent.h
Normal file
123
extras/Projucer/Source/Project/UI/jucer_UserAvatarComponent.h
Normal file
|
|
@ -0,0 +1,123 @@
|
|||
/*
|
||||
==============================================================================
|
||||
|
||||
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
|
||||
|
||||
#include "../../Application/jucer_Application.h"
|
||||
|
||||
class UserAvatarComponent : public Component,
|
||||
public SettableTooltipClient,
|
||||
public ChangeBroadcaster,
|
||||
private LicenseController::LicenseStateListener
|
||||
{
|
||||
public:
|
||||
UserAvatarComponent (bool tooltip, bool signIn)
|
||||
: displayTooltip (tooltip),
|
||||
signInOnClick (signIn)
|
||||
{
|
||||
ProjucerApplication::getApp().getLicenseController().addListener (this);
|
||||
licenseStateChanged();
|
||||
}
|
||||
|
||||
~UserAvatarComponent() override
|
||||
{
|
||||
ProjucerApplication::getApp().getLicenseController().removeListener (this);
|
||||
}
|
||||
|
||||
void paint (Graphics& g) override
|
||||
{
|
||||
auto bounds = getLocalBounds();
|
||||
|
||||
if (! isGPL)
|
||||
{
|
||||
bounds = bounds.removeFromRight (bounds.getHeight());
|
||||
|
||||
Path ellipse;
|
||||
ellipse.addEllipse (bounds.toFloat());
|
||||
|
||||
g.reduceClipRegion (ellipse);
|
||||
}
|
||||
|
||||
g.drawImage (userAvatarImage, bounds.toFloat(), RectanglePlacement::fillDestination);
|
||||
}
|
||||
|
||||
void mouseUp (const MouseEvent&) override
|
||||
{
|
||||
if (signInOnClick)
|
||||
{
|
||||
PopupMenu menu;
|
||||
menu.addCommandItem (ProjucerApplication::getApp().commandManager.get(), CommandIDs::loginLogout);
|
||||
|
||||
menu.showMenuAsync (PopupMenu::Options().withTargetComponent (this));
|
||||
}
|
||||
}
|
||||
|
||||
bool isDisplaingGPLLogo() const noexcept { return isGPL; }
|
||||
|
||||
private:
|
||||
Image createDefaultAvatarImage()
|
||||
{
|
||||
Image image (Image::ARGB, 250, 250, true);
|
||||
Graphics g (image);
|
||||
|
||||
g.setColour (findColour (defaultButtonBackgroundColourId));
|
||||
g.fillAll();
|
||||
|
||||
g.setColour (findColour (defaultIconColourId));
|
||||
|
||||
auto path = getIcons().user;
|
||||
g.fillPath (path, RectanglePlacement (RectanglePlacement::centred)
|
||||
.getTransformToFit (path.getBounds(), image.getBounds().reduced (image.getHeight() / 5).toFloat()));
|
||||
|
||||
return image;
|
||||
}
|
||||
|
||||
void licenseStateChanged() override
|
||||
{
|
||||
auto state = ProjucerApplication::getApp().getLicenseController().getCurrentState();
|
||||
|
||||
isGPL = ProjucerApplication::getApp().getLicenseController().getCurrentState().isGPL();
|
||||
|
||||
if (displayTooltip)
|
||||
{
|
||||
auto formattedUserString = [state]() -> String
|
||||
{
|
||||
if (state.isValid())
|
||||
return (state.isGPL() ? "" : (state.username + " - ")) + state.getLicenseTypeString();
|
||||
|
||||
return "Not logged in";
|
||||
}();
|
||||
|
||||
setTooltip (formattedUserString);
|
||||
}
|
||||
|
||||
userAvatarImage = state.isValid() ? state.avatar : defaultAvatarImage;
|
||||
repaint();
|
||||
sendChangeMessage();
|
||||
}
|
||||
|
||||
void lookAndFeelChanged() override
|
||||
{
|
||||
defaultAvatarImage = createDefaultAvatarImage();
|
||||
licenseStateChanged();
|
||||
repaint();
|
||||
}
|
||||
|
||||
Image userAvatarImage, defaultAvatarImage { createDefaultAvatarImage() };
|
||||
bool isGPL = false, displayTooltip = false, signInOnClick = false;
|
||||
};
|
||||
|
|
@ -22,17 +22,63 @@
|
|||
#include "../Application/jucer_Application.h"
|
||||
#include "../LiveBuildEngine/jucer_CompileEngineSettings.h"
|
||||
|
||||
namespace
|
||||
//==============================================================================
|
||||
Project::ProjectFileModificationPoller::ProjectFileModificationPoller (Project& p)
|
||||
: project (p)
|
||||
{
|
||||
String makeValid4CC (const String& seed)
|
||||
{
|
||||
auto s = build_tools::makeValidIdentifier (seed, false, true, false) + "xxxx";
|
||||
startTimer (250);
|
||||
}
|
||||
|
||||
return s.substring (0, 1).toUpperCase()
|
||||
+ s.substring (1, 4).toLowerCase();
|
||||
void Project::ProjectFileModificationPoller::reset()
|
||||
{
|
||||
project.removeProjectMessage (ProjectMessages::Ids::jucerFileModified);
|
||||
showingWarning = false;
|
||||
|
||||
startTimer (250);
|
||||
}
|
||||
|
||||
void Project::ProjectFileModificationPoller::timerCallback()
|
||||
{
|
||||
if (project.hasProjectBeenModified())
|
||||
{
|
||||
if (! showingWarning)
|
||||
{
|
||||
project.addProjectMessage (ProjectMessages::Ids::jucerFileModified,
|
||||
{ { "Keep", [this] { keepProject(); } },
|
||||
{ "Re-load from disk", [this] { reloadProjectFromDisk(); } },
|
||||
{ "Ignore", [this] { reset(); } } });
|
||||
|
||||
stopTimer();
|
||||
showingWarning = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Project::ProjectFileModificationPoller::reloadProjectFromDisk()
|
||||
{
|
||||
auto oldTemporaryDirectory = project.getTemporaryDirectory();
|
||||
auto projectFile = project.getFile();
|
||||
|
||||
MessageManager::callAsync ([oldTemporaryDirectory, projectFile]
|
||||
{
|
||||
if (auto* mw = ProjucerApplication::getApp().mainWindowList.getMainWindowForFile (projectFile))
|
||||
{
|
||||
mw->closeCurrentProject (OpenDocumentManager::SaveIfNeeded::no);
|
||||
mw->openFile (projectFile);
|
||||
|
||||
if (oldTemporaryDirectory != File())
|
||||
if (auto* newProject = mw->getProject())
|
||||
newProject->setTemporaryDirectory (oldTemporaryDirectory);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void Project::ProjectFileModificationPoller::keepProject()
|
||||
{
|
||||
project.saveProject();
|
||||
reset();
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
Project::Project (const File& f)
|
||||
: FileBasedDocument (projectFileExtension,
|
||||
|
|
@ -48,16 +94,37 @@ Project::Project (const File& f)
|
|||
initialiseMainGroup();
|
||||
initialiseAudioPluginValues();
|
||||
|
||||
exporterPathsModuleList.reset (new AvailableModuleList());
|
||||
|
||||
setChangedFlag (false);
|
||||
modificationTime = getFile().getLastModificationTime();
|
||||
|
||||
auto& app = ProjucerApplication::getApp();
|
||||
|
||||
if (! app.isRunningCommandLine)
|
||||
app.getLicenseController().addListener (this);
|
||||
|
||||
app.getJUCEPathModulesList().addListener (this);
|
||||
app.getUserPathsModulesList().addListener (this);
|
||||
|
||||
updateJUCEPathWarning();
|
||||
getGlobalProperties().addChangeListener (this);
|
||||
|
||||
LatestVersionCheckerAndUpdater::getInstance()->checkForNewVersion (true);
|
||||
}
|
||||
|
||||
Project::~Project()
|
||||
{
|
||||
projectRoot.removeListener (this);
|
||||
ProjucerApplication::getApp().openDocumentManager.closeAllDocumentsUsingProject (*this, false);
|
||||
getGlobalProperties().removeChangeListener (this);
|
||||
|
||||
auto& app = ProjucerApplication::getApp();
|
||||
|
||||
app.openDocumentManager.closeAllDocumentsUsingProject (*this, OpenDocumentManager::SaveIfNeeded::no);
|
||||
|
||||
if (! app.isRunningCommandLine)
|
||||
app.getLicenseController().removeListener (this);
|
||||
|
||||
app.getJUCEPathModulesList().removeListener (this);
|
||||
app.getUserPathsModulesList().removeListener (this);
|
||||
}
|
||||
|
||||
const char* Project::projectFileExtension = ".jucer";
|
||||
|
|
@ -93,6 +160,8 @@ void Project::updateCompanyNameDependencies()
|
|||
bundleIdentifierValue.setDefault (getDefaultBundleIdentifierString());
|
||||
pluginAAXIdentifierValue.setDefault (getDefaultAAXIdentifierString());
|
||||
pluginManufacturerValue.setDefault (getDefaultPluginManufacturerString());
|
||||
|
||||
updateLicenseWarning();
|
||||
}
|
||||
|
||||
void Project::updateProjectSettings()
|
||||
|
|
@ -105,7 +174,7 @@ bool Project::setCppVersionFromOldExporterSettings()
|
|||
{
|
||||
auto highestLanguageStandard = -1;
|
||||
|
||||
for (Project::ExporterIterator exporter (*this); exporter.next();)
|
||||
for (ExporterIterator exporter (*this); exporter.next();)
|
||||
{
|
||||
if (exporter->isXcode()) // cpp version was per-build configuration for xcode exporters
|
||||
{
|
||||
|
|
@ -130,7 +199,7 @@ bool Project::setCppVersionFromOldExporterSettings()
|
|||
{
|
||||
if (cppLanguageStandard.toString().containsIgnoreCase ("latest"))
|
||||
{
|
||||
cppStandardValue = "latest";
|
||||
cppStandardValue = Project::getCppStandardVars().getLast();
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
@ -153,7 +222,7 @@ bool Project::setCppVersionFromOldExporterSettings()
|
|||
|
||||
void Project::updateDeprecatedProjectSettings()
|
||||
{
|
||||
for (Project::ExporterIterator exporter (*this); exporter.next();)
|
||||
for (ExporterIterator exporter (*this); exporter.next();)
|
||||
exporter->updateDeprecatedSettings();
|
||||
}
|
||||
|
||||
|
|
@ -161,7 +230,7 @@ void Project::updateDeprecatedProjectSettingsInteractively()
|
|||
{
|
||||
jassert (! ProjucerApplication::getApp().isRunningCommandLine);
|
||||
|
||||
for (Project::ExporterIterator exporter (*this); exporter.next();)
|
||||
for (ExporterIterator exporter (*this); exporter.next();)
|
||||
exporter->updateDeprecatedSettingsInteractively();
|
||||
}
|
||||
|
||||
|
|
@ -226,6 +295,14 @@ void Project::initialiseProjectValues()
|
|||
|
||||
void Project::initialiseAudioPluginValues()
|
||||
{
|
||||
auto makeValid4CC = [] (const String& seed)
|
||||
{
|
||||
auto s = build_tools::makeValidIdentifier (seed, false, true, false) + "xxxx";
|
||||
|
||||
return s.substring (0, 1).toUpperCase()
|
||||
+ s.substring (1, 4).toLowerCase();
|
||||
};
|
||||
|
||||
pluginFormatsValue.referTo (projectRoot, Ids::pluginFormats, getUndoManager(),
|
||||
Array<var> (Ids::buildVST3.toString(), Ids::buildAU.toString(), Ids::buildStandalone.toString()), ",");
|
||||
pluginCharacteristicsValue.referTo (projectRoot, Ids::pluginCharacteristicsValue, getUndoManager(), Array<var> (), ",");
|
||||
|
|
@ -259,7 +336,7 @@ void Project::updateOldStyleConfigList()
|
|||
{
|
||||
projectRoot.removeChild (deprecatedConfigsList, nullptr);
|
||||
|
||||
for (Project::ExporterIterator exporter (*this); exporter.next();)
|
||||
for (ExporterIterator exporter (*this); exporter.next();)
|
||||
{
|
||||
if (exporter->getNumConfigurations() == 0)
|
||||
{
|
||||
|
|
@ -287,7 +364,7 @@ void Project::moveOldPropertyFromProjectToAllExporters (Identifier name)
|
|||
{
|
||||
if (projectRoot.hasProperty (name))
|
||||
{
|
||||
for (Project::ExporterIterator exporter (*this); exporter.next();)
|
||||
for (ExporterIterator exporter (*this); exporter.next();)
|
||||
exporter->settings.setProperty (name, projectRoot [name], nullptr);
|
||||
|
||||
projectRoot.removeProperty (name, nullptr);
|
||||
|
|
@ -325,7 +402,7 @@ void Project::removeDefunctExporters()
|
|||
|
||||
void Project::updateOldModulePaths()
|
||||
{
|
||||
for (Project::ExporterIterator exporter (*this); exporter.next();)
|
||||
for (ExporterIterator exporter (*this); exporter.next();)
|
||||
exporter->updateOldModulePaths();
|
||||
}
|
||||
|
||||
|
|
@ -499,32 +576,6 @@ static constexpr int getBuiltJuceVersion()
|
|||
+ JUCE_BUILDNUMBER;
|
||||
}
|
||||
|
||||
static bool isModuleNewerThanProjucer (const ModuleDescription& module)
|
||||
{
|
||||
return module.getID().startsWith ("juce_") && getJuceVersion (module.getVersion()) > getBuiltJuceVersion();
|
||||
}
|
||||
|
||||
void Project::warnAboutOldProjucerVersion()
|
||||
{
|
||||
for (auto& juceModule : ProjucerApplication::getApp().getJUCEPathModuleList().getAllModules())
|
||||
{
|
||||
if (isModuleNewerThanProjucer ({ juceModule.second }))
|
||||
{
|
||||
if (ProjucerApplication::getApp().isRunningCommandLine)
|
||||
std::cout << "WARNING! This version of the Projucer is out-of-date!" << std::endl;
|
||||
else
|
||||
AlertWindow::showMessageBoxAsync (AlertWindow::WarningIcon,
|
||||
"Projucer",
|
||||
"This version of the Projucer is out-of-date!"
|
||||
"\n\n"
|
||||
"Always make sure that you're running the very latest version, "
|
||||
"preferably compiled directly from the JUCE repository that you're working with!");
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
static File lastDocumentOpened;
|
||||
|
||||
|
|
@ -560,7 +611,7 @@ Result Project::loadDocument (const File& file)
|
|||
|
||||
registerRecentFile (file);
|
||||
|
||||
enabledModuleList.reset();
|
||||
enabledModulesList.reset();
|
||||
|
||||
projectRoot = newTree;
|
||||
projectRoot.addListener (this);
|
||||
|
|
@ -582,60 +633,303 @@ Result Project::loadDocument (const File& file)
|
|||
moveOldPropertyFromProjectToAllExporters (Ids::smallIcon);
|
||||
getEnabledModules().sortAlphabetically();
|
||||
|
||||
compileEngineSettings.reset (new CompileEngineSettings (projectRoot));
|
||||
|
||||
exporterPathsModulesList.reset (new AvailableModulesList());
|
||||
rescanExporterPathModules (! ProjucerApplication::getApp().isRunningCommandLine);
|
||||
exporterPathsModulesList->addListener (this);
|
||||
|
||||
setCppVersionFromOldExporterSettings();
|
||||
updateDeprecatedProjectSettings();
|
||||
|
||||
setChangedFlag (false);
|
||||
|
||||
if (! ProjucerApplication::getApp().isRunningCommandLine)
|
||||
warnAboutOldProjucerVersion();
|
||||
|
||||
compileEngineSettings.reset (new CompileEngineSettings (projectRoot));
|
||||
|
||||
exporterPathsModuleList.reset (new AvailableModuleList());
|
||||
rescanExporterPathModules (! ProjucerApplication::getApp().isRunningCommandLine);
|
||||
updateLicenseWarning();
|
||||
|
||||
return Result::ok();
|
||||
}
|
||||
|
||||
Result Project::saveDocument (const File& file)
|
||||
{
|
||||
return saveProject (file, false);
|
||||
jassert (file == getFile());
|
||||
ignoreUnused (file);
|
||||
|
||||
return saveProject();
|
||||
}
|
||||
|
||||
Result Project::saveProject (const File& file, bool isCommandLineApp)
|
||||
Result Project::saveProject (ProjectExporter* exporterToSave)
|
||||
{
|
||||
if (isSaveAndExportDisabled())
|
||||
return Result::fail ("Save and export is disabled.");
|
||||
|
||||
if (isSaving)
|
||||
return Result::ok();
|
||||
|
||||
if (isTemporaryProject())
|
||||
{
|
||||
askUserWhereToSaveProject();
|
||||
saveAndMoveTemporaryProject (false);
|
||||
return Result::ok();
|
||||
}
|
||||
|
||||
updateProjectSettings();
|
||||
|
||||
if (! isCommandLineApp)
|
||||
if (! ProjucerApplication::getApp().isRunningCommandLine)
|
||||
{
|
||||
ProjucerApplication::getApp().openDocumentManager.saveAll();
|
||||
|
||||
if (! isTemporaryProject())
|
||||
registerRecentFile (file);
|
||||
registerRecentFile (getFile());
|
||||
}
|
||||
|
||||
const ScopedValueSetter<bool> vs (isSaving, true, false);
|
||||
|
||||
ProjectSaver saver (*this, file);
|
||||
return saver.save (! isCommandLineApp, shouldWaitAfterSaving, specifiedExporterToSave);
|
||||
ProjectSaver saver (*this);
|
||||
return saver.save (exporterToSave);
|
||||
}
|
||||
|
||||
Result Project::saveResourcesOnly (const File& file)
|
||||
Result Project::openProjectInIDE (ProjectExporter& exporterToOpen, bool saveFirst)
|
||||
{
|
||||
ProjectSaver saver (*this, file);
|
||||
for (ExporterIterator exporter (*this); exporter.next();)
|
||||
{
|
||||
if (exporter->canLaunchProject() && exporter->getName() == exporterToOpen.getName())
|
||||
{
|
||||
if (isTemporaryProject())
|
||||
{
|
||||
saveAndMoveTemporaryProject (true);
|
||||
return Result::ok();
|
||||
}
|
||||
|
||||
if (saveFirst)
|
||||
{
|
||||
auto result = saveProject();
|
||||
|
||||
if (! result.wasOk())
|
||||
return result;
|
||||
}
|
||||
|
||||
// Workaround for a bug where Xcode thinks the project is invalid if opened immediately
|
||||
// after writing
|
||||
if (saveFirst && exporter->isXcode())
|
||||
Thread::sleep (1000);
|
||||
|
||||
exporter->launchProject();
|
||||
}
|
||||
}
|
||||
|
||||
return Result::ok();
|
||||
}
|
||||
|
||||
Result Project::saveResourcesOnly()
|
||||
{
|
||||
ProjectSaver saver (*this);
|
||||
return saver.saveResourcesOnly();
|
||||
}
|
||||
|
||||
bool Project::hasIncompatibleLicenseTypeAndSplashScreenSetting() const
|
||||
{
|
||||
auto companyName = companyNameValue.get().toString();
|
||||
auto isJUCEProject = (companyName == "ROLI Ltd." || companyName == "JUCE");
|
||||
|
||||
return ! ProjucerApplication::getApp().isRunningCommandLine && ! isJUCEProject && ! shouldDisplaySplashScreen()
|
||||
&& ! ProjucerApplication::getApp().getLicenseController().getCurrentState().isPaidOrGPL();
|
||||
}
|
||||
|
||||
bool Project::isSaveAndExportDisabled() const
|
||||
{
|
||||
return ! ProjucerApplication::getApp().isRunningCommandLine && hasIncompatibleLicenseTypeAndSplashScreenSetting();
|
||||
}
|
||||
|
||||
void Project::updateLicenseWarning()
|
||||
{
|
||||
if (hasIncompatibleLicenseTypeAndSplashScreenSetting())
|
||||
{
|
||||
addProjectMessage (ProjectMessages::Ids::incompatibleLicense,
|
||||
{ { "Log in", [this] { ProjucerApplication::getApp().mainWindowList.getMainWindowForFile (getFile())->showLoginFormOverlay(); } },
|
||||
{ "Enable splash screen", [this] { displaySplashScreenValue = true; } } });
|
||||
}
|
||||
else
|
||||
{
|
||||
removeProjectMessage (ProjectMessages::Ids::incompatibleLicense);
|
||||
}
|
||||
}
|
||||
|
||||
void Project::updateJUCEPathWarning()
|
||||
{
|
||||
if (ProjucerApplication::getApp().shouldPromptUserAboutIncorrectJUCEPath()
|
||||
&& ProjucerApplication::getApp().settings->isJUCEPathIncorrect())
|
||||
{
|
||||
auto dontAskAgain = [this]
|
||||
{
|
||||
ProjucerApplication::getApp().setShouldPromptUserAboutIncorrectJUCEPath (false);
|
||||
removeProjectMessage (ProjectMessages::Ids::jucePath);
|
||||
};
|
||||
|
||||
addProjectMessage (ProjectMessages::Ids::jucePath,
|
||||
{ { "Set path", [] { ProjucerApplication::getApp().showPathsWindow (true); } },
|
||||
{ "Ignore", [this] { removeProjectMessage (ProjectMessages::Ids::jucePath); } },
|
||||
{ "Don't ask again", std::move (dontAskAgain) } });
|
||||
}
|
||||
else
|
||||
{
|
||||
removeProjectMessage (ProjectMessages::Ids::jucePath);
|
||||
}
|
||||
}
|
||||
|
||||
void Project::updateModuleWarnings()
|
||||
{
|
||||
auto& modules = getEnabledModules();
|
||||
|
||||
bool cppStandard = false, missingDependencies = false, oldProjucer = false, moduleNotFound = false;
|
||||
|
||||
for (auto moduleID : modules.getAllModules())
|
||||
{
|
||||
if (! cppStandard && modules.doesModuleHaveHigherCppStandardThanProject (moduleID))
|
||||
cppStandard = true;
|
||||
|
||||
if (! missingDependencies && ! modules.getExtraDependenciesNeeded (moduleID).isEmpty())
|
||||
missingDependencies = true;
|
||||
|
||||
auto info = modules.getModuleInfo (moduleID);
|
||||
|
||||
if (! oldProjucer && (isJUCEModule (moduleID) && getJuceVersion (info.getVersion()) > getBuiltJuceVersion()))
|
||||
oldProjucer = true;
|
||||
|
||||
if (! moduleNotFound && ! info.isValid())
|
||||
moduleNotFound = true;
|
||||
}
|
||||
|
||||
updateCppStandardWarning (cppStandard);
|
||||
updateMissingModuleDependenciesWarning (missingDependencies);
|
||||
updateOldProjucerWarning (oldProjucer);
|
||||
updateModuleNotFoundWarning (moduleNotFound);
|
||||
}
|
||||
|
||||
void Project::updateCppStandardWarning (bool showWarning)
|
||||
{
|
||||
if (showWarning)
|
||||
{
|
||||
auto removeModules = [this]
|
||||
{
|
||||
auto& modules = getEnabledModules();
|
||||
|
||||
for (auto& module : modules.getModulesWithHigherCppStandardThanProject())
|
||||
modules.removeModule (module);
|
||||
};
|
||||
|
||||
auto updateCppStandard = [this]
|
||||
{
|
||||
cppStandardValue = getEnabledModules().getHighestModuleCppStandard();
|
||||
};
|
||||
|
||||
addProjectMessage (ProjectMessages::Ids::cppStandard,
|
||||
{ { "Update project C++ standard" , std::move (updateCppStandard) },
|
||||
{ "Remove module(s)", std::move (removeModules) } });
|
||||
}
|
||||
else
|
||||
{
|
||||
removeProjectMessage (ProjectMessages::Ids::cppStandard);
|
||||
}
|
||||
}
|
||||
|
||||
void Project::updateMissingModuleDependenciesWarning (bool showWarning)
|
||||
{
|
||||
if (showWarning)
|
||||
{
|
||||
auto removeModules = [this]
|
||||
{
|
||||
auto& modules = getEnabledModules();
|
||||
|
||||
for (auto& mod : modules.getModulesWithMissingDependencies())
|
||||
modules.removeModule (mod);
|
||||
};
|
||||
|
||||
auto addMissingDependencies = [this]
|
||||
{
|
||||
auto& modules = getEnabledModules();
|
||||
|
||||
for (auto& mod : modules.getModulesWithMissingDependencies())
|
||||
modules.tryToFixMissingDependencies (mod);
|
||||
};
|
||||
|
||||
addProjectMessage (ProjectMessages::Ids::missingModuleDependencies,
|
||||
{ { "Add missing dependencies", std::move (addMissingDependencies) },
|
||||
{ "Remove module(s)", std::move (removeModules) } });
|
||||
}
|
||||
else
|
||||
{
|
||||
removeProjectMessage (ProjectMessages::Ids::missingModuleDependencies);
|
||||
}
|
||||
}
|
||||
|
||||
void Project::updateOldProjucerWarning (bool showWarning)
|
||||
{
|
||||
if (showWarning)
|
||||
addProjectMessage (ProjectMessages::Ids::oldProjucer, {});
|
||||
else
|
||||
removeProjectMessage (ProjectMessages::Ids::oldProjucer);
|
||||
}
|
||||
|
||||
void Project::updateModuleNotFoundWarning (bool showWarning)
|
||||
{
|
||||
if (showWarning)
|
||||
addProjectMessage (ProjectMessages::Ids::moduleNotFound, {});
|
||||
else
|
||||
removeProjectMessage (ProjectMessages::Ids::moduleNotFound);
|
||||
}
|
||||
|
||||
void Project::licenseStateChanged()
|
||||
{
|
||||
updateLicenseWarning();
|
||||
}
|
||||
|
||||
void Project::changeListenerCallback (ChangeBroadcaster*)
|
||||
{
|
||||
updateJUCEPathWarning();
|
||||
}
|
||||
|
||||
void Project::availableModulesChanged (AvailableModulesList* listThatHasChanged)
|
||||
{
|
||||
if (listThatHasChanged == &ProjucerApplication::getApp().getJUCEPathModulesList())
|
||||
updateJUCEPathWarning();
|
||||
|
||||
updateModuleWarnings();
|
||||
}
|
||||
|
||||
void Project::addProjectMessage (const Identifier& messageToAdd,
|
||||
std::vector<ProjectMessages::MessageAction>&& actions)
|
||||
{
|
||||
removeProjectMessage (messageToAdd);
|
||||
|
||||
messageActions[messageToAdd] = std::move (actions);
|
||||
|
||||
ValueTree child (messageToAdd);
|
||||
child.setProperty (ProjectMessages::Ids::isVisible, true, nullptr);
|
||||
|
||||
projectMessages.getChildWithName (ProjectMessages::getTypeForMessage (messageToAdd)).addChild (child, -1, nullptr);
|
||||
}
|
||||
|
||||
void Project::removeProjectMessage (const Identifier& messageToRemove)
|
||||
{
|
||||
auto subTree = projectMessages.getChildWithName (ProjectMessages::getTypeForMessage (messageToRemove));
|
||||
auto child = subTree.getChildWithName (messageToRemove);
|
||||
|
||||
if (child.isValid())
|
||||
subTree.removeChild (child, nullptr);
|
||||
|
||||
messageActions.erase (messageToRemove);
|
||||
}
|
||||
|
||||
std::vector<ProjectMessages::MessageAction> Project::getMessageActions (const Identifier& message)
|
||||
{
|
||||
auto iter = messageActions.find (message);
|
||||
|
||||
if (iter != messageActions.end())
|
||||
return iter->second;
|
||||
|
||||
jassertfalse;
|
||||
return {};
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
void Project::setTemporaryDirectory (const File& dir) noexcept
|
||||
{
|
||||
|
|
@ -645,17 +939,16 @@ void Project::setTemporaryDirectory (const File& dir) noexcept
|
|||
forgetRecentFile (getFile());
|
||||
}
|
||||
|
||||
void Project::askUserWhereToSaveProject()
|
||||
void Project::saveAndMoveTemporaryProject (bool openInIDE)
|
||||
{
|
||||
FileChooser fc ("Save Project");
|
||||
fc.browseForDirectory();
|
||||
|
||||
if (fc.getResult().exists())
|
||||
moveTemporaryDirectory (fc.getResult());
|
||||
}
|
||||
auto newParentDirectory = fc.getResult();
|
||||
|
||||
if (! newParentDirectory.exists())
|
||||
return;
|
||||
|
||||
void Project::moveTemporaryDirectory (const File& newParentDirectory)
|
||||
{
|
||||
auto newDirectory = newParentDirectory.getChildFile (tempDirectory.getFileName());
|
||||
auto oldJucerFileName = getFile().getFileName();
|
||||
|
||||
|
|
@ -670,10 +963,12 @@ void Project::moveTemporaryDirectory (const File& newParentDirectory)
|
|||
{
|
||||
Component::SafePointer<MainWindow> safeWindow (window);
|
||||
|
||||
MessageManager::callAsync ([safeWindow, newDirectory, oldJucerFileName]
|
||||
MessageManager::callAsync ([safeWindow, newDirectory, oldJucerFileName, openInIDE]() mutable
|
||||
{
|
||||
if (safeWindow != nullptr)
|
||||
safeWindow.getComponent()->moveProject (newDirectory.getChildFile (oldJucerFileName));
|
||||
safeWindow->moveProject (newDirectory.getChildFile (oldJucerFileName),
|
||||
openInIDE ? MainWindow::OpenInIDE::yes
|
||||
: MainWindow::OpenInIDE::no);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
@ -724,14 +1019,43 @@ void Project::valueTreePropertyChanged (ValueTree& tree, const Identifier& prope
|
|||
if (shouldWriteLegacyPluginCharacteristicsSettings)
|
||||
writeLegacyPluginCharacteristicsSettings();
|
||||
}
|
||||
else if (property == Ids::displaySplashScreen)
|
||||
{
|
||||
updateLicenseWarning();
|
||||
}
|
||||
else if (property == Ids::cppLanguageStandard)
|
||||
{
|
||||
updateModuleWarnings();
|
||||
}
|
||||
|
||||
changed();
|
||||
}
|
||||
}
|
||||
|
||||
void Project::valueTreeChildAdded (ValueTree&, ValueTree&) { changed(); }
|
||||
void Project::valueTreeChildRemoved (ValueTree&, ValueTree&, int) { changed(); }
|
||||
void Project::valueTreeChildOrderChanged (ValueTree&, int, int) { changed(); }
|
||||
void Project::valueTreeChildAdded (ValueTree& parent, ValueTree& child)
|
||||
{
|
||||
ignoreUnused (parent);
|
||||
|
||||
if (child.getType() == Ids::MODULE)
|
||||
updateModuleWarnings();
|
||||
|
||||
changed();
|
||||
}
|
||||
|
||||
void Project::valueTreeChildRemoved (ValueTree& parent, ValueTree& child, int index)
|
||||
{
|
||||
ignoreUnused (parent, index);
|
||||
|
||||
if (child.getType() == Ids::MODULE)
|
||||
updateModuleWarnings();
|
||||
|
||||
changed();
|
||||
}
|
||||
|
||||
void Project::valueTreeChildOrderChanged (ValueTree&, int, int)
|
||||
{
|
||||
changed();
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
bool Project::hasProjectBeenModified()
|
||||
|
|
@ -888,24 +1212,17 @@ void Project::createPropertyEditors (PropertyListBuilder& props)
|
|||
"no such statement will be included. This setting used to be enabled by default, but it "
|
||||
"is recommended to leave it disabled for new projects.");
|
||||
|
||||
{
|
||||
String licenseRequiredTagline ("Required for closed source applications without an Indie or Pro JUCE license");
|
||||
String licenseRequiredInfo ("In accordance with the terms of the JUCE 5 End-Use License Agreement (www.juce.com/juce-5-licence), "
|
||||
"this option can only be disabled for closed source applications if you have a JUCE Indie or Pro "
|
||||
"license, or are using JUCE under the GPL v3 license.");
|
||||
props.add (new ChoicePropertyComponent (displaySplashScreenValue, "Display the JUCE Splash Screen (required for closed source applications without an Indie or Pro JUCE license)"),
|
||||
"This option controls the display of the standard JUCE splash screen. "
|
||||
"In accordance with the terms of the JUCE 5 End-Use License Agreement (www.juce.com/juce-5-licence), "
|
||||
"this option can only be disabled for closed source applications if you have a JUCE Indie or Pro "
|
||||
"license, or are using JUCE under the GPL v3 license.");
|
||||
|
||||
StringPairArray description;
|
||||
description.set ("Display the JUCE splash screen", "This option controls the display of the standard JUCE splash screen.");
|
||||
|
||||
props.add (new ChoicePropertyComponent (displaySplashScreenValue, String ("Display the JUCE Splash Screen") + " (" + licenseRequiredTagline + ")"),
|
||||
description["Display the JUCE splash screen"] + " " + licenseRequiredInfo);
|
||||
}
|
||||
|
||||
props.add (new ChoicePropertyComponent (splashScreenColourValue, "Splash Screen Colour",
|
||||
{ "Dark", "Light" },
|
||||
{ "Dark", "Light" }),
|
||||
props.add (new ChoicePropertyComponentWithEnablement (splashScreenColourValue, displaySplashScreenValue, "Splash Screen Colour",
|
||||
{ "Dark", "Light" }, { "Dark", "Light" }),
|
||||
"Choose the colour of the JUCE splash screen.");
|
||||
|
||||
|
||||
{
|
||||
StringArray projectTypeNames;
|
||||
Array<var> projectTypeCodes;
|
||||
|
|
@ -954,8 +1271,8 @@ void Project::createPropertyEditors (PropertyListBuilder& props)
|
|||
"The namespace containing the binary assets.");
|
||||
|
||||
props.add (new ChoicePropertyComponent (cppStandardValue, "C++ Language Standard",
|
||||
{ "C++11", "C++14", "C++17", "Use Latest" },
|
||||
{ "11", "14", "17", "latest" }),
|
||||
getCppStandardStrings(),
|
||||
getCppStandardVars()),
|
||||
"The standard of the C++ language that will be used for compilation.");
|
||||
|
||||
props.add (new TextPropertyComponent (preprocessorDefsValue, "Preprocessor Definitions", 32768, true),
|
||||
|
|
@ -1912,12 +2229,12 @@ Array<var> Project::getDefaultRTASCategories() const noexcept
|
|||
}
|
||||
|
||||
//==============================================================================
|
||||
EnabledModuleList& Project::getEnabledModules()
|
||||
EnabledModulesList& Project::getEnabledModules()
|
||||
{
|
||||
if (enabledModuleList == nullptr)
|
||||
enabledModuleList.reset (new EnabledModuleList (*this, projectRoot.getOrCreateChildWithName (Ids::MODULES, nullptr)));
|
||||
if (enabledModulesList == nullptr)
|
||||
enabledModulesList.reset (new EnabledModulesList (*this, projectRoot.getOrCreateChildWithName (Ids::MODULES, nullptr)));
|
||||
|
||||
return *enabledModuleList;
|
||||
return *enabledModulesList;
|
||||
}
|
||||
|
||||
static StringArray getModulePathsFromExporters (Project& project, bool onlyThisOS)
|
||||
|
|
@ -1979,37 +2296,38 @@ static Array<File> getExporterModulePathsToScan (Project& project)
|
|||
return files;
|
||||
}
|
||||
|
||||
AvailableModuleList& Project::getExporterPathsModuleList()
|
||||
AvailableModulesList& Project::getExporterPathsModulesList()
|
||||
{
|
||||
return *exporterPathsModuleList;
|
||||
jassert (exporterPathsModulesList != nullptr);
|
||||
return *exporterPathsModulesList;
|
||||
}
|
||||
|
||||
void Project::rescanExporterPathModules (bool async)
|
||||
{
|
||||
if (async)
|
||||
exporterPathsModuleList->scanPathsAsync (getExporterModulePathsToScan (*this));
|
||||
exporterPathsModulesList->scanPathsAsync (getExporterModulePathsToScan (*this));
|
||||
else
|
||||
exporterPathsModuleList->scanPaths (getExporterModulePathsToScan (*this));
|
||||
exporterPathsModulesList->scanPaths (getExporterModulePathsToScan (*this));
|
||||
}
|
||||
|
||||
AvailableModuleList::ModuleIDAndFolder Project::getModuleWithID (const String& id)
|
||||
AvailableModulesList::ModuleIDAndFolder Project::getModuleWithID (const String& id)
|
||||
{
|
||||
if (! getEnabledModules().shouldUseGlobalPath (id))
|
||||
{
|
||||
const auto& mod = exporterPathsModuleList->getModuleWithID (id);
|
||||
const auto& mod = exporterPathsModulesList->getModuleWithID (id);
|
||||
|
||||
if (mod.second != File())
|
||||
return mod;
|
||||
}
|
||||
|
||||
const auto& list = (isJUCEModule (id) ? ProjucerApplication::getApp().getJUCEPathModuleList().getAllModules()
|
||||
: ProjucerApplication::getApp().getUserPathsModuleList().getAllModules());
|
||||
const auto& list = (isJUCEModule (id) ? ProjucerApplication::getApp().getJUCEPathModulesList().getAllModules()
|
||||
: ProjucerApplication::getApp().getUserPathsModulesList().getAllModules());
|
||||
|
||||
for (auto& m : list)
|
||||
if (m.first == id)
|
||||
return m;
|
||||
|
||||
return exporterPathsModuleList->getModuleWithID (id);
|
||||
return exporterPathsModulesList->getModuleWithID (id);
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
|
|
|
|||
|
|
@ -18,16 +18,96 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include "../Application/UserAccount/jucer_LicenseController.h"
|
||||
#include "Modules/jucer_AvailableModulesList.h"
|
||||
|
||||
class ProjectExporter;
|
||||
class LibraryModule;
|
||||
class EnabledModuleList;
|
||||
class AvailableModuleList;
|
||||
class ProjectContentComponent;
|
||||
class EnabledModulesList;
|
||||
class CompileEngineSettings;
|
||||
|
||||
namespace ProjectMessages
|
||||
{
|
||||
namespace Ids
|
||||
{
|
||||
#define DECLARE_ID(name) static const Identifier name (#name)
|
||||
|
||||
DECLARE_ID (projectMessages);
|
||||
|
||||
DECLARE_ID (incompatibleLicense);
|
||||
DECLARE_ID (cppStandard);
|
||||
DECLARE_ID (moduleNotFound);
|
||||
DECLARE_ID (jucePath);
|
||||
DECLARE_ID (jucerFileModified);
|
||||
DECLARE_ID (missingModuleDependencies);
|
||||
DECLARE_ID (oldProjucer);
|
||||
DECLARE_ID (newVersionAvailable);
|
||||
|
||||
DECLARE_ID (notification);
|
||||
DECLARE_ID (warning);
|
||||
|
||||
DECLARE_ID (isVisible);
|
||||
|
||||
#undef DECLARE_ID
|
||||
}
|
||||
|
||||
inline Identifier getTypeForMessage (const Identifier& message)
|
||||
{
|
||||
if (message == Ids::incompatibleLicense || message == Ids::cppStandard || message == Ids::moduleNotFound
|
||||
|| message == Ids::jucePath || message == Ids::jucerFileModified || message == Ids::missingModuleDependencies
|
||||
|| message == Ids::oldProjucer)
|
||||
{
|
||||
return Ids::warning;
|
||||
}
|
||||
|
||||
if (message == Ids::newVersionAvailable)
|
||||
{
|
||||
return Ids::notification;
|
||||
}
|
||||
|
||||
jassertfalse;
|
||||
return {};
|
||||
}
|
||||
|
||||
inline String getTitleForMessage (const Identifier& message)
|
||||
{
|
||||
if (message == Ids::incompatibleLicense) return "Incompatible License and Splash Screen Setting";
|
||||
if (message == Ids::cppStandard) return "C++ Standard";
|
||||
if (message == Ids::moduleNotFound) return "Module Not Found";
|
||||
if (message == Ids::jucePath) return "JUCE Path";
|
||||
if (message == Ids::jucerFileModified) return "Project File Modified";
|
||||
if (message == Ids::missingModuleDependencies) return "Missing Module Dependencies";
|
||||
if (message == Ids::oldProjucer) return "Projucer Out of Date";
|
||||
if (message == Ids::newVersionAvailable) return "New Version Available";
|
||||
|
||||
jassertfalse;
|
||||
return {};
|
||||
}
|
||||
|
||||
inline String getDescriptionForMessage (const Identifier& message)
|
||||
{
|
||||
if (message == Ids::incompatibleLicense) return "Save and export is disabled.";
|
||||
if (message == Ids::cppStandard) return "Module(s) have a higher C++ standard requirement than the project.";
|
||||
if (message == Ids::moduleNotFound) return "Module(s) could not be found at the specified paths.";
|
||||
if (message == Ids::jucePath) return "The path to your JUCE folder is incorrect.";
|
||||
if (message == Ids::jucerFileModified) return "The .jucer file has been modified since the last save.";
|
||||
if (message == Ids::missingModuleDependencies) return "Module(s) have missing dependencies.";
|
||||
if (message == Ids::oldProjucer) return "The version of the Projucer you are using is out of date.";
|
||||
if (message == Ids::newVersionAvailable) return "A new version of JUCE is available to download.";
|
||||
|
||||
jassertfalse;
|
||||
return {};
|
||||
}
|
||||
|
||||
using MessageAction = std::pair<String, std::function<void()>>;
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
class Project : public FileBasedDocument,
|
||||
public ValueTree::Listener
|
||||
public ValueTree::Listener,
|
||||
private LicenseController::LicenseStateListener,
|
||||
private ChangeListener,
|
||||
private AvailableModulesList::Listener
|
||||
{
|
||||
public:
|
||||
//==============================================================================
|
||||
|
|
@ -35,12 +115,14 @@ public:
|
|||
~Project() override;
|
||||
|
||||
//==============================================================================
|
||||
// FileBasedDocument stuff..
|
||||
String getDocumentTitle() override;
|
||||
Result loadDocument (const File& file) override;
|
||||
Result saveDocument (const File& file) override;
|
||||
Result saveProject (const File& file, bool isCommandLineApp);
|
||||
Result saveResourcesOnly (const File& file);
|
||||
|
||||
Result saveProject (ProjectExporter* exporterToSave = nullptr);
|
||||
Result saveResourcesOnly();
|
||||
Result openProjectInIDE (ProjectExporter& exporterToOpen, bool saveFirst);
|
||||
|
||||
File getLastDocumentOpened() override;
|
||||
void setLastDocumentOpened (const File& file) override;
|
||||
|
||||
|
|
@ -116,6 +198,9 @@ public:
|
|||
bool shouldDisplaySplashScreen() const { return displaySplashScreenValue.get(); }
|
||||
String getSplashScreenColourString() const { return splashScreenColourValue.get(); }
|
||||
|
||||
static StringArray getCppStandardStrings() { return { "C++11", "C++14", "C++17", "Use Latest" }; }
|
||||
static Array<var> getCppStandardVars() { return { "11", "14", "17", "latest" }; }
|
||||
|
||||
String getCppStandardString() const { return cppStandardValue.get(); }
|
||||
|
||||
StringArray getCompilerFlagSchemes() const;
|
||||
|
|
@ -363,9 +448,9 @@ public:
|
|||
bool isConfigFlagEnabled (const String& name, bool defaultIsEnabled = false) const;
|
||||
|
||||
//==============================================================================
|
||||
EnabledModuleList& getEnabledModules();
|
||||
EnabledModulesList& getEnabledModules();
|
||||
|
||||
AvailableModuleList& getExporterPathsModuleList();
|
||||
AvailableModulesList& getExporterPathsModulesList();
|
||||
void rescanExporterPathModules (bool async = false);
|
||||
|
||||
std::pair<String, File> getModuleWithID (const String&);
|
||||
|
|
@ -397,22 +482,45 @@ public:
|
|||
String getUniqueTargetFolderSuffixForExporter (const String& exporterName, const String& baseTargetFolder);
|
||||
|
||||
//==============================================================================
|
||||
bool isCurrentlySaving() const noexcept { return isSaving; }
|
||||
bool shouldWaitAfterSaving = false;
|
||||
String specifiedExporterToSave = {};
|
||||
bool isCurrentlySaving() const noexcept { return isSaving; }
|
||||
|
||||
//==============================================================================
|
||||
bool isTemporaryProject() const noexcept { return tempDirectory != File(); }
|
||||
File getTemporaryDirectory() const noexcept { return tempDirectory; }
|
||||
void setTemporaryDirectory (const File&) noexcept;
|
||||
|
||||
void setOpenInIDEAfterSaving (bool open) noexcept { openInIDEAfterSaving = open; }
|
||||
bool shouldOpenInIDEAfterSaving() const noexcept { return openInIDEAfterSaving; }
|
||||
|
||||
//==============================================================================
|
||||
CompileEngineSettings& getCompileEngineSettings() { return *compileEngineSettings; }
|
||||
|
||||
//==============================================================================
|
||||
ValueTree getProjectMessages() const { return projectMessages; }
|
||||
|
||||
void addProjectMessage (const Identifier& messageToAdd, std::vector<ProjectMessages::MessageAction>&& messageActions);
|
||||
void removeProjectMessage (const Identifier& messageToRemove);
|
||||
|
||||
std::vector<ProjectMessages::MessageAction> getMessageActions (const Identifier& message);
|
||||
|
||||
//==============================================================================
|
||||
bool hasIncompatibleLicenseTypeAndSplashScreenSetting() const;
|
||||
bool isSaveAndExportDisabled() const;
|
||||
|
||||
private:
|
||||
//==============================================================================
|
||||
struct ProjectFileModificationPoller : private Timer
|
||||
{
|
||||
ProjectFileModificationPoller (Project& p);
|
||||
|
||||
private:
|
||||
void timerCallback() override;
|
||||
void reset();
|
||||
|
||||
void keepProject();
|
||||
void reloadProjectFromDisk();
|
||||
|
||||
Project& project;
|
||||
bool showingWarning = false;
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
ValueTree projectRoot { Ids::JUCERPROJECT };
|
||||
|
||||
ValueWithDefault projectNameValue, projectUIDValue, projectLineFeedValue, projectTypeValue, versionValue, bundleIdentifierValue, companyNameValue,
|
||||
|
|
@ -427,8 +535,8 @@ private:
|
|||
|
||||
//==============================================================================
|
||||
std::unique_ptr<CompileEngineSettings> compileEngineSettings;
|
||||
std::unique_ptr<EnabledModuleList> enabledModuleList;
|
||||
std::unique_ptr<AvailableModuleList> exporterPathsModuleList;
|
||||
std::unique_ptr<EnabledModulesList> enabledModulesList;
|
||||
std::unique_ptr<AvailableModulesList> exporterPathsModulesList;
|
||||
|
||||
//==============================================================================
|
||||
void updateDeprecatedProjectSettings();
|
||||
|
|
@ -449,10 +557,8 @@ private:
|
|||
|
||||
//==============================================================================
|
||||
File tempDirectory = {};
|
||||
bool openInIDEAfterSaving = false;
|
||||
|
||||
void askUserWhereToSaveProject();
|
||||
void moveTemporaryDirectory (const File&);
|
||||
void saveAndMoveTemporaryProject (bool openInIDE);
|
||||
bool saveProjectRootToFile();
|
||||
|
||||
//==============================================================================
|
||||
|
|
@ -481,7 +587,27 @@ private:
|
|||
void moveOldPropertyFromProjectToAllExporters (Identifier name);
|
||||
void removeDefunctExporters();
|
||||
void updateOldModulePaths();
|
||||
void warnAboutOldProjucerVersion();
|
||||
|
||||
//==============================================================================
|
||||
void licenseStateChanged() override;
|
||||
void changeListenerCallback (ChangeBroadcaster*) override;
|
||||
void availableModulesChanged (AvailableModulesList*) override;
|
||||
|
||||
void updateLicenseWarning();
|
||||
void updateJUCEPathWarning();
|
||||
|
||||
void updateModuleWarnings();
|
||||
void updateCppStandardWarning (bool showWarning);
|
||||
void updateMissingModuleDependenciesWarning (bool showWarning);
|
||||
void updateOldProjucerWarning (bool showWarning);
|
||||
void updateModuleNotFoundWarning (bool showWarning);
|
||||
|
||||
ValueTree projectMessages { ProjectMessages::Ids::projectMessages, {},
|
||||
{ { ProjectMessages::Ids::notification, {} }, { ProjectMessages::Ids::warning, {} } } };
|
||||
std::map<Identifier, std::vector<ProjectMessages::MessageAction>> messageActions;
|
||||
|
||||
ProjectFileModificationPoller fileModificationPoller { *this };
|
||||
|
||||
//==============================================================================
|
||||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (Project)
|
||||
};
|
||||
|
|
|
|||
|
|
@ -16,12 +16,655 @@
|
|||
==============================================================================
|
||||
*/
|
||||
|
||||
#include "../Application/jucer_Headers.h"
|
||||
#include "jucer_ProjectSaver.h"
|
||||
|
||||
#include "jucer_ProjectExport_CLion.h"
|
||||
#include "../Application/jucer_Application.h"
|
||||
|
||||
static constexpr const char* generatedGroupID = "__jucelibfiles";
|
||||
static constexpr const char* generatedGroupUID = "__generatedcode__";
|
||||
|
||||
//==============================================================================
|
||||
ProjectSaver::ProjectSaver (Project& p)
|
||||
: project (p),
|
||||
generatedCodeFolder (project.getGeneratedCodeFolder()),
|
||||
generatedFilesGroup (Project::Item::createGroup (project, getJuceCodeGroupName(), generatedGroupUID, true)),
|
||||
projectLineFeed (project.getProjectLineFeed())
|
||||
{
|
||||
generatedFilesGroup.setID (generatedGroupID);
|
||||
}
|
||||
|
||||
Result ProjectSaver::save (ProjectExporter* exporterToSave)
|
||||
{
|
||||
if (! ProjucerApplication::getApp().isRunningCommandLine)
|
||||
{
|
||||
SaveThreadWithProgressWindow thread (*this, exporterToSave);
|
||||
thread.runThread();
|
||||
|
||||
return thread.result;
|
||||
}
|
||||
|
||||
return saveProject (exporterToSave);
|
||||
}
|
||||
|
||||
Result ProjectSaver::saveResourcesOnly()
|
||||
{
|
||||
writeBinaryDataFiles();
|
||||
|
||||
if (errors.size() > 0)
|
||||
return Result::fail (errors[0]);
|
||||
|
||||
return Result::ok();
|
||||
}
|
||||
|
||||
void ProjectSaver::saveBasicProjectItems (const OwnedArray<LibraryModule>& modules, const String& appConfigUserContent)
|
||||
{
|
||||
writePluginDefines();
|
||||
writeAppConfigFile (modules, appConfigUserContent);
|
||||
writeBinaryDataFiles();
|
||||
writeAppHeader (modules);
|
||||
writeModuleCppWrappers (modules);
|
||||
}
|
||||
|
||||
Result ProjectSaver::saveContentNeededForLiveBuild()
|
||||
{
|
||||
auto modules = getModules();
|
||||
|
||||
if (errors.size() == 0)
|
||||
{
|
||||
saveBasicProjectItems (modules, loadUserContentFromAppConfig());
|
||||
return Result::ok();
|
||||
}
|
||||
|
||||
return Result::fail (errors[0]);
|
||||
}
|
||||
|
||||
Project::Item ProjectSaver::addFileToGeneratedGroup (const File& file)
|
||||
{
|
||||
auto item = generatedFilesGroup.findItemForFile (file);
|
||||
|
||||
if (item.isValid())
|
||||
return item;
|
||||
|
||||
generatedFilesGroup.addFileAtIndex (file, -1, true);
|
||||
return generatedFilesGroup.findItemForFile (file);
|
||||
}
|
||||
|
||||
bool ProjectSaver::copyFolder (const File& source, const File& dest)
|
||||
{
|
||||
if (source.isDirectory() && dest.createDirectory())
|
||||
{
|
||||
for (auto& f : source.findChildFiles (File::findFiles, false))
|
||||
{
|
||||
auto target = dest.getChildFile (f.getFileName());
|
||||
filesCreated.add (target);
|
||||
|
||||
if (! f.copyFileTo (target))
|
||||
return false;
|
||||
}
|
||||
|
||||
for (auto& f : source.findChildFiles (File::findDirectories, false))
|
||||
{
|
||||
auto name = f.getFileName();
|
||||
|
||||
if (name == ".git" || name == ".svn" || name == ".cvs")
|
||||
continue;
|
||||
|
||||
if (! copyFolder (f, dest.getChildFile (f.getFileName())))
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
Project::Item ProjectSaver::saveGeneratedFile (const String& filePath, const MemoryOutputStream& newData)
|
||||
{
|
||||
if (! generatedCodeFolder.createDirectory())
|
||||
{
|
||||
addError ("Couldn't create folder: " + generatedCodeFolder.getFullPathName());
|
||||
return Project::Item (project, {}, false);
|
||||
}
|
||||
|
||||
auto file = generatedCodeFolder.getChildFile (filePath);
|
||||
|
||||
if (replaceFileIfDifferent (file, newData))
|
||||
return addFileToGeneratedGroup (file);
|
||||
|
||||
return { project, {}, true };
|
||||
}
|
||||
|
||||
bool ProjectSaver::replaceFileIfDifferent (const File& f, const MemoryOutputStream& newData)
|
||||
{
|
||||
filesCreated.add (f);
|
||||
|
||||
if (! build_tools::overwriteFileWithNewDataIfDifferent (f, newData))
|
||||
{
|
||||
addError ("Can't write to file: " + f.getFullPathName());
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ProjectSaver::deleteUnwantedFilesIn (const File& parent)
|
||||
{
|
||||
// Recursively clears out any files in a folder that we didn't create, but avoids
|
||||
// any folders containing hidden files that might be used by version-control systems.
|
||||
auto shouldFileBeKept = [] (const String& filename)
|
||||
{
|
||||
static StringArray filesToKeep (".svn", ".cvs", "CMakeLists.txt");
|
||||
return filesToKeep.contains (filename);
|
||||
};
|
||||
|
||||
bool folderIsNowEmpty = true;
|
||||
Array<File> filesToDelete;
|
||||
|
||||
for (const auto& i : RangedDirectoryIterator (parent, false, "*", File::findFilesAndDirectories))
|
||||
{
|
||||
auto f = i.getFile();
|
||||
|
||||
if (filesCreated.contains (f) || shouldFileBeKept (f.getFileName()))
|
||||
{
|
||||
folderIsNowEmpty = false;
|
||||
}
|
||||
else if (i.isDirectory())
|
||||
{
|
||||
if (deleteUnwantedFilesIn (f))
|
||||
filesToDelete.add (f);
|
||||
else
|
||||
folderIsNowEmpty = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
filesToDelete.add (f);
|
||||
}
|
||||
}
|
||||
|
||||
for (int j = filesToDelete.size(); --j >= 0;)
|
||||
filesToDelete.getReference (j).deleteRecursively();
|
||||
|
||||
return folderIsNowEmpty;
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
void ProjectSaver::addError (const String& message)
|
||||
{
|
||||
const ScopedLock sl (errorLock);
|
||||
errors.add (message);
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
File ProjectSaver::getAppConfigFile() const
|
||||
{
|
||||
return generatedCodeFolder.getChildFile (Project::getAppConfigFilename());
|
||||
}
|
||||
|
||||
File ProjectSaver::getPluginDefinesFile() const
|
||||
{
|
||||
return generatedCodeFolder.getChildFile (Project::getPluginDefinesFilename());
|
||||
}
|
||||
|
||||
String ProjectSaver::loadUserContentFromAppConfig() const
|
||||
{
|
||||
StringArray userContent;
|
||||
bool foundCodeSection = false;
|
||||
auto lines = StringArray::fromLines (getAppConfigFile().loadFileAsString());
|
||||
|
||||
for (int i = 0; i < lines.size(); ++i)
|
||||
{
|
||||
if (lines[i].contains ("[BEGIN_USER_CODE_SECTION]"))
|
||||
{
|
||||
for (int j = i + 1; j < lines.size() && ! lines[j].contains ("[END_USER_CODE_SECTION]"); ++j)
|
||||
userContent.add (lines[j]);
|
||||
|
||||
foundCodeSection = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (! foundCodeSection)
|
||||
{
|
||||
userContent.add ({});
|
||||
userContent.add ("// (You can add your own code in this section, and the Projucer will not overwrite it)");
|
||||
userContent.add ({});
|
||||
}
|
||||
|
||||
return userContent.joinIntoString (projectLineFeed) + projectLineFeed;
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
OwnedArray<LibraryModule> ProjectSaver::getModules()
|
||||
{
|
||||
OwnedArray<LibraryModule> modules;
|
||||
project.getEnabledModules().createRequiredModules (modules);
|
||||
|
||||
for (auto* module : modules)
|
||||
{
|
||||
if (! module->isValid())
|
||||
{
|
||||
addError ("At least one of your JUCE module paths is invalid!\n"
|
||||
"Please go to the Modules settings page and ensure each path points to the correct JUCE modules folder.");
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
if (project.getEnabledModules().getExtraDependenciesNeeded (module->getID()).size() > 0)
|
||||
{
|
||||
addError ("At least one of your modules has missing dependencies!\n"
|
||||
"Please go to the settings page of the highlighted modules and add the required dependencies.");
|
||||
|
||||
return {};
|
||||
}
|
||||
}
|
||||
|
||||
return modules;
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
Result ProjectSaver::saveProject (ProjectExporter* specifiedExporterToSave)
|
||||
{
|
||||
if (project.getNumExporters() == 0)
|
||||
{
|
||||
return Result::fail ("No exporters found!\n"
|
||||
"Please add an exporter before saving.");
|
||||
}
|
||||
|
||||
auto oldProjectFile = project.getFile();
|
||||
auto modules = getModules();
|
||||
|
||||
if (errors.size() == 0)
|
||||
{
|
||||
writeMainProjectFile();
|
||||
project.updateModificationTime();
|
||||
|
||||
auto projectRootHash = project.getProjectRoot().toXmlString().hashCode();
|
||||
|
||||
if (project.isAudioPluginProject())
|
||||
{
|
||||
if (project.shouldBuildUnityPlugin())
|
||||
writeUnityScriptFile();
|
||||
}
|
||||
|
||||
saveBasicProjectItems (modules, loadUserContentFromAppConfig());
|
||||
writeProjects (modules, specifiedExporterToSave);
|
||||
runPostExportScript();
|
||||
|
||||
// if the project root has changed after writing the other files then re-save it
|
||||
if (project.getProjectRoot().toXmlString().hashCode() != projectRootHash)
|
||||
{
|
||||
writeMainProjectFile();
|
||||
project.updateModificationTime();
|
||||
}
|
||||
|
||||
if (generatedCodeFolder.exists())
|
||||
{
|
||||
writeReadmeFile();
|
||||
deleteUnwantedFilesIn (generatedCodeFolder);
|
||||
}
|
||||
|
||||
if (errors.size() == 0)
|
||||
return Result::ok();
|
||||
}
|
||||
|
||||
project.setFile (oldProjectFile);
|
||||
return Result::fail (errors[0]);
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
void ProjectSaver::writeMainProjectFile()
|
||||
{
|
||||
if (auto xml = project.getProjectRoot().createXml())
|
||||
{
|
||||
XmlElement::TextFormat format;
|
||||
format.newLineChars = projectLineFeed.toRawUTF8();
|
||||
|
||||
MemoryOutputStream mo (8192);
|
||||
xml->writeTo (mo, format);
|
||||
replaceFileIfDifferent (project.getFile(), mo);
|
||||
}
|
||||
else
|
||||
{
|
||||
addError ("Failed to write main project file: " + project.getFile().getFullPathName());
|
||||
}
|
||||
}
|
||||
|
||||
static void writeAutoGenWarningComment (OutputStream& out)
|
||||
{
|
||||
out << "/*" << newLine << newLine
|
||||
<< " IMPORTANT! This file is auto-generated each time you save your" << newLine
|
||||
<< " project - if you alter its contents, your changes may be overwritten!" << newLine
|
||||
<< newLine;
|
||||
}
|
||||
|
||||
void ProjectSaver::writePluginDefines (MemoryOutputStream& out) const
|
||||
{
|
||||
const auto pluginDefines = getAudioPluginDefines();
|
||||
|
||||
if (pluginDefines.isEmpty())
|
||||
return;
|
||||
|
||||
writeAutoGenWarningComment (out);
|
||||
out << "*/" << newLine << newLine
|
||||
<< "#pragma once" << newLine << newLine
|
||||
<< pluginDefines << newLine;
|
||||
}
|
||||
|
||||
void ProjectSaver::writeAppConfig (MemoryOutputStream& out, const OwnedArray<LibraryModule>& modules, const String& userContent)
|
||||
{
|
||||
if (! project.shouldUseAppConfig())
|
||||
return;
|
||||
|
||||
writeAutoGenWarningComment (out);
|
||||
|
||||
out << " There's a section below where you can add your own custom code safely, and the" << newLine
|
||||
<< " Projucer will preserve the contents of that block, but the best way to change" << newLine
|
||||
<< " any of these definitions is by using the Projucer's project settings." << newLine
|
||||
<< newLine
|
||||
<< " Any commented-out settings will assume their default values." << newLine
|
||||
<< newLine
|
||||
<< "*/" << newLine
|
||||
<< newLine;
|
||||
|
||||
out << "#pragma once" << newLine
|
||||
<< newLine
|
||||
<< "//==============================================================================" << newLine
|
||||
<< "// [BEGIN_USER_CODE_SECTION]" << newLine
|
||||
<< userContent
|
||||
<< "// [END_USER_CODE_SECTION]" << newLine;
|
||||
|
||||
if (getPluginDefinesFile().existsAsFile() && getAudioPluginDefines().isNotEmpty())
|
||||
out << newLine << CodeHelpers::createIncludeStatement (Project::getPluginDefinesFilename()) << newLine;
|
||||
|
||||
out << newLine
|
||||
<< "/*" << newLine
|
||||
<< " ==============================================================================" << newLine
|
||||
<< newLine
|
||||
<< " In accordance with the terms of the JUCE 5 End-Use License Agreement, the" << newLine
|
||||
<< " JUCE Code in SECTION A cannot be removed, changed or otherwise rendered" << newLine
|
||||
<< " ineffective unless you have a JUCE Indie or Pro license, or are using JUCE" << newLine
|
||||
<< " under the GPL v3 license." << newLine
|
||||
<< newLine
|
||||
<< " End User License Agreement: www.juce.com/juce-5-licence" << newLine
|
||||
<< newLine
|
||||
<< " ==============================================================================" << newLine
|
||||
<< "*/" << newLine
|
||||
<< newLine
|
||||
<< "// BEGIN SECTION A" << newLine
|
||||
<< newLine
|
||||
<< "#ifndef JUCE_DISPLAY_SPLASH_SCREEN" << newLine
|
||||
<< " #define JUCE_DISPLAY_SPLASH_SCREEN " << (project.shouldDisplaySplashScreen() ? "1" : "0") << newLine
|
||||
<< "#endif" << newLine << newLine
|
||||
<< "// END SECTION A" << newLine
|
||||
<< newLine
|
||||
<< "#define JUCE_USE_DARK_SPLASH_SCREEN " << (project.getSplashScreenColourString() == "Dark" ? "1" : "0") << newLine
|
||||
<< newLine
|
||||
<< "#define JUCE_PROJUCER_VERSION 0x" << String::toHexString (ProjectInfo::versionNumber) << newLine;
|
||||
|
||||
out << newLine
|
||||
<< "//==============================================================================" << newLine;
|
||||
|
||||
auto longestModuleName = [&modules]()
|
||||
{
|
||||
int longest = 0;
|
||||
|
||||
for (auto* module : modules)
|
||||
longest = jmax (longest, module->getID().length());
|
||||
|
||||
return longest;
|
||||
}();
|
||||
|
||||
for (auto* module : modules)
|
||||
{
|
||||
out << "#define JUCE_MODULE_AVAILABLE_" << module->getID()
|
||||
<< String::repeatedString (" ", longestModuleName + 5 - module->getID().length()) << " 1" << newLine;
|
||||
}
|
||||
|
||||
out << newLine << "#define JUCE_GLOBAL_MODULE_SETTINGS_INCLUDED 1" << newLine;
|
||||
|
||||
for (auto* module : modules)
|
||||
{
|
||||
OwnedArray<Project::ConfigFlag> flags;
|
||||
module->getConfigFlags (project, flags);
|
||||
|
||||
if (flags.size() > 0)
|
||||
{
|
||||
out << newLine
|
||||
<< "//==============================================================================" << newLine
|
||||
<< "// " << module->getID() << " flags:" << newLine;
|
||||
|
||||
for (auto* flag : flags)
|
||||
{
|
||||
out << newLine
|
||||
<< "#ifndef " << flag->symbol
|
||||
<< newLine
|
||||
<< (flag->value.isUsingDefault() ? " //#define " : " #define ") << flag->symbol << " " << (flag->value.get() ? "1" : "0")
|
||||
<< newLine
|
||||
<< "#endif"
|
||||
<< newLine;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
auto& type = project.getProjectType();
|
||||
auto isStandaloneApplication = (! type.isAudioPlugin() && ! type.isDynamicLibrary());
|
||||
|
||||
out << newLine
|
||||
<< "//==============================================================================" << newLine
|
||||
<< "#ifndef JUCE_STANDALONE_APPLICATION" << newLine
|
||||
<< " #if defined(JucePlugin_Name) && defined(JucePlugin_Build_Standalone)" << newLine
|
||||
<< " #define JUCE_STANDALONE_APPLICATION JucePlugin_Build_Standalone" << newLine
|
||||
<< " #else" << newLine
|
||||
<< " #define JUCE_STANDALONE_APPLICATION " << (isStandaloneApplication ? "1" : "0") << newLine
|
||||
<< " #endif" << newLine
|
||||
<< "#endif" << newLine;
|
||||
}
|
||||
|
||||
template <typename WriterCallback>
|
||||
void ProjectSaver::writeOrRemoveGeneratedFile (const String& name, WriterCallback&& writerCallback)
|
||||
{
|
||||
MemoryOutputStream mem;
|
||||
mem.setNewLineString (projectLineFeed);
|
||||
|
||||
writerCallback (mem);
|
||||
|
||||
if (mem.getDataSize() != 0)
|
||||
{
|
||||
saveGeneratedFile (name, mem);
|
||||
return;
|
||||
}
|
||||
|
||||
const auto destFile = generatedCodeFolder.getChildFile (name);
|
||||
|
||||
if (destFile.existsAsFile())
|
||||
{
|
||||
if (! destFile.deleteFile())
|
||||
addError ("Couldn't remove unnecessary file: " + destFile.getFullPathName());
|
||||
}
|
||||
}
|
||||
|
||||
void ProjectSaver::writePluginDefines()
|
||||
{
|
||||
writeOrRemoveGeneratedFile (Project::getPluginDefinesFilename(), [&] (MemoryOutputStream& mem)
|
||||
{
|
||||
writePluginDefines (mem);
|
||||
});
|
||||
}
|
||||
|
||||
void ProjectSaver::writeAppConfigFile (const OwnedArray<LibraryModule>& modules, const String& userContent)
|
||||
{
|
||||
writeOrRemoveGeneratedFile (Project::getAppConfigFilename(), [&] (MemoryOutputStream& mem)
|
||||
{
|
||||
writeAppConfig (mem, modules, userContent);
|
||||
});
|
||||
}
|
||||
|
||||
void ProjectSaver::writeAppHeader (MemoryOutputStream& out, const OwnedArray<LibraryModule>& modules)
|
||||
{
|
||||
writeAutoGenWarningComment (out);
|
||||
|
||||
out << " This is the header file that your files should include in order to get all the" << newLine
|
||||
<< " JUCE library headers. You should avoid including the JUCE headers directly in" << newLine
|
||||
<< " your own source files, because that wouldn't pick up the correct configuration" << newLine
|
||||
<< " options for your app." << newLine
|
||||
<< newLine
|
||||
<< "*/" << newLine << newLine;
|
||||
|
||||
out << "#pragma once" << newLine << newLine;
|
||||
|
||||
if (getAppConfigFile().exists() && project.shouldUseAppConfig())
|
||||
out << CodeHelpers::createIncludeStatement (Project::getAppConfigFilename()) << newLine;
|
||||
|
||||
if (modules.size() > 0)
|
||||
{
|
||||
out << newLine;
|
||||
|
||||
for (auto* module : modules)
|
||||
module->writeIncludes (*this, out);
|
||||
|
||||
out << newLine;
|
||||
}
|
||||
|
||||
if (hasBinaryData && project.shouldIncludeBinaryInJuceHeader())
|
||||
out << CodeHelpers::createIncludeStatement (project.getBinaryDataHeaderFile(), getAppConfigFile()) << newLine;
|
||||
|
||||
out << newLine
|
||||
<< "#if defined (JUCE_PROJUCER_VERSION) && JUCE_PROJUCER_VERSION < JUCE_VERSION" << newLine
|
||||
<< " /** If you've hit this error then the version of the Projucer that was used to generate this project is" << newLine
|
||||
<< " older than the version of the JUCE modules being included. To fix this error, re-save your project" << newLine
|
||||
<< " using the latest version of the Projucer or, if you aren't using the Projucer to manage your project," << newLine
|
||||
<< " remove the JUCE_PROJUCER_VERSION define from the AppConfig.h file." << newLine
|
||||
<< " */" << newLine
|
||||
<< " #error \"This project was last saved using an outdated version of the Projucer! Re-save this project with the latest version to fix this error.\"" << newLine
|
||||
<< "#endif" << newLine
|
||||
<< newLine;
|
||||
|
||||
if (project.shouldAddUsingNamespaceToJuceHeader())
|
||||
out << "#if ! DONT_SET_USING_JUCE_NAMESPACE" << newLine
|
||||
<< " // If your code uses a lot of JUCE classes, then this will obviously save you" << newLine
|
||||
<< " // a lot of typing, but can be disabled by setting DONT_SET_USING_JUCE_NAMESPACE." << newLine
|
||||
<< " using namespace juce;" << newLine
|
||||
<< "#endif" << newLine;
|
||||
|
||||
out << newLine
|
||||
<< "#if ! JUCE_DONT_DECLARE_PROJECTINFO" << newLine
|
||||
<< "namespace ProjectInfo" << newLine
|
||||
<< "{" << newLine
|
||||
<< " const char* const projectName = " << CppTokeniserFunctions::addEscapeChars (project.getProjectNameString()).quoted() << ";" << newLine
|
||||
<< " const char* const companyName = " << CppTokeniserFunctions::addEscapeChars (project.getCompanyNameString()).quoted() << ";" << newLine
|
||||
<< " const char* const versionString = " << CppTokeniserFunctions::addEscapeChars (project.getVersionString()).quoted() << ";" << newLine
|
||||
<< " const int versionNumber = " << project.getVersionAsHex() << ";" << newLine
|
||||
<< "}" << newLine
|
||||
<< "#endif" << newLine;
|
||||
}
|
||||
|
||||
void ProjectSaver::writeAppHeader (const OwnedArray<LibraryModule>& modules)
|
||||
{
|
||||
MemoryOutputStream mem;
|
||||
mem.setNewLineString (projectLineFeed);
|
||||
|
||||
writeAppHeader (mem, modules);
|
||||
saveGeneratedFile (Project::getJuceSourceHFilename(), mem);
|
||||
}
|
||||
|
||||
void ProjectSaver::writeModuleCppWrappers (const OwnedArray<LibraryModule>& modules)
|
||||
{
|
||||
for (auto* module : modules)
|
||||
{
|
||||
for (auto& cu : module->getAllCompileUnits())
|
||||
{
|
||||
MemoryOutputStream mem;
|
||||
mem.setNewLineString (projectLineFeed);
|
||||
|
||||
writeAutoGenWarningComment (mem);
|
||||
|
||||
mem << "*/" << newLine << newLine;
|
||||
|
||||
if (project.shouldUseAppConfig())
|
||||
mem << "#include " << Project::getAppConfigFilename().quoted() << newLine;
|
||||
|
||||
mem << "#include <";
|
||||
|
||||
if (cu.file.getFileExtension() != ".r") // .r files are included without the path
|
||||
mem << module->getID() << "/";
|
||||
|
||||
mem << cu.file.getFileName() << ">" << newLine;
|
||||
|
||||
replaceFileIfDifferent (generatedCodeFolder.getChildFile (cu.getFilenameForProxyFile()), mem);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ProjectSaver::writeBinaryDataFiles()
|
||||
{
|
||||
auto binaryDataH = project.getBinaryDataHeaderFile();
|
||||
|
||||
JucerResourceFile resourceFile (project);
|
||||
|
||||
if (resourceFile.getNumFiles() > 0)
|
||||
{
|
||||
auto dataNamespace = project.getBinaryDataNamespaceString().trim();
|
||||
|
||||
if (dataNamespace.isEmpty())
|
||||
dataNamespace = "BinaryData";
|
||||
|
||||
resourceFile.setClassName (dataNamespace);
|
||||
|
||||
auto maxSize = project.getMaxBinaryFileSize();
|
||||
|
||||
if (maxSize <= 0)
|
||||
maxSize = 10 * 1024 * 1024;
|
||||
|
||||
Array<File> binaryDataFiles;
|
||||
auto r = resourceFile.write (maxSize);
|
||||
|
||||
if (r.result.wasOk())
|
||||
{
|
||||
hasBinaryData = true;
|
||||
|
||||
for (auto& f : r.filesCreated)
|
||||
{
|
||||
filesCreated.add (f);
|
||||
generatedFilesGroup.addFileRetainingSortOrder (f, ! f.hasFileExtension (".h"));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
addError (r.result.getErrorMessage());
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int i = 20; --i >= 0;)
|
||||
project.getBinaryDataCppFile (i).deleteFile();
|
||||
|
||||
binaryDataH.deleteFile();
|
||||
}
|
||||
}
|
||||
|
||||
void ProjectSaver::writeReadmeFile()
|
||||
{
|
||||
MemoryOutputStream out;
|
||||
out.setNewLineString (projectLineFeed);
|
||||
|
||||
out << newLine
|
||||
<< " Important Note!!" << newLine
|
||||
<< " ================" << newLine
|
||||
<< newLine
|
||||
<< "The purpose of this folder is to contain files that are auto-generated by the Projucer," << newLine
|
||||
<< "and ALL files in this folder will be mercilessly DELETED and completely re-written whenever" << newLine
|
||||
<< "the Projucer saves your project." << newLine
|
||||
<< newLine
|
||||
<< "Therefore, it's a bad idea to make any manual changes to the files in here, or to" << newLine
|
||||
<< "put any of your own files in here if you don't want to lose them. (Of course you may choose" << newLine
|
||||
<< "to add the folder's contents to your version-control system so that you can re-merge your own" << newLine
|
||||
<< "modifications after the Projucer has saved its changes)." << newLine;
|
||||
|
||||
replaceFileIfDifferent (generatedCodeFolder.getChildFile ("ReadMe.txt"), out);
|
||||
}
|
||||
|
||||
String ProjectSaver::getAudioPluginDefines() const
|
||||
{
|
||||
const auto flags = project.getAudioPluginFlags();
|
||||
|
|
@ -47,7 +690,27 @@ String ProjectSaver::getAudioPluginDefines() const
|
|||
return mem.toString().trim();
|
||||
}
|
||||
|
||||
void ProjectSaver::writeProjects (const OwnedArray<LibraryModule>& modules, const String& specifiedExporterToSave, bool isCommandLineApp)
|
||||
void ProjectSaver::writeUnityScriptFile()
|
||||
{
|
||||
auto unityScriptContents = replaceLineFeeds (BinaryData::UnityPluginGUIScript_cs_in,
|
||||
projectLineFeed);
|
||||
|
||||
auto projectName = Project::addUnityPluginPrefixIfNecessary (project.getProjectNameString());
|
||||
|
||||
unityScriptContents = unityScriptContents.replace ("${plugin_class_name}", projectName.replace (" ", "_"))
|
||||
.replace ("${plugin_name}", projectName)
|
||||
.replace ("${plugin_vendor}", project.getPluginManufacturerString())
|
||||
.replace ("${plugin_description}", project.getPluginDescriptionString());
|
||||
|
||||
auto f = generatedCodeFolder.getChildFile (project.getUnityScriptName());
|
||||
|
||||
MemoryOutputStream out;
|
||||
out << unityScriptContents;
|
||||
|
||||
replaceFileIfDifferent (f, out);
|
||||
}
|
||||
|
||||
void ProjectSaver::writeProjects (const OwnedArray<LibraryModule>& modules, ProjectExporter* specifiedExporterToSave)
|
||||
{
|
||||
ThreadPool threadPool;
|
||||
|
||||
|
|
@ -55,24 +718,27 @@ void ProjectSaver::writeProjects (const OwnedArray<LibraryModule>& modules, cons
|
|||
auto originalGeneratedGroup = generatedFilesGroup.state.createCopy();
|
||||
|
||||
CLionProjectExporter* clionExporter = nullptr;
|
||||
OwnedArray<ProjectExporter> exporters;
|
||||
std::vector<std::unique_ptr<ProjectExporter>> exporters;
|
||||
|
||||
try
|
||||
{
|
||||
for (Project::ExporterIterator exp (project); exp.next();)
|
||||
{
|
||||
if (specifiedExporterToSave.isNotEmpty() && exp->getName() != specifiedExporterToSave)
|
||||
if (specifiedExporterToSave != nullptr && exp->getName() != specifiedExporterToSave->getName())
|
||||
continue;
|
||||
|
||||
auto exporter = exporters.add (std::move (exp.exporter));
|
||||
exporters.push_back (std::move (exp.exporter));
|
||||
}
|
||||
|
||||
for (auto& exporter : exporters)
|
||||
{
|
||||
exporter->initialiseDependencyPathValues();
|
||||
|
||||
if (exporter->getTargetFolder().createDirectory())
|
||||
{
|
||||
if (exporter->isCLion())
|
||||
{
|
||||
clionExporter = dynamic_cast<CLionProjectExporter*> (exporter);
|
||||
clionExporter = dynamic_cast<CLionProjectExporter*> (exporter.get());
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
@ -84,17 +750,17 @@ void ProjectSaver::writeProjects (const OwnedArray<LibraryModule>& modules, cons
|
|||
generatedFilesGroup.state = originalGeneratedGroup.createCopy();
|
||||
exporter->addSettingsForProjectType (project.getProjectType());
|
||||
|
||||
for (auto& module: modules)
|
||||
for (auto* module : modules)
|
||||
module->addSettingsForModuleToExporter (*exporter, *this);
|
||||
|
||||
generatedFilesGroup.sortAlphabetically (true, true);
|
||||
exporter->getAllGroups().add (generatedFilesGroup);
|
||||
}
|
||||
|
||||
if (isCommandLineApp)
|
||||
saveExporter (exporter, modules);
|
||||
if (ProjucerApplication::getApp().isRunningCommandLine)
|
||||
saveExporter (*exporter, modules);
|
||||
else
|
||||
threadPool.addJob (new ExporterJob (*this, exporter, modules), true);
|
||||
threadPool.addJob (new ExporterJob (*this, *exporter, modules), true);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
@ -107,15 +773,69 @@ void ProjectSaver::writeProjects (const OwnedArray<LibraryModule>& modules, cons
|
|||
addError (saveError.message);
|
||||
}
|
||||
|
||||
if (! isCommandLineApp)
|
||||
while (threadPool.getNumJobs() > 0)
|
||||
Thread::sleep (10);
|
||||
while (threadPool.getNumJobs() > 0)
|
||||
Thread::sleep (10);
|
||||
|
||||
if (clionExporter != nullptr)
|
||||
{
|
||||
for (auto* exporter : exporters)
|
||||
clionExporter->writeCMakeListsExporterSection (exporter);
|
||||
for (auto& exporter : exporters)
|
||||
clionExporter->writeCMakeListsExporterSection (exporter.get());
|
||||
|
||||
std::cout << "Finished saving: " << clionExporter->getName() << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
void ProjectSaver::runPostExportScript()
|
||||
{
|
||||
#if JUCE_WINDOWS
|
||||
auto cmdString = project.getPostExportShellCommandWinString();
|
||||
#else
|
||||
auto cmdString = project.getPostExportShellCommandPosixString();
|
||||
#endif
|
||||
|
||||
auto shellCommand = cmdString.replace ("%%1%%", project.getProjectFolder().getFullPathName());
|
||||
|
||||
if (shellCommand.isNotEmpty())
|
||||
{
|
||||
#if JUCE_WINDOWS
|
||||
StringArray argList ("cmd.exe", "/c");
|
||||
#else
|
||||
StringArray argList ("/bin/sh", "-c");
|
||||
#endif
|
||||
|
||||
argList.add (shellCommand);
|
||||
ChildProcess shellProcess;
|
||||
|
||||
if (! shellProcess.start (argList))
|
||||
{
|
||||
addError ("Failed to run shell command: " + argList.joinIntoString (" "));
|
||||
return;
|
||||
}
|
||||
|
||||
if (! shellProcess.waitForProcessToFinish (10000))
|
||||
{
|
||||
addError ("Timeout running shell command: " + argList.joinIntoString (" "));
|
||||
return;
|
||||
}
|
||||
|
||||
auto exitCode = shellProcess.getExitCode();
|
||||
|
||||
if (exitCode != 0)
|
||||
addError ("Shell command: " + argList.joinIntoString (" ") + " failed with exit code: " + String (exitCode));
|
||||
}
|
||||
}
|
||||
|
||||
void ProjectSaver::saveExporter (ProjectExporter& exporter, const OwnedArray<LibraryModule>& modules)
|
||||
{
|
||||
try
|
||||
{
|
||||
exporter.create (modules);
|
||||
|
||||
if (! exporter.isCLion())
|
||||
std::cout << "Finished saving: " << exporter.getName() << std::endl;
|
||||
}
|
||||
catch (build_tools::SaveError& error)
|
||||
{
|
||||
addError (error.message);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -18,809 +18,127 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include "../Application/jucer_Headers.h"
|
||||
#include "jucer_ResourceFile.h"
|
||||
#include "../Project/jucer_Module.h"
|
||||
#include "../Project/Modules/jucer_Modules.h"
|
||||
#include "jucer_ProjectExporter.h"
|
||||
|
||||
//==============================================================================
|
||||
class ProjectSaver
|
||||
{
|
||||
public:
|
||||
ProjectSaver (Project& p, const File& file)
|
||||
: project (p),
|
||||
projectFile (file),
|
||||
generatedCodeFolder (project.getGeneratedCodeFolder()),
|
||||
generatedFilesGroup (Project::Item::createGroup (project, getJuceCodeGroupName(), "__generatedcode__", true))
|
||||
{
|
||||
generatedFilesGroup.setID (getGeneratedGroupID());
|
||||
}
|
||||
ProjectSaver (Project& projectToSave);
|
||||
|
||||
struct SaveThread : public ThreadWithProgressWindow
|
||||
Result save (ProjectExporter* exporterToSave = nullptr);
|
||||
Result saveResourcesOnly();
|
||||
void saveBasicProjectItems (const OwnedArray<LibraryModule>& modules, const String& appConfigUserContent);
|
||||
Result saveContentNeededForLiveBuild();
|
||||
|
||||
Project& getProject() { return project; }
|
||||
|
||||
Project::Item addFileToGeneratedGroup (const File& file);
|
||||
bool copyFolder (const File& source, const File& dest);
|
||||
|
||||
static String getJuceCodeGroupName() { return "JUCE Library Code"; }
|
||||
|
||||
private:
|
||||
//==============================================================================
|
||||
struct SaveThreadWithProgressWindow : public ThreadWithProgressWindow
|
||||
{
|
||||
public:
|
||||
SaveThread (ProjectSaver& ps, bool wait, const String& exp)
|
||||
SaveThreadWithProgressWindow (ProjectSaver& ps, ProjectExporter* exporterToSave)
|
||||
: ThreadWithProgressWindow ("Saving...", true, false),
|
||||
saver (ps),
|
||||
shouldWaitAfterSaving (wait),
|
||||
specifiedExporterToSave (exp)
|
||||
specifiedExporterToSave (exporterToSave)
|
||||
{}
|
||||
|
||||
void run() override
|
||||
{
|
||||
setProgress (-1);
|
||||
result = saver.save (false, shouldWaitAfterSaving, specifiedExporterToSave);
|
||||
result = saver.saveProject (specifiedExporterToSave);
|
||||
}
|
||||
|
||||
ProjectSaver& saver;
|
||||
Result result = Result::ok();
|
||||
bool shouldWaitAfterSaving;
|
||||
String specifiedExporterToSave;
|
||||
ProjectExporter* specifiedExporterToSave;
|
||||
|
||||
JUCE_DECLARE_NON_COPYABLE (SaveThread)
|
||||
JUCE_DECLARE_NON_COPYABLE (SaveThreadWithProgressWindow)
|
||||
};
|
||||
|
||||
Result save (bool showProgressBox, bool waitAfterSaving, const String& specifiedExporterToSave)
|
||||
{
|
||||
if (showProgressBox)
|
||||
{
|
||||
SaveThread thread (*this, waitAfterSaving, specifiedExporterToSave);
|
||||
thread.runThread();
|
||||
return thread.result;
|
||||
}
|
||||
|
||||
projectLineFeed = project.getProjectLineFeed();
|
||||
|
||||
auto appConfigUserContent = loadUserContentFromAppConfig();
|
||||
|
||||
auto oldFile = project.getFile();
|
||||
project.setFile (projectFile);
|
||||
|
||||
OwnedArray<LibraryModule> modules;
|
||||
project.getEnabledModules().createRequiredModules (modules);
|
||||
|
||||
checkModuleValidity (modules);
|
||||
|
||||
if (errors.size() == 0)
|
||||
{
|
||||
writeMainProjectFile();
|
||||
project.updateModificationTime();
|
||||
|
||||
auto projectRootHash = project.getProjectRoot().toXmlString().hashCode();
|
||||
|
||||
if (project.isAudioPluginProject())
|
||||
{
|
||||
if (project.shouldBuildUnityPlugin())
|
||||
writeUnityScriptFile();
|
||||
}
|
||||
|
||||
saveBasicProjectItems (modules, appConfigUserContent);
|
||||
writeProjects (modules, specifiedExporterToSave, ! showProgressBox);
|
||||
runPostExportScript();
|
||||
|
||||
// if the project root has changed after writing the other files then re-save it
|
||||
if (project.getProjectRoot().toXmlString().hashCode() != projectRootHash)
|
||||
{
|
||||
writeMainProjectFile();
|
||||
project.updateModificationTime();
|
||||
}
|
||||
|
||||
if (generatedCodeFolder.exists())
|
||||
{
|
||||
writeReadmeFile();
|
||||
deleteUnwantedFilesIn (generatedCodeFolder);
|
||||
}
|
||||
|
||||
if (errors.size() == 0)
|
||||
{
|
||||
// Workaround for a bug where Xcode thinks the project is invalid if opened immediately
|
||||
// after writing
|
||||
if (waitAfterSaving)
|
||||
Thread::sleep (2000);
|
||||
|
||||
return Result::ok();
|
||||
}
|
||||
}
|
||||
|
||||
project.setFile (oldFile);
|
||||
return Result::fail (errors[0]);
|
||||
}
|
||||
|
||||
Result saveResourcesOnly()
|
||||
{
|
||||
writeBinaryDataFiles();
|
||||
|
||||
if (errors.size() > 0)
|
||||
return Result::fail (errors[0]);
|
||||
|
||||
return Result::ok();
|
||||
}
|
||||
|
||||
void saveBasicProjectItems (const OwnedArray<LibraryModule>& modules, const String& appConfigUserContent)
|
||||
{
|
||||
writePluginDefines();
|
||||
writeAppConfigFile (modules, appConfigUserContent);
|
||||
writeBinaryDataFiles();
|
||||
writeAppHeader (modules);
|
||||
writeModuleCppWrappers (modules);
|
||||
}
|
||||
|
||||
Result saveContentNeededForLiveBuild()
|
||||
{
|
||||
OwnedArray<LibraryModule> modules;
|
||||
project.getEnabledModules().createRequiredModules (modules);
|
||||
|
||||
checkModuleValidity (modules);
|
||||
|
||||
if (errors.size() == 0)
|
||||
{
|
||||
saveBasicProjectItems (modules, loadUserContentFromAppConfig());
|
||||
|
||||
return Result::ok();
|
||||
}
|
||||
|
||||
return Result::fail (errors[0]);
|
||||
}
|
||||
|
||||
Project::Item saveGeneratedFile (const String& filePath, const MemoryOutputStream& newData)
|
||||
{
|
||||
if (! generatedCodeFolder.createDirectory())
|
||||
{
|
||||
addError ("Couldn't create folder: " + generatedCodeFolder.getFullPathName());
|
||||
return Project::Item (project, ValueTree(), false);
|
||||
}
|
||||
|
||||
auto file = generatedCodeFolder.getChildFile (filePath);
|
||||
|
||||
if (replaceFileIfDifferent (file, newData))
|
||||
return addFileToGeneratedGroup (file);
|
||||
|
||||
return { project, {}, true };
|
||||
}
|
||||
|
||||
Project::Item addFileToGeneratedGroup (const File& file)
|
||||
{
|
||||
auto item = generatedFilesGroup.findItemForFile (file);
|
||||
|
||||
if (item.isValid())
|
||||
return item;
|
||||
|
||||
generatedFilesGroup.addFileAtIndex (file, -1, true);
|
||||
return generatedFilesGroup.findItemForFile (file);
|
||||
}
|
||||
|
||||
static void writeAutoGenWarningComment (OutputStream& out)
|
||||
{
|
||||
out << "/*" << newLine << newLine
|
||||
<< " IMPORTANT! This file is auto-generated each time you save your" << newLine
|
||||
<< " project - if you alter its contents, your changes may be overwritten!" << newLine
|
||||
<< newLine;
|
||||
}
|
||||
|
||||
static const char* getGeneratedGroupID() noexcept { return "__jucelibfiles"; }
|
||||
Project::Item& getGeneratedCodeGroup() { return generatedFilesGroup; }
|
||||
|
||||
static String getJuceCodeGroupName() { return "JUCE Library Code"; }
|
||||
|
||||
File getGeneratedCodeFolder() const { return generatedCodeFolder; }
|
||||
|
||||
bool replaceFileIfDifferent (const File& f, const MemoryOutputStream& newData)
|
||||
{
|
||||
filesCreated.add (f);
|
||||
|
||||
if (!build_tools::overwriteFileWithNewDataIfDifferent (f, newData))
|
||||
{
|
||||
addError ("Can't write to file: " + f.getFullPathName());
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool shouldFolderBeIgnoredWhenCopying (const File& f)
|
||||
{
|
||||
return f.getFileName() == ".git" || f.getFileName() == ".svn" || f.getFileName() == ".cvs";
|
||||
}
|
||||
|
||||
bool copyFolder (const File& source, const File& dest)
|
||||
{
|
||||
if (source.isDirectory() && dest.createDirectory())
|
||||
{
|
||||
for (auto& f : source.findChildFiles (File::findFiles, false))
|
||||
{
|
||||
auto target = dest.getChildFile (f.getFileName());
|
||||
filesCreated.add (target);
|
||||
|
||||
if (! f.copyFileTo (target))
|
||||
return false;
|
||||
}
|
||||
|
||||
for (auto& f : source.findChildFiles (File::findDirectories, false))
|
||||
if (! shouldFolderBeIgnoredWhenCopying (f))
|
||||
if (! copyFolder (f, dest.getChildFile (f.getFileName())))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
Project& project;
|
||||
SortedSet<File> filesCreated;
|
||||
|
||||
private:
|
||||
const File projectFile, generatedCodeFolder;
|
||||
Project::Item generatedFilesGroup;
|
||||
StringArray errors;
|
||||
CriticalSection errorLock;
|
||||
|
||||
bool hasBinaryData = false;
|
||||
String projectLineFeed = "\r\n";
|
||||
|
||||
// Recursively clears out any files in a folder that we didn't create, but avoids
|
||||
// any folders containing hidden files that might be used by version-control systems.
|
||||
bool deleteUnwantedFilesIn (const File& parent)
|
||||
{
|
||||
bool folderIsNowEmpty = true;
|
||||
Array<File> filesToDelete;
|
||||
|
||||
for (const auto& i : RangedDirectoryIterator (parent, false, "*", File::findFilesAndDirectories))
|
||||
{
|
||||
auto f = i.getFile();
|
||||
|
||||
if (filesCreated.contains (f) || shouldFileBeKept (f.getFileName()))
|
||||
{
|
||||
folderIsNowEmpty = false;
|
||||
}
|
||||
else if (i.isDirectory())
|
||||
{
|
||||
if (deleteUnwantedFilesIn (f))
|
||||
filesToDelete.add (f);
|
||||
else
|
||||
folderIsNowEmpty = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
filesToDelete.add (f);
|
||||
}
|
||||
}
|
||||
|
||||
for (int j = filesToDelete.size(); --j >= 0;)
|
||||
filesToDelete.getReference(j).deleteRecursively();
|
||||
|
||||
return folderIsNowEmpty;
|
||||
}
|
||||
|
||||
static bool shouldFileBeKept (const String& filename)
|
||||
{
|
||||
static const char* filesToKeep[] = { ".svn", ".cvs", "CMakeLists.txt" };
|
||||
|
||||
for (auto* f : filesToKeep)
|
||||
if (filename == f)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void writeMainProjectFile()
|
||||
{
|
||||
if (auto xml = project.getProjectRoot().createXml())
|
||||
{
|
||||
XmlElement::TextFormat format;
|
||||
format.newLineChars = projectLineFeed.toRawUTF8();
|
||||
|
||||
MemoryOutputStream mo (8192);
|
||||
xml->writeTo (mo, format);
|
||||
replaceFileIfDifferent (projectFile, mo);
|
||||
}
|
||||
else
|
||||
{
|
||||
jassertfalse;
|
||||
}
|
||||
}
|
||||
|
||||
static int findLongestModuleName (const OwnedArray<LibraryModule>& modules)
|
||||
{
|
||||
int longest = 0;
|
||||
|
||||
for (auto& m : modules)
|
||||
longest = jmax (longest, m->getID().length());
|
||||
|
||||
return longest;
|
||||
}
|
||||
|
||||
File getAppConfigFile() const { return generatedCodeFolder.getChildFile (Project::getAppConfigFilename()); }
|
||||
File getPluginDefinesFile() const { return generatedCodeFolder.getChildFile (Project::getPluginDefinesFilename()); }
|
||||
|
||||
String loadUserContentFromAppConfig() const
|
||||
{
|
||||
StringArray userContent;
|
||||
bool foundCodeSection = false;
|
||||
auto lines = StringArray::fromLines (getAppConfigFile().loadFileAsString());
|
||||
|
||||
for (int i = 0; i < lines.size(); ++i)
|
||||
{
|
||||
if (lines[i].contains ("[BEGIN_USER_CODE_SECTION]"))
|
||||
{
|
||||
for (int j = i + 1; j < lines.size() && ! lines[j].contains ("[END_USER_CODE_SECTION]"); ++j)
|
||||
userContent.add (lines[j]);
|
||||
|
||||
foundCodeSection = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (! foundCodeSection)
|
||||
{
|
||||
userContent.add ({});
|
||||
userContent.add ("// (You can add your own code in this section, and the Projucer will not overwrite it)");
|
||||
userContent.add ({});
|
||||
}
|
||||
|
||||
return userContent.joinIntoString (projectLineFeed) + projectLineFeed;
|
||||
}
|
||||
|
||||
void checkModuleValidity (OwnedArray<LibraryModule>& modules)
|
||||
{
|
||||
if (project.getNumExporters() == 0)
|
||||
{
|
||||
addError ("No exporters found!\n"
|
||||
"Please add an exporter before saving.");
|
||||
return;
|
||||
}
|
||||
|
||||
for (auto moduleIter = modules.begin(); moduleIter != modules.end(); ++moduleIter)
|
||||
{
|
||||
if (auto* module = *moduleIter)
|
||||
{
|
||||
if (! module->isValid())
|
||||
{
|
||||
addError ("At least one of your JUCE module paths is invalid!\n"
|
||||
"Please go to the Modules settings page and ensure each path points to the correct JUCE modules folder.");
|
||||
return;
|
||||
}
|
||||
|
||||
if (project.getEnabledModules().getExtraDependenciesNeeded (module->getID()).size() > 0)
|
||||
{
|
||||
addError ("At least one of your modules has missing dependencies!\n"
|
||||
"Please go to the settings page of the highlighted modules and add the required dependencies.");
|
||||
return;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// this should never happen!
|
||||
jassertfalse;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void writePluginDefines (MemoryOutputStream& out) const
|
||||
{
|
||||
const auto pluginDefines = getAudioPluginDefines();
|
||||
|
||||
if (pluginDefines.isEmpty())
|
||||
return;
|
||||
|
||||
writeAutoGenWarningComment (out);
|
||||
out << "*/" << newLine << newLine
|
||||
<< "#pragma once" << newLine << newLine
|
||||
<< pluginDefines << newLine;
|
||||
}
|
||||
|
||||
void writeAppConfig (MemoryOutputStream& out, const OwnedArray<LibraryModule>& modules, const String& userContent)
|
||||
{
|
||||
if (! project.shouldUseAppConfig())
|
||||
return;
|
||||
|
||||
writeAutoGenWarningComment (out);
|
||||
out << " There's a section below where you can add your own custom code safely, and the" << newLine
|
||||
<< " Projucer will preserve the contents of that block, but the best way to change" << newLine
|
||||
<< " any of these definitions is by using the Projucer's project settings." << newLine
|
||||
<< newLine
|
||||
<< " Any commented-out settings will assume their default values." << newLine
|
||||
<< newLine
|
||||
<< "*/" << newLine
|
||||
<< newLine;
|
||||
|
||||
out << "#pragma once" << newLine
|
||||
<< newLine
|
||||
<< "//==============================================================================" << newLine
|
||||
<< "// [BEGIN_USER_CODE_SECTION]" << newLine
|
||||
<< userContent
|
||||
<< "// [END_USER_CODE_SECTION]" << newLine;
|
||||
|
||||
if (getPluginDefinesFile().existsAsFile() && getAudioPluginDefines().isNotEmpty())
|
||||
out << newLine << CodeHelpers::createIncludeStatement (Project::getPluginDefinesFilename()) << newLine;
|
||||
|
||||
out << newLine
|
||||
<< "/*" << newLine
|
||||
<< " ==============================================================================" << newLine
|
||||
<< newLine
|
||||
<< " In accordance with the terms of the JUCE 5 End-Use License Agreement, the" << newLine
|
||||
<< " JUCE Code in SECTION A cannot be removed, changed or otherwise rendered" << newLine
|
||||
<< " ineffective unless you have a JUCE Indie or Pro license, or are using JUCE" << newLine
|
||||
<< " under the GPL v3 license." << newLine
|
||||
<< newLine
|
||||
<< " End User License Agreement: www.juce.com/juce-5-licence" << newLine
|
||||
<< newLine
|
||||
<< " ==============================================================================" << newLine
|
||||
<< "*/" << newLine
|
||||
<< newLine
|
||||
<< "// BEGIN SECTION A" << newLine
|
||||
<< newLine
|
||||
<< "#ifndef JUCE_DISPLAY_SPLASH_SCREEN" << newLine
|
||||
<< " #define JUCE_DISPLAY_SPLASH_SCREEN " << (project.shouldDisplaySplashScreen() ? "1" : "0") << newLine
|
||||
<< "#endif" << newLine << newLine
|
||||
<< "// END SECTION A" << newLine
|
||||
<< newLine
|
||||
<< "#define JUCE_USE_DARK_SPLASH_SCREEN " << (project.getSplashScreenColourString() == "Dark" ? "1" : "0") << newLine
|
||||
<< newLine
|
||||
<< "#define JUCE_PROJUCER_VERSION 0x" << String::toHexString (ProjectInfo::versionNumber) << newLine;
|
||||
|
||||
out << newLine
|
||||
<< "//==============================================================================" << newLine;
|
||||
|
||||
auto longestName = findLongestModuleName (modules);
|
||||
|
||||
for (auto& m : modules)
|
||||
out << "#define JUCE_MODULE_AVAILABLE_" << m->getID()
|
||||
<< String::repeatedString (" ", longestName + 5 - m->getID().length()) << " 1" << newLine;
|
||||
|
||||
out << newLine << "#define JUCE_GLOBAL_MODULE_SETTINGS_INCLUDED 1" << newLine;
|
||||
|
||||
for (auto& m : modules)
|
||||
{
|
||||
OwnedArray<Project::ConfigFlag> flags;
|
||||
m->getConfigFlags (project, flags);
|
||||
|
||||
if (flags.size() > 0)
|
||||
{
|
||||
out << newLine
|
||||
<< "//==============================================================================" << newLine
|
||||
<< "// " << m->getID() << " flags:" << newLine;
|
||||
|
||||
for (auto* flag : flags)
|
||||
{
|
||||
out << newLine
|
||||
<< "#ifndef " << flag->symbol
|
||||
<< newLine
|
||||
<< (flag->value.isUsingDefault() ? " //#define " : " #define ") << flag->symbol << " " << (flag->value.get() ? "1" : "0")
|
||||
<< newLine
|
||||
<< "#endif"
|
||||
<< newLine;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
auto& type = project.getProjectType();
|
||||
|
||||
auto isStandaloneApplication = (! type.isAudioPlugin() && ! type.isDynamicLibrary());
|
||||
|
||||
out << newLine
|
||||
<< "//==============================================================================" << newLine
|
||||
<< "#ifndef JUCE_STANDALONE_APPLICATION" << newLine
|
||||
<< " #if defined(JucePlugin_Name) && defined(JucePlugin_Build_Standalone)" << newLine
|
||||
<< " #define JUCE_STANDALONE_APPLICATION JucePlugin_Build_Standalone" << newLine
|
||||
<< " #else" << newLine
|
||||
<< " #define JUCE_STANDALONE_APPLICATION " << (isStandaloneApplication ? "1" : "0") << newLine
|
||||
<< " #endif" << newLine
|
||||
<< "#endif" << newLine;
|
||||
}
|
||||
}
|
||||
|
||||
template <typename WriterCallback>
|
||||
void writeOrRemoveGeneratedFile (const String& name, WriterCallback&& writerCallback)
|
||||
{
|
||||
MemoryOutputStream mem;
|
||||
mem.setNewLineString (projectLineFeed);
|
||||
|
||||
writerCallback (mem);
|
||||
|
||||
if (mem.getDataSize() != 0)
|
||||
{
|
||||
saveGeneratedFile (name, mem);
|
||||
return;
|
||||
}
|
||||
|
||||
const auto destFile = generatedCodeFolder.getChildFile (name);
|
||||
|
||||
if (destFile.existsAsFile())
|
||||
{
|
||||
if (! destFile.deleteFile())
|
||||
addError ("Couldn't remove unnecessary file: " + destFile.getFullPathName());
|
||||
}
|
||||
}
|
||||
|
||||
void writePluginDefines()
|
||||
{
|
||||
writeOrRemoveGeneratedFile (Project::getPluginDefinesFilename(), [&] (MemoryOutputStream& mem)
|
||||
{
|
||||
writePluginDefines (mem);
|
||||
});
|
||||
}
|
||||
|
||||
void writeAppConfigFile (const OwnedArray<LibraryModule>& modules, const String& userContent)
|
||||
{
|
||||
writeOrRemoveGeneratedFile (Project::getAppConfigFilename(), [&] (MemoryOutputStream& mem)
|
||||
{
|
||||
writeAppConfig (mem, modules, userContent);
|
||||
});
|
||||
}
|
||||
|
||||
void writeAppHeader (MemoryOutputStream& out, const OwnedArray<LibraryModule>& modules)
|
||||
{
|
||||
writeAutoGenWarningComment (out);
|
||||
|
||||
out << " This is the header file that your files should include in order to get all the" << newLine
|
||||
<< " JUCE library headers. You should avoid including the JUCE headers directly in" << newLine
|
||||
<< " your own source files, because that wouldn't pick up the correct configuration" << newLine
|
||||
<< " options for your app." << newLine
|
||||
<< newLine
|
||||
<< "*/" << newLine << newLine;
|
||||
|
||||
out << "#pragma once" << newLine << newLine;
|
||||
|
||||
if (getAppConfigFile().exists() && project.shouldUseAppConfig())
|
||||
out << CodeHelpers::createIncludeStatement (Project::getAppConfigFilename()) << newLine;
|
||||
|
||||
if (modules.size() > 0)
|
||||
{
|
||||
out << newLine;
|
||||
|
||||
for (int i = 0; i < modules.size(); ++i)
|
||||
modules.getUnchecked(i)->writeIncludes (*this, out);
|
||||
|
||||
out << newLine;
|
||||
}
|
||||
|
||||
if (hasBinaryData && project.shouldIncludeBinaryInJuceHeader())
|
||||
out << CodeHelpers::createIncludeStatement (project.getBinaryDataHeaderFile(), getAppConfigFile()) << newLine;
|
||||
|
||||
out << newLine
|
||||
<< "#if defined (JUCE_PROJUCER_VERSION) && JUCE_PROJUCER_VERSION < JUCE_VERSION" << newLine
|
||||
<< " /** If you've hit this error then the version of the Projucer that was used to generate this project is" << newLine
|
||||
<< " older than the version of the JUCE modules being included. To fix this error, re-save your project" << newLine
|
||||
<< " using the latest version of the Projucer or, if you aren't using the Projucer to manage your project," << newLine
|
||||
<< " remove the JUCE_PROJUCER_VERSION define from the AppConfig.h file." << newLine
|
||||
<< " */" << newLine
|
||||
<< " #error \"This project was last saved using an outdated version of the Projucer! Re-save this project with the latest version to fix this error.\"" << newLine
|
||||
<< "#endif" << newLine
|
||||
<< newLine;
|
||||
|
||||
if (project.shouldAddUsingNamespaceToJuceHeader())
|
||||
out << "#if ! DONT_SET_USING_JUCE_NAMESPACE" << newLine
|
||||
<< " // If your code uses a lot of JUCE classes, then this will obviously save you" << newLine
|
||||
<< " // a lot of typing, but can be disabled by setting DONT_SET_USING_JUCE_NAMESPACE." << newLine
|
||||
<< " using namespace juce;" << newLine
|
||||
<< "#endif" << newLine
|
||||
<< newLine;
|
||||
|
||||
out << "#if ! JUCE_DONT_DECLARE_PROJECTINFO" << newLine
|
||||
<< "namespace ProjectInfo" << newLine
|
||||
<< "{" << newLine
|
||||
<< " const char* const projectName = " << CppTokeniserFunctions::addEscapeChars (project.getProjectNameString()).quoted() << ";" << newLine
|
||||
<< " const char* const companyName = " << CppTokeniserFunctions::addEscapeChars (project.getCompanyNameString()).quoted() << ";" << newLine
|
||||
<< " const char* const versionString = " << CppTokeniserFunctions::addEscapeChars (project.getVersionString()).quoted() << ";" << newLine
|
||||
<< " const int versionNumber = " << project.getVersionAsHex() << ";" << newLine
|
||||
<< "}" << newLine
|
||||
<< "#endif" << newLine;
|
||||
}
|
||||
|
||||
void writeAppHeader (const OwnedArray<LibraryModule>& modules)
|
||||
{
|
||||
MemoryOutputStream mem;
|
||||
mem.setNewLineString (projectLineFeed);
|
||||
|
||||
writeAppHeader (mem, modules);
|
||||
saveGeneratedFile (Project::getJuceSourceHFilename(), mem);
|
||||
}
|
||||
|
||||
void writeModuleCppWrappers (const OwnedArray<LibraryModule>& modules)
|
||||
{
|
||||
for (auto* module : modules)
|
||||
{
|
||||
for (auto& cu : module->getAllCompileUnits())
|
||||
{
|
||||
MemoryOutputStream mem;
|
||||
mem.setNewLineString (projectLineFeed);
|
||||
|
||||
writeAutoGenWarningComment (mem);
|
||||
|
||||
mem << "*/" << newLine << newLine;
|
||||
|
||||
if (project.shouldUseAppConfig())
|
||||
mem << "#include " << Project::getAppConfigFilename().quoted() << newLine;
|
||||
|
||||
mem << "#include <";
|
||||
|
||||
if (cu.file.getFileExtension() != ".r") // .r files are included without the path
|
||||
mem << module->getID() << "/";
|
||||
|
||||
mem << cu.file.getFileName() << ">" << newLine;
|
||||
|
||||
replaceFileIfDifferent (generatedCodeFolder.getChildFile (cu.getFilenameForProxyFile()), mem);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void writeBinaryDataFiles()
|
||||
{
|
||||
auto binaryDataH = project.getBinaryDataHeaderFile();
|
||||
|
||||
JucerResourceFile resourceFile (project);
|
||||
|
||||
if (resourceFile.getNumFiles() > 0)
|
||||
{
|
||||
auto dataNamespace = project.getBinaryDataNamespaceString().trim();
|
||||
|
||||
if (dataNamespace.isEmpty())
|
||||
dataNamespace = "BinaryData";
|
||||
|
||||
resourceFile.setClassName (dataNamespace);
|
||||
|
||||
auto maxSize = project.getMaxBinaryFileSize();
|
||||
|
||||
if (maxSize <= 0)
|
||||
maxSize = 10 * 1024 * 1024;
|
||||
|
||||
auto r = resourceFile.write (maxSize);
|
||||
|
||||
if (r.result.wasOk())
|
||||
{
|
||||
hasBinaryData = true;
|
||||
|
||||
for (auto& f : r.filesCreated)
|
||||
{
|
||||
filesCreated.add (f);
|
||||
generatedFilesGroup.addFileRetainingSortOrder (f, ! f.hasFileExtension (".h"));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
addError (r.result.getErrorMessage());
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int i = 20; --i >= 0;)
|
||||
project.getBinaryDataCppFile (i).deleteFile();
|
||||
|
||||
binaryDataH.deleteFile();
|
||||
}
|
||||
}
|
||||
|
||||
void writeReadmeFile()
|
||||
{
|
||||
MemoryOutputStream out;
|
||||
out.setNewLineString (projectLineFeed);
|
||||
|
||||
out << newLine
|
||||
<< " Important Note!!" << newLine
|
||||
<< " ================" << newLine
|
||||
<< newLine
|
||||
<< "The purpose of this folder is to contain files that are auto-generated by the Projucer," << newLine
|
||||
<< "and ALL files in this folder will be mercilessly DELETED and completely re-written whenever" << newLine
|
||||
<< "the Projucer saves your project." << newLine
|
||||
<< newLine
|
||||
<< "Therefore, it's a bad idea to make any manual changes to the files in here, or to" << newLine
|
||||
<< "put any of your own files in here if you don't want to lose them. (Of course you may choose" << newLine
|
||||
<< "to add the folder's contents to your version-control system so that you can re-merge your own" << newLine
|
||||
<< "modifications after the Projucer has saved its changes)." << newLine;
|
||||
|
||||
replaceFileIfDifferent (generatedCodeFolder.getChildFile ("ReadMe.txt"), out);
|
||||
}
|
||||
|
||||
void addError (const String& message)
|
||||
{
|
||||
const ScopedLock sl (errorLock);
|
||||
errors.add (message);
|
||||
}
|
||||
|
||||
String getAudioPluginDefines() const;
|
||||
|
||||
void writeUnityScriptFile()
|
||||
{
|
||||
auto unityScriptContents = replaceLineFeeds (BinaryData::UnityPluginGUIScript_cs_in,
|
||||
projectLineFeed);
|
||||
|
||||
auto projectName = Project::addUnityPluginPrefixIfNecessary (project.getProjectNameString());
|
||||
|
||||
unityScriptContents = unityScriptContents.replace ("${plugin_class_name}", projectName.replace (" ", "_"))
|
||||
.replace ("${plugin_name}", projectName)
|
||||
.replace ("${plugin_vendor}", project.getPluginManufacturerString())
|
||||
.replace ("${plugin_description}", project.getPluginDescriptionString());
|
||||
|
||||
auto f = getGeneratedCodeFolder().getChildFile (project.getUnityScriptName());
|
||||
|
||||
MemoryOutputStream out;
|
||||
out << unityScriptContents;
|
||||
|
||||
replaceFileIfDifferent (f, out);
|
||||
}
|
||||
|
||||
void writeProjects (const OwnedArray<LibraryModule>&, const String&, bool);
|
||||
|
||||
void runPostExportScript()
|
||||
{
|
||||
#if JUCE_WINDOWS
|
||||
auto cmdString = project.getPostExportShellCommandWinString();
|
||||
#else
|
||||
auto cmdString = project.getPostExportShellCommandPosixString();
|
||||
#endif
|
||||
|
||||
auto shellCommand = cmdString.replace ("%%1%%", project.getProjectFolder().getFullPathName());
|
||||
|
||||
if (shellCommand.isNotEmpty())
|
||||
{
|
||||
#if JUCE_WINDOWS
|
||||
StringArray argList ("cmd.exe", "/c");
|
||||
#else
|
||||
StringArray argList ("/bin/sh", "-c");
|
||||
#endif
|
||||
|
||||
argList.add (shellCommand);
|
||||
ChildProcess shellProcess;
|
||||
|
||||
if (! shellProcess.start (argList))
|
||||
{
|
||||
addError ("Failed to run shell command: " + argList.joinIntoString (" "));
|
||||
return;
|
||||
}
|
||||
|
||||
if (! shellProcess.waitForProcessToFinish (10000))
|
||||
{
|
||||
addError ("Timeout running shell command: " + argList.joinIntoString (" "));
|
||||
return;
|
||||
}
|
||||
|
||||
auto exitCode = shellProcess.getExitCode();
|
||||
|
||||
if (exitCode != 0)
|
||||
addError ("Shell command: " + argList.joinIntoString (" ") + " failed with exit code: " + String (exitCode));
|
||||
}
|
||||
}
|
||||
|
||||
void saveExporter (ProjectExporter* exporter, const OwnedArray<LibraryModule>& modules)
|
||||
{
|
||||
try
|
||||
{
|
||||
exporter->create (modules);
|
||||
|
||||
if (! exporter->isCLion())
|
||||
std::cout << "Finished saving: " << exporter->getName() << std::endl;
|
||||
}
|
||||
catch (build_tools::SaveError& error)
|
||||
{
|
||||
addError (error.message);
|
||||
}
|
||||
}
|
||||
|
||||
class ExporterJob : public ThreadPoolJob
|
||||
{
|
||||
public:
|
||||
ExporterJob (ProjectSaver& ps, ProjectExporter* pe,
|
||||
const OwnedArray<LibraryModule>& moduleList)
|
||||
: ThreadPoolJob ("export"),
|
||||
owner (ps), exporter (pe), modules (moduleList)
|
||||
{
|
||||
}
|
||||
ExporterJob (ProjectSaver& ps, ProjectExporter& pe, const OwnedArray<LibraryModule>& modulesList)
|
||||
: ThreadPoolJob ("export"),
|
||||
owner (ps),
|
||||
exporter (pe),
|
||||
modules (modulesList)
|
||||
{
|
||||
}
|
||||
|
||||
JobStatus runJob() override
|
||||
{
|
||||
owner.saveExporter (exporter.get(), modules);
|
||||
return jobHasFinished;
|
||||
}
|
||||
JobStatus runJob() override
|
||||
{
|
||||
owner.saveExporter (exporter, modules);
|
||||
return jobHasFinished;
|
||||
}
|
||||
|
||||
private:
|
||||
ProjectSaver& owner;
|
||||
std::unique_ptr<ProjectExporter> exporter;
|
||||
const OwnedArray<LibraryModule>& modules;
|
||||
ProjectSaver& owner;
|
||||
ProjectExporter& exporter;
|
||||
const OwnedArray<LibraryModule>& modules;
|
||||
|
||||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (ExporterJob)
|
||||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (ExporterJob)
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
Project::Item saveGeneratedFile (const String& filePath, const MemoryOutputStream& newData);
|
||||
bool replaceFileIfDifferent (const File& f, const MemoryOutputStream& newData);
|
||||
bool deleteUnwantedFilesIn (const File& parent);
|
||||
|
||||
void addError (const String& message);
|
||||
|
||||
File getAppConfigFile() const;
|
||||
File getPluginDefinesFile() const;
|
||||
|
||||
String loadUserContentFromAppConfig() const;
|
||||
String getAudioPluginDefines() const;
|
||||
OwnedArray<LibraryModule> getModules();
|
||||
|
||||
Result saveProject (ProjectExporter* specifiedExporterToSave);
|
||||
|
||||
template <typename WriterCallback>
|
||||
void writeOrRemoveGeneratedFile (const String& name, WriterCallback&& writerCallback);
|
||||
|
||||
void writePluginDefines (MemoryOutputStream& outStream) const;
|
||||
void writePluginDefines();
|
||||
void writeAppConfigFile (const OwnedArray<LibraryModule>& modules, const String& userContent);
|
||||
|
||||
void writeMainProjectFile();
|
||||
void writeAppConfig (MemoryOutputStream& outStream, const OwnedArray<LibraryModule>& modules, const String& userContent);
|
||||
void writeAppHeader (MemoryOutputStream& outStream, const OwnedArray<LibraryModule>& modules);
|
||||
void writeAppHeader (const OwnedArray<LibraryModule>& modules);
|
||||
void writeModuleCppWrappers (const OwnedArray<LibraryModule>& modules);
|
||||
void writeBinaryDataFiles();
|
||||
void writeReadmeFile();
|
||||
void writePluginCharacteristicsFile();
|
||||
void writeUnityScriptFile();
|
||||
void writeProjects (const OwnedArray<LibraryModule>&, ProjectExporter*);
|
||||
void runPostExportScript();
|
||||
void saveExporter (ProjectExporter& exporter, const OwnedArray<LibraryModule>& modules);
|
||||
|
||||
//==============================================================================
|
||||
Project& project;
|
||||
|
||||
File generatedCodeFolder;
|
||||
Project::Item generatedFilesGroup;
|
||||
SortedSet<File> filesCreated;
|
||||
String projectLineFeed;
|
||||
|
||||
CriticalSection errorLock;
|
||||
StringArray errors;
|
||||
|
||||
bool hasBinaryData = false;
|
||||
|
||||
//==============================================================================
|
||||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (ProjectSaver)
|
||||
};
|
||||
|
|
|
|||
|
|
@ -350,18 +350,9 @@ void StoredSettings::checkJUCEPaths()
|
|||
projectDefaults.getPropertyAsValue (Ids::defaultJuceModulePath, nullptr) = File (juceFolder).getChildFile ("modules").getFullPathName();
|
||||
}
|
||||
|
||||
bool StoredSettings::shouldAskUserToSetJUCEPath() noexcept
|
||||
bool StoredSettings::isJUCEPathIncorrect()
|
||||
{
|
||||
if (! isGlobalPathValid ({}, Ids::jucePath, getStoredPath (Ids::jucePath, TargetOS::getThisOS()).get().toString())
|
||||
&& getGlobalProperties().getValue ("dontAskAboutJUCEPath", {}).isEmpty())
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void StoredSettings::setDontAskAboutJUCEPathAgain() noexcept
|
||||
{
|
||||
getGlobalProperties().setValue ("dontAskAboutJUCEPath", 1);
|
||||
return ! isGlobalPathValid ({}, Ids::jucePath, getStoredPath (Ids::jucePath, TargetOS::getThisOS()).get().toString());
|
||||
}
|
||||
|
||||
static String getFallbackPathForOS (const Identifier& key, DependencyPathOS os)
|
||||
|
|
|
|||
|
|
@ -55,9 +55,7 @@ public:
|
|||
|
||||
//==============================================================================
|
||||
ValueWithDefault getStoredPath (const Identifier& key, DependencyPathOS os);
|
||||
|
||||
bool shouldAskUserToSetJUCEPath() noexcept;
|
||||
void setDontAskAboutJUCEPathAgain() noexcept;
|
||||
bool isJUCEPathIncorrect();
|
||||
|
||||
//==============================================================================
|
||||
AppearanceSettings appearance;
|
||||
|
|
|
|||
|
|
@ -23,7 +23,7 @@
|
|||
// Handy list of static Identifiers..
|
||||
namespace Ids
|
||||
{
|
||||
#define DECLARE_ID(name) const Identifier name (#name)
|
||||
#define DECLARE_ID(name) const Identifier name (#name)
|
||||
|
||||
DECLARE_ID (name);
|
||||
DECLARE_ID (file);
|
||||
|
|
@ -359,8 +359,11 @@ namespace Ids
|
|||
DECLARE_ID (compilerFlagSchemes);
|
||||
DECLARE_ID (compilerFlagScheme);
|
||||
DECLARE_ID (dontQueryForUpdate);
|
||||
DECLARE_ID (dontAskAboutJUCEPath);
|
||||
DECLARE_ID (postExportShellCommandPosix);
|
||||
DECLARE_ID (postExportShellCommandWin);
|
||||
DECLARE_ID (liveBuildEnabled);
|
||||
DECLARE_ID (guiEditorEnabled);
|
||||
|
||||
const Identifier ID ("id");
|
||||
const Identifier ID_uppercase ("ID");
|
||||
|
|
|
|||
|
|
@ -19,7 +19,6 @@
|
|||
#include "../../Application/jucer_Headers.h"
|
||||
#include "../../ProjectSaving/jucer_ProjectExporter.h"
|
||||
#include "jucer_PIPGenerator.h"
|
||||
#include "../../Project/jucer_Module.h"
|
||||
|
||||
//==============================================================================
|
||||
static void ensureSingleNewLineAfterIncludes (StringArray& lines)
|
||||
|
|
@ -105,7 +104,7 @@ PIPGenerator::PIPGenerator (const File& pip, const File& output, const File& juc
|
|||
|
||||
if (userModulesPath != File())
|
||||
{
|
||||
availableUserModules.reset (new AvailableModuleList());
|
||||
availableUserModules.reset (new AvailableModulesList());
|
||||
availableUserModules->scanPaths ({ userModulesPath });
|
||||
}
|
||||
}
|
||||
|
|
@ -357,6 +356,8 @@ Result PIPGenerator::setProjectSettings (ValueTree& jucerTree)
|
|||
: "\"File->Global Paths...\"")
|
||||
+ " menu item.");
|
||||
}
|
||||
|
||||
jucerTree.setProperty (Ids::displaySplashScreen, true, nullptr);
|
||||
}
|
||||
|
||||
setPropertyIfNotEmpty (Ids::defines, defines);
|
||||
|
|
|
|||
|
|
@ -19,6 +19,7 @@
|
|||
#pragma once
|
||||
|
||||
#include "../Helpers/jucer_MiscUtilities.h"
|
||||
#include "../../Project/Modules/jucer_AvailableModulesList.h"
|
||||
|
||||
//==============================================================================
|
||||
class PIPGenerator
|
||||
|
|
@ -70,13 +71,9 @@ private:
|
|||
|
||||
//==============================================================================
|
||||
File pipFile, outputDirectory, juceModulesPath, userModulesPath;
|
||||
|
||||
std::unique_ptr<AvailableModuleList> availableUserModules;
|
||||
|
||||
std::unique_ptr<AvailableModulesList> availableUserModules;
|
||||
var metadata;
|
||||
|
||||
bool isTemp = false;
|
||||
bool useLocalCopy = false;
|
||||
bool isTemp = false, useLocalCopy = false;
|
||||
|
||||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (PIPGenerator)
|
||||
};
|
||||
|
|
|
|||
|
|
@ -20,19 +20,52 @@
|
|||
|
||||
|
||||
//==============================================================================
|
||||
struct IconButton : public Button
|
||||
class IconButton : public Button
|
||||
{
|
||||
IconButton (String name, const Path* p)
|
||||
: Button (name),
|
||||
icon (p, Colours::transparentBlack)
|
||||
public:
|
||||
IconButton (String buttonName, Image imageToDisplay)
|
||||
: Button (buttonName),
|
||||
iconImage (imageToDisplay)
|
||||
{
|
||||
lookAndFeelChanged();
|
||||
setTooltip (name);
|
||||
setTooltip (buttonName);
|
||||
}
|
||||
|
||||
IconButton (String buttonName, Path pathToDisplay)
|
||||
: Button (buttonName),
|
||||
iconPath (pathToDisplay),
|
||||
iconImage (createImageFromPath (iconPath))
|
||||
{
|
||||
setTooltip (buttonName);
|
||||
}
|
||||
|
||||
void setImage (Image newImage)
|
||||
{
|
||||
iconImage = newImage;
|
||||
repaint();
|
||||
}
|
||||
|
||||
void setPath (Path newPath)
|
||||
{
|
||||
iconImage = createImageFromPath (newPath);
|
||||
repaint();
|
||||
}
|
||||
|
||||
void setBackgroundColour (Colour backgroundColourToUse)
|
||||
{
|
||||
backgroundColour = backgroundColourToUse;
|
||||
usingNonDefaultBackgroundColour = true;
|
||||
}
|
||||
|
||||
void setIconInset (int newIconInset)
|
||||
{
|
||||
iconInset = newIconInset;
|
||||
repaint();
|
||||
}
|
||||
|
||||
void paintButton (Graphics& g, bool isMouseOverButton, bool isButtonDown) override
|
||||
{
|
||||
auto alpha = 1.0f;
|
||||
float alpha = 1.0f;
|
||||
|
||||
if (! isEnabled())
|
||||
{
|
||||
isMouseOverButton = false;
|
||||
|
|
@ -41,43 +74,56 @@ struct IconButton : public Button
|
|||
alpha = 0.2f;
|
||||
}
|
||||
|
||||
auto backgroundColour = isIDEButton ? Colours::white
|
||||
: isUserButton ? findColour (userButtonBackgroundColourId)
|
||||
: findColour (defaultButtonBackgroundColourId);
|
||||
auto fill = isButtonDown ? backgroundColour.darker (0.5f)
|
||||
: isMouseOverButton ? backgroundColour.darker (0.2f)
|
||||
: backgroundColour;
|
||||
|
||||
backgroundColour = isButtonDown ? backgroundColour.darker (0.5f)
|
||||
: isMouseOverButton ? backgroundColour.darker (0.2f)
|
||||
: backgroundColour;
|
||||
|
||||
auto bounds = getLocalBounds().toFloat();
|
||||
auto bounds = getLocalBounds();
|
||||
|
||||
if (isButtonDown)
|
||||
bounds.reduce (2, 2);
|
||||
|
||||
Path ellipse;
|
||||
ellipse.addEllipse (bounds);
|
||||
g.reduceClipRegion(ellipse);
|
||||
ellipse.addEllipse (bounds.toFloat());
|
||||
g.reduceClipRegion (ellipse);
|
||||
|
||||
g.setColour (backgroundColour.withAlpha (alpha));
|
||||
g.setColour (fill.withAlpha (alpha));
|
||||
g.fillAll();
|
||||
|
||||
if (iconImage != Image())
|
||||
{
|
||||
if (isIDEButton)
|
||||
bounds.reduce (7, 7);
|
||||
|
||||
g.setOpacity (alpha);
|
||||
g.drawImage (iconImage, bounds, RectanglePlacement::fillDestination, false);
|
||||
}
|
||||
else
|
||||
{
|
||||
icon.withColour (findColour (defaultIconColourId).withAlpha (alpha)).draw (g, bounds.reduced (2, 2), false);
|
||||
}
|
||||
g.setOpacity (alpha);
|
||||
g.drawImage (iconImage, bounds.reduced (iconInset).toFloat(), RectanglePlacement::fillDestination, false);
|
||||
}
|
||||
|
||||
Icon icon;
|
||||
Image iconImage;
|
||||
private:
|
||||
void lookAndFeelChanged() override
|
||||
{
|
||||
if (! usingNonDefaultBackgroundColour)
|
||||
backgroundColour = findColour (defaultButtonBackgroundColourId);
|
||||
|
||||
bool isIDEButton = false;
|
||||
bool isUserButton = false;
|
||||
if (iconPath != Path())
|
||||
iconImage = createImageFromPath (iconPath);
|
||||
|
||||
repaint();
|
||||
}
|
||||
|
||||
Image createImageFromPath (Path path)
|
||||
{
|
||||
Image image (Image::ARGB, 250, 250, true);
|
||||
Graphics g (image);
|
||||
|
||||
g.setColour (findColour (defaultIconColourId));
|
||||
|
||||
g.fillPath (path, RectanglePlacement (RectanglePlacement::centred)
|
||||
.getTransformToFit (path.getBounds(), image.getBounds().toFloat()));
|
||||
|
||||
return image;
|
||||
}
|
||||
|
||||
Path iconPath;
|
||||
Image iconImage;
|
||||
Colour backgroundColour { findColour (defaultButtonBackgroundColourId) };
|
||||
bool usingNonDefaultBackgroundColour = false;
|
||||
int iconInset = 2;
|
||||
|
||||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (IconButton)
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1515,29 +1515,6 @@ const uint8 clion[] = { 110,109,0,0,0,0,0,0,0,0,98,0,0,0,0,170,170,38,67,0,0,0,0
|
|||
0,192,218,67,98,0,128,44,67,0,192,218,67,0,0,220,66,0,192,218,67,252,255,61,66,0,192,218,67,98,252,255,61,66,170,138,213,67,252,255,61,66,84,85,208,67,252,255,61,66,254,31,203,67,99,101,0,0 };
|
||||
}
|
||||
|
||||
/*static void convertSVGPathToCppData (const String& pathString)
|
||||
{
|
||||
XmlElement svg ("svg");
|
||||
XmlElement* path = svg.createNewChildElement ("path");
|
||||
path->setAttribute ("d", pathString);
|
||||
|
||||
std::unique_ptr<Drawable> d (Drawable::createFromSVG (svg));
|
||||
DrawablePath* dp = dynamic_cast<DrawablePath*> (d->getChildComponent(0));
|
||||
jassert (dp != nullptr);
|
||||
Path p (dp->getPath());
|
||||
|
||||
p.applyTransform (RectanglePlacement (RectanglePlacement::centred).getTransformToFit (p.getBounds(),
|
||||
Rectangle<float> (500.0f, 500.0f)));
|
||||
|
||||
MemoryOutputStream data;
|
||||
p.writePathToStream (data);
|
||||
|
||||
MemoryOutputStream out;
|
||||
CodeHelpers::writeDataAsCppLiteral (data.getMemoryBlock(), out, false, true);
|
||||
|
||||
DBG (out.toString() << newLine);
|
||||
}*/
|
||||
|
||||
Icons::Icons()
|
||||
{
|
||||
#define JUCE_LOAD_PATH_DATA(name) \
|
||||
|
|
|
|||
|
|
@ -22,18 +22,22 @@
|
|||
//==============================================================================
|
||||
struct Icon
|
||||
{
|
||||
Icon() : path (nullptr) {}
|
||||
Icon (const Path& p, Colour c) : path (&p), colour (c) {}
|
||||
Icon (const Path* p, Colour c) : path (p), colour (c) {}
|
||||
Icon() = default;
|
||||
|
||||
Icon (const Path& pathToUse, Colour pathColour)
|
||||
: path (pathToUse),
|
||||
colour (pathColour)
|
||||
{
|
||||
}
|
||||
|
||||
void draw (Graphics& g, const juce::Rectangle<float>& area, bool isCrossedOut) const
|
||||
{
|
||||
if (path != nullptr)
|
||||
if (! path.isEmpty())
|
||||
{
|
||||
g.setColour (colour);
|
||||
|
||||
const RectanglePlacement placement (RectanglePlacement::centred | RectanglePlacement::onlyReduceInSize);
|
||||
g.fillPath (*path, placement.getTransformToFit (path->getBounds(), area));
|
||||
g.fillPath (path, placement.getTransformToFit (path.getBounds(), area));
|
||||
|
||||
if (isCrossedOut)
|
||||
{
|
||||
|
|
@ -54,7 +58,7 @@ struct Icon
|
|||
return Icon (path, newColour);
|
||||
}
|
||||
|
||||
const Path* path;
|
||||
Path path;
|
||||
Colour colour;
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -19,6 +19,7 @@
|
|||
#include "../../Application/jucer_Headers.h"
|
||||
#include "jucer_ProjucerLookAndFeel.h"
|
||||
#include "../../Application/jucer_Application.h"
|
||||
#include "../../Project/UI/jucer_ProjectContentComponent.h"
|
||||
|
||||
//==============================================================================
|
||||
ProjucerLookAndFeel::ProjucerLookAndFeel()
|
||||
|
|
@ -40,24 +41,40 @@ void ProjucerLookAndFeel::drawTabButton (TabBarButton& button, Graphics& g, bool
|
|||
const auto alpha = button.isEnabled() ? ((isMouseOver || isMouseDown) ? 1.0f : 0.8f) : 0.3f;
|
||||
|
||||
#ifndef BUILDING_JUCE_COMPILEENGINE
|
||||
auto textColour = findColour (defaultTextColourId).withMultipliedAlpha (alpha);
|
||||
auto iconColour = findColour (button.isFrontTab() ? activeTabIconColourId
|
||||
: inactiveTabIconColourId);
|
||||
|
||||
if (button.getName() == "Project")
|
||||
auto isProjectTab = button.getName() == ProjectContentComponent::getProjectTabName();
|
||||
auto isBuildTab = button.getName() == ProjectContentComponent::getBuildTabName();
|
||||
|
||||
if (isProjectTab || isBuildTab)
|
||||
{
|
||||
auto icon = Icon (getIcons().closedFolder, iconColour.withMultipliedAlpha (alpha));
|
||||
icon.draw (g, button.getTextArea().reduced (8, 8).toFloat(), false);
|
||||
}
|
||||
else if (button.getName() == "Build")
|
||||
{
|
||||
auto icon = Icon (getIcons().buildTab, iconColour.withMultipliedAlpha (alpha));
|
||||
icon.draw (g, button.getTextArea().reduced (8, 8).toFloat(), false);
|
||||
auto icon = Icon (isProjectTab ? getIcons().closedFolder : getIcons().buildTab,
|
||||
iconColour.withMultipliedAlpha (alpha));
|
||||
|
||||
auto isSingleTab = (button.getTabbedButtonBar().getNumTabs() == 1);
|
||||
|
||||
if (isSingleTab)
|
||||
{
|
||||
auto activeArea = button.getActiveArea().reduced (5);
|
||||
|
||||
activeArea.removeFromLeft (15);
|
||||
icon.draw (g, activeArea.removeFromLeft (activeArea.getHeight()).toFloat(), false);
|
||||
activeArea.removeFromLeft (10);
|
||||
|
||||
g.setColour (textColour);
|
||||
g.drawFittedText (isProjectTab ? ProjectContentComponent::getProjectTabName() : ProjectContentComponent::getBuildTabName(),
|
||||
activeArea, Justification::centredLeft, 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
icon.draw (g, button.getTextArea().reduced (8, 8).toFloat(), false);
|
||||
}
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
auto textColour = findColour (defaultTextColourId).withMultipliedAlpha (alpha);
|
||||
|
||||
TextLayout textLayout;
|
||||
LookAndFeel_V3::createTabTextLayout (button, (float) area.getWidth(), (float) area.getHeight(), textColour, textLayout);
|
||||
|
||||
|
|
|
|||
|
|
@ -19,8 +19,6 @@
|
|||
#include "../Application/jucer_Headers.h"
|
||||
#include "jucer_NewFileWizard.h"
|
||||
|
||||
NewFileWizard::Type* createGUIComponentWizard();
|
||||
|
||||
//==============================================================================
|
||||
namespace
|
||||
{
|
||||
|
|
@ -232,7 +230,6 @@ NewFileWizard::NewFileWizard()
|
|||
registerWizard (new NewCppAndHeaderFileWizard());
|
||||
registerWizard (new NewComponentFileWizard());
|
||||
registerWizard (new NewSingleFileComponentFileWizard());
|
||||
registerWizard (createGUIComponentWizard());
|
||||
}
|
||||
|
||||
NewFileWizard::~NewFileWizard()
|
||||
|
|
|
|||
|
|
@ -122,11 +122,10 @@ struct NewProjectWizard
|
|||
projectFile = targetFolder.getChildFile (File::createLegalFileName (appTitle))
|
||||
.withFileExtension (Project::projectFileExtension);
|
||||
|
||||
std::unique_ptr<Project> project (new Project (projectFile));
|
||||
auto project = std::make_unique<Project> (projectFile);
|
||||
|
||||
if (failedFiles.size() == 0)
|
||||
{
|
||||
project->setFile (projectFile);
|
||||
project->setTitle (appTitle);
|
||||
|
||||
if (! initialiseProject (*project))
|
||||
|
|
@ -136,6 +135,9 @@ struct NewProjectWizard
|
|||
project->getProjectValue (Ids::useAppConfig) = false;
|
||||
project->getProjectValue (Ids::addUsingNamespaceToJuceHeader) = false;
|
||||
|
||||
if (! ProjucerApplication::getApp().getLicenseController().getCurrentState().isPaidOrGPL())
|
||||
project->getProjectValue (Ids::displaySplashScreen) = true;
|
||||
|
||||
addExporters (*project, wc);
|
||||
addDefaultModules (*project, useGlobalPath);
|
||||
|
||||
|
|
@ -174,7 +176,7 @@ struct NewProjectWizard
|
|||
{
|
||||
auto defaultModules = getDefaultModules();
|
||||
|
||||
AvailableModuleList list;
|
||||
AvailableModulesList list;
|
||||
list.scanPaths ({ modulesFolder });
|
||||
|
||||
for (auto& mod : list.getAllModules())
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue