From 711e75bdc847eb8826014b7c38303449e18374b4 Mon Sep 17 00:00:00 2001 From: ed Date: Thu, 15 Mar 2018 11:11:42 +0000 Subject: [PATCH] Projucer: Add analytics --- extras/Projucer/Builds/LinuxMakefile/Makefile | 12 + .../MacOSX/Projucer.xcodeproj/project.pbxproj | 24 +- .../VisualStudio2013/Projucer_App.vcxproj | 23 +- .../Projucer_App.vcxproj.filters | 50 +++- .../VisualStudio2015/Projucer_App.vcxproj | 23 +- .../Projucer_App.vcxproj.filters | 50 +++- .../VisualStudio2017/Projucer_App.vcxproj | 23 +- .../Projucer_App.vcxproj.filters | 50 +++- extras/Projucer/JuceLibraryCode/AppConfig.h | 1 + .../Projucer/JuceLibraryCode/BinaryData.cpp | 20 +- extras/Projucer/JuceLibraryCode/BinaryData.h | 5 +- extras/Projucer/JuceLibraryCode/JuceHeader.h | 1 + .../include_juce_analytics.cpp | 9 + extras/Projucer/Projucer.jucer | 26 +- .../Source/Application/jucer_Application.cpp | 59 +++++ .../Source/Application/jucer_Application.h | 7 + .../Application/jucer_ProjucerAnalytics.cpp | 245 ++++++++++++++++++ .../Application/jucer_ProjucerAnalytics.h | 68 +++++ .../Source/BinaryData/nothingtoseehere.txt | 1 + .../UI/jucer_JucerDocumentEditor.cpp | 6 + .../Licenses/jucer_LicenseController.cpp | 12 + .../UI/Sidebar/jucer_ModuleTreeItems.h | 9 + .../Project/UI/jucer_HeaderComponent.cpp | 16 ++ .../UI/jucer_ProjectContentComponent.cpp | 17 ++ .../Projucer/Source/Project/jucer_Module.cpp | 6 + .../Projucer/Source/Project/jucer_Project.cpp | 26 ++ .../Projucer/Source/Project/jucer_Project.h | 3 + .../Source/Wizards/jucer_NewProjectWizard.h | 5 + 28 files changed, 772 insertions(+), 25 deletions(-) create mode 100644 extras/Projucer/JuceLibraryCode/include_juce_analytics.cpp create mode 100644 extras/Projucer/Source/Application/jucer_ProjucerAnalytics.cpp create mode 100644 extras/Projucer/Source/Application/jucer_ProjucerAnalytics.h create mode 100644 extras/Projucer/Source/BinaryData/nothingtoseehere.txt diff --git a/extras/Projucer/Builds/LinuxMakefile/Makefile b/extras/Projucer/Builds/LinuxMakefile/Makefile index 59e0162117..a8e5c03649 100644 --- a/extras/Projucer/Builds/LinuxMakefile/Makefile +++ b/extras/Projucer/Builds/LinuxMakefile/Makefile @@ -72,6 +72,7 @@ OBJECTS_APP := \ $(JUCE_OBJDIR)/jucer_CommandLine_f35de107.o \ $(JUCE_OBJDIR)/jucer_Main_f8488f5b.o \ $(JUCE_OBJDIR)/jucer_MainWindow_1e163aeb.o \ + $(JUCE_OBJDIR)/jucer_ProjucerAnalytics_5740f336.o \ $(JUCE_OBJDIR)/jucer_DocumentEditorComponent_bc853a2f.o \ $(JUCE_OBJDIR)/jucer_OpenDocumentManager_ba866622.o \ $(JUCE_OBJDIR)/jucer_SourceCodeEditor_55965985.o \ @@ -121,6 +122,7 @@ OBJECTS_APP := \ $(JUCE_OBJDIR)/jucer_NewFileWizard_fac97f47.o \ $(JUCE_OBJDIR)/jucer_NewProjectWizardClasses_891f6fa2.o \ $(JUCE_OBJDIR)/BinaryData_ce4232d4.o \ + $(JUCE_OBJDIR)/include_juce_analytics_f8e9fa94.o \ $(JUCE_OBJDIR)/include_juce_core_f26d17db.o \ $(JUCE_OBJDIR)/include_juce_cryptography_8cb807a8.o \ $(JUCE_OBJDIR)/include_juce_data_structures_7471b1e3.o \ @@ -160,6 +162,11 @@ $(JUCE_OBJDIR)/jucer_MainWindow_1e163aeb.o: ../../Source/Application/jucer_MainW @echo "Compiling jucer_MainWindow.cpp" $(V_AT)$(CXX) $(JUCE_CXXFLAGS) $(JUCE_CPPFLAGS_APP) $(JUCE_CFLAGS_APP) -o "$@" -c "$<" +$(JUCE_OBJDIR)/jucer_ProjucerAnalytics_5740f336.o: ../../Source/Application/jucer_ProjucerAnalytics.cpp + -$(V_AT)mkdir -p $(JUCE_OBJDIR) + @echo "Compiling jucer_ProjucerAnalytics.cpp" + $(V_AT)$(CXX) $(JUCE_CXXFLAGS) $(JUCE_CPPFLAGS_APP) $(JUCE_CFLAGS_APP) -o "$@" -c "$<" + $(JUCE_OBJDIR)/jucer_DocumentEditorComponent_bc853a2f.o: ../../Source/CodeEditor/jucer_DocumentEditorComponent.cpp -$(V_AT)mkdir -p $(JUCE_OBJDIR) @echo "Compiling jucer_DocumentEditorComponent.cpp" @@ -405,6 +412,11 @@ $(JUCE_OBJDIR)/BinaryData_ce4232d4.o: ../../JuceLibraryCode/BinaryData.cpp @echo "Compiling BinaryData.cpp" $(V_AT)$(CXX) $(JUCE_CXXFLAGS) $(JUCE_CPPFLAGS_APP) $(JUCE_CFLAGS_APP) -o "$@" -c "$<" +$(JUCE_OBJDIR)/include_juce_analytics_f8e9fa94.o: ../../JuceLibraryCode/include_juce_analytics.cpp + -$(V_AT)mkdir -p $(JUCE_OBJDIR) + @echo "Compiling include_juce_analytics.cpp" + $(V_AT)$(CXX) $(JUCE_CXXFLAGS) $(JUCE_CPPFLAGS_APP) $(JUCE_CFLAGS_APP) -o "$@" -c "$<" + $(JUCE_OBJDIR)/include_juce_core_f26d17db.o: ../../JuceLibraryCode/include_juce_core.cpp -$(V_AT)mkdir -p $(JUCE_OBJDIR) @echo "Compiling include_juce_core.cpp" diff --git a/extras/Projucer/Builds/MacOSX/Projucer.xcodeproj/project.pbxproj b/extras/Projucer/Builds/MacOSX/Projucer.xcodeproj/project.pbxproj index 0cdb10559d..6d8000e29f 100644 --- a/extras/Projucer/Builds/MacOSX/Projucer.xcodeproj/project.pbxproj +++ b/extras/Projucer/Builds/MacOSX/Projucer.xcodeproj/project.pbxproj @@ -28,6 +28,7 @@ 954A036F5DDB375DB23FFB3E = {isa = PBXBuildFile; fileRef = 0400CB0E056A1D840304D2DE; }; 95B44E6C74B1DED31DBE37EB = {isa = PBXBuildFile; fileRef = 8C52A3DDA62A746AA7A68535; }; AA9D0B8E23F3D87A23DE9F8A = {isa = PBXBuildFile; fileRef = 9069981E414A631B036CC9AC; }; + 98F9BB4612E82EE59689E15C = {isa = PBXBuildFile; fileRef = B6496F16ACE80CACC5721570; }; 09C4EDDF7F8B6E75EA3CE3A9 = {isa = PBXBuildFile; fileRef = BC3B310D42C489E8B8D93327; }; 71713DE4716DCEDB45A206E2 = {isa = PBXBuildFile; fileRef = F9111E150CFF155329D44853; }; 940CE4E081E9E685243C07AA = {isa = PBXBuildFile; fileRef = 332AF94C3275FEA8B878D603; }; @@ -77,6 +78,7 @@ 518DD443B6F17A5AFD707263 = {isa = PBXBuildFile; fileRef = A69024A225F2AC31F17B1314; }; B7EBA1A83575F48CD08140B9 = {isa = PBXBuildFile; fileRef = 4B083E951ECB62217C46CB01; }; 3C5267E06A897B0DC0F7EA50 = {isa = PBXBuildFile; fileRef = 472F9A90F685220D730EBF6C; }; + 202DC8CF15ACBE096CC327EA = {isa = PBXBuildFile; fileRef = 805A3A5FBA3B9E28363DD77B; }; 5DD883699B85E4C492CAD065 = {isa = PBXBuildFile; fileRef = DB9C8E35DF815B803CB4A9CF; }; D5C9125F65493CA481F18E53 = {isa = PBXBuildFile; fileRef = D766BB9D8C32B5560F0493F3; }; 02E8F35A8E0D4A0DF6F38D60 = {isa = PBXBuildFile; fileRef = 1DE5BBC777FB64798D823002; }; @@ -167,6 +169,7 @@ 432EC251A122071809471804 = {isa = PBXFileReference; lastKnownFileType = file.svg; name = "juce-logo-with-text.svg"; path = "../../Source/BinaryData/Icons/juce-logo-with-text.svg"; sourceTree = "SOURCE_ROOT"; }; 471C7B0A8B92320AF0C80839 = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "jucer_ProjectWizard_StaticLibrary.h"; path = "../../Source/Wizards/jucer_ProjectWizard_StaticLibrary.h"; sourceTree = "SOURCE_ROOT"; }; 472F9A90F685220D730EBF6C = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = BinaryData.cpp; path = ../../JuceLibraryCode/BinaryData.cpp; sourceTree = "SOURCE_ROOT"; }; + 4818A05DE44ADA03D85E1083 = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "jucer_ProjucerAnalytics.h"; path = "../../Source/Application/jucer_ProjucerAnalytics.h"; sourceTree = "SOURCE_ROOT"; }; 486E8D02DAD2A0BF54A901C0 = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = "jucer_MiscUtilities.cpp"; path = "../../Source/Utility/Helpers/jucer_MiscUtilities.cpp"; sourceTree = "SOURCE_ROOT"; }; 4974E7808F9B57E9A627F878 = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "jucer_FileTreeItems.h"; path = "../../Source/Project/UI/Sidebar/jucer_FileTreeItems.h"; sourceTree = "SOURCE_ROOT"; }; 4A4EBDAD8D098F72CE053235 = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "jucer_ProjectWizard_AudioPlugin.h"; path = "../../Source/Wizards/jucer_ProjectWizard_AudioPlugin.h"; sourceTree = "SOURCE_ROOT"; }; @@ -193,9 +196,11 @@ 5783563E39E48ADFC68EB84A = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "jucer_ComponentTextProperty.h"; path = "../../Source/ComponentEditor/Properties/jucer_ComponentTextProperty.h"; sourceTree = "SOURCE_ROOT"; }; 58139D8D454051C59E77609B = {isa = PBXFileReference; lastKnownFileType = file.nib; name = RecentFilesMenuTemplate.nib; path = ../../Source/BinaryData/RecentFilesMenuTemplate.nib; sourceTree = "SOURCE_ROOT"; }; 5867DC4E39DF8539B54C0D59 = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; name = "include_juce_events.mm"; path = "../../JuceLibraryCode/include_juce_events.mm"; sourceTree = "SOURCE_ROOT"; }; + 58DE91CE6B05AFBACADDB251 = {isa = PBXFileReference; lastKnownFileType = file; name = "juce_analytics"; path = "../../../../modules/juce_analytics"; sourceTree = "SOURCE_ROOT"; }; 58F1FF52E887887A93E84FC2 = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "jucer_PresetIDs.h"; path = "../../Source/Utility/Helpers/jucer_PresetIDs.h"; sourceTree = "SOURCE_ROOT"; }; 59203884BC48D3B7F8DEABA8 = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "jucer_ContentCompTemplate.h"; path = "../../Source/BinaryData/Templates/jucer_ContentCompTemplate.h"; sourceTree = "SOURCE_ROOT"; }; 59520B8137E6A2E483074399 = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "jucer_ProjectExport_Make.h"; path = "../../Source/ProjectSaving/jucer_ProjectExport_Make.h"; sourceTree = "SOURCE_ROOT"; }; + 59B08C7B13B8EA5137ACA77A = {isa = PBXFileReference; lastKnownFileType = text.txt; name = nothingtoseehere.txt; path = ../../Source/BinaryData/nothingtoseehere.txt; sourceTree = "SOURCE_ROOT"; }; 59F8A47C0020D62C8836A1E7 = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "jucer_PropertyComponentsWithEnablement.h"; path = "../../Source/Utility/UI/PropertyComponents/jucer_PropertyComponentsWithEnablement.h"; sourceTree = "SOURCE_ROOT"; }; 5A75806B34E4EA6598A6024A = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AudioToolbox.framework; path = System/Library/Frameworks/AudioToolbox.framework; sourceTree = SDKROOT; }; 5B3532C5F103DAC87B4A5675 = {isa = PBXFileReference; lastKnownFileType = file.svg; name = "wizard_GUI.svg"; path = "../../Source/BinaryData/Icons/wizard_GUI.svg"; sourceTree = "SOURCE_ROOT"; }; @@ -235,6 +240,7 @@ 7CA44FF0BA319517C6E39651 = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = "jucer_Application.cpp"; path = "../../Source/Application/jucer_Application.cpp"; sourceTree = "SOURCE_ROOT"; }; 7E2013F425E231C6D865DDD0 = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "jucer_ComponentChoiceProperty.h"; path = "../../Source/ComponentEditor/Properties/jucer_ComponentChoiceProperty.h"; sourceTree = "SOURCE_ROOT"; }; 7F0A5319912991615FC57945 = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "jucer_ColourPropertyComponent.h"; path = "../../Source/ComponentEditor/Properties/jucer_ColourPropertyComponent.h"; sourceTree = "SOURCE_ROOT"; }; + 805A3A5FBA3B9E28363DD77B = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = "include_juce_analytics.cpp"; path = "../../JuceLibraryCode/include_juce_analytics.cpp"; sourceTree = "SOURCE_ROOT"; }; 807049CA2D5B6DE18EA078F2 = {isa = PBXFileReference; lastKnownFileType = file.svg; name = "export_android.svg"; path = "../../Source/BinaryData/Icons/export_android.svg"; sourceTree = "SOURCE_ROOT"; }; 80D62B907248523E6943298B = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Accelerate.framework; path = System/Library/Frameworks/Accelerate.framework; sourceTree = SDKROOT; }; 8336A43CE1C3C26D7C7B53D8 = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = "jucer_NewComponentTemplate.cpp"; path = "../../Source/BinaryData/Templates/jucer_NewComponentTemplate.cpp"; sourceTree = "SOURCE_ROOT"; }; @@ -308,6 +314,7 @@ B2CB95B3F44C3CC5735051A3 = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "jucer_JustificationProperty.h"; path = "../../Source/ComponentEditor/Properties/jucer_JustificationProperty.h"; sourceTree = "SOURCE_ROOT"; }; B3528C08B84CBC950252EA69 = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "jucer_ModulesInformationComponent.h"; path = "../../Source/Project/UI/jucer_ModulesInformationComponent.h"; sourceTree = "SOURCE_ROOT"; }; B403AF75EAF361ED74EE476E = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = "jucer_FileHelpers.cpp"; path = "../../Source/Utility/Helpers/jucer_FileHelpers.cpp"; sourceTree = "SOURCE_ROOT"; }; + B6496F16ACE80CACC5721570 = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = "jucer_ProjucerAnalytics.cpp"; path = "../../Source/Application/jucer_ProjucerAnalytics.cpp"; sourceTree = "SOURCE_ROOT"; }; B6F2905330EA5C560D527209 = {isa = PBXFileReference; lastKnownFileType = file; name = "juce_graphics"; path = "../../../../modules/juce_graphics"; sourceTree = "SOURCE_ROOT"; }; B8385E9A644BD3CD94876448 = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "jucer_ProjectType.h"; path = "../../Source/Project/jucer_ProjectType.h"; sourceTree = "SOURCE_ROOT"; }; B83C9BD89F31EA9E5E12A3C6 = {isa = PBXFileReference; lastKnownFileType = image.png; name = "juce_icon.png"; path = "../../Source/BinaryData/Icons/juce_icon.png"; sourceTree = "SOURCE_ROOT"; }; @@ -349,7 +356,6 @@ D2FE76E4CF003856278343CC = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = "jucer_CompileEngineServer.cpp"; path = "../../Source/LiveBuildEngine/jucer_CompileEngineServer.cpp"; sourceTree = "SOURCE_ROOT"; }; D4EB334E5186D1584EC63CA4 = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "jucer_AudioComponentSimpleTemplate.h"; path = "../../Source/BinaryData/Templates/jucer_AudioComponentSimpleTemplate.h"; sourceTree = "SOURCE_ROOT"; }; D5795F8CAC5876714DAB355F = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "jucer_AnimatedComponentTemplate.h"; path = "../../Source/BinaryData/Templates/jucer_AnimatedComponentTemplate.h"; sourceTree = "SOURCE_ROOT"; }; - D588BA6A0C62DE1F18D5C2EA = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "jucer_GlobalSearchPathsWindowComponent.h"; path = "../../Source/Application/Windows/jucer_GlobalSearchPathsWindowComponent.h"; sourceTree = "SOURCE_ROOT"; }; D5EF5961B1F0E3FAED32E30A = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "jucer_ProjectExport_CLion.h"; path = "../../Source/ProjectSaving/jucer_ProjectExport_CLion.h"; sourceTree = "SOURCE_ROOT"; }; D6390A40B3279E0E626C78D3 = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = "jucer_ColouredElement.cpp"; path = "../../Source/ComponentEditor/PaintElements/jucer_ColouredElement.cpp"; sourceTree = "SOURCE_ROOT"; }; D766BB9D8C32B5560F0493F3 = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; name = "include_juce_cryptography.mm"; path = "../../JuceLibraryCode/include_juce_cryptography.mm"; sourceTree = "SOURCE_ROOT"; }; @@ -377,6 +383,7 @@ E96597BBC6A98255B51B94DC = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = IOKit.framework; path = System/Library/Frameworks/IOKit.framework; sourceTree = SDKROOT; }; E983E6DDE3318B872EBE347F = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreAudioKit.framework; path = System/Library/Frameworks/CoreAudioKit.framework; sourceTree = SDKROOT; }; EAC1731150A7F79D59BAA0B6 = {isa = PBXFileReference; lastKnownFileType = file.svg; name = "export_visualStudio.svg"; path = "../../Source/BinaryData/Icons/export_visualStudio.svg"; sourceTree = "SOURCE_ROOT"; }; + EB2E723DC3DB150A8A644D08 = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "jucer_GlobalPathsWindowComponent.h"; path = "../../Source/Application/Windows/jucer_GlobalPathsWindowComponent.h"; sourceTree = "SOURCE_ROOT"; }; ED5EAC91D8A0A1911BE9F482 = {isa = PBXFileReference; lastKnownFileType = file.svg; name = "wizard_ConsoleApp.svg"; path = "../../Source/BinaryData/Icons/wizard_ConsoleApp.svg"; sourceTree = "SOURCE_ROOT"; }; ED69863B3D591FB3F0CA50E4 = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "jucer_PaintRoutineEditor.h"; path = "../../Source/ComponentEditor/UI/jucer_PaintRoutineEditor.h"; sourceTree = "SOURCE_ROOT"; }; EE690110171E1648FF2118B8 = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "jucer_Application.h"; path = "../../Source/Application/jucer_Application.h"; sourceTree = "SOURCE_ROOT"; }; @@ -404,7 +411,7 @@ B83DAADA1A871F21582FFB23, D91E7F8FEF9290195D56782C, C736264708F3F68BA745BA29, - D588BA6A0C62DE1F18D5C2EA, + EB2E723DC3DB150A8A644D08, DDC382008FFD9F9E0B2B0EDD, F7C74E934C954F6F1A3BE4F9, 92926A4D3CC4BB2A9D35EB0B, ); name = Windows; sourceTree = ""; }; @@ -421,7 +428,9 @@ 3F8EC008960DBEB2A5D3C3F4, 8C52A3DDA62A746AA7A68535, 9069981E414A631B036CC9AC, - 2CD34A70B4032C0426F7AA10, ); name = Application; sourceTree = ""; }; + 2CD34A70B4032C0426F7AA10, + B6496F16ACE80CACC5721570, + 4818A05DE44ADA03D85E1083, ); name = Application; sourceTree = ""; }; 8CF70DA9AB4725126B9F55BE = {isa = PBXGroup; children = ( 129F2DE0FEF154F8F8C7A74E, 0B24F292A357ABFD9BCC6D7F, @@ -484,6 +493,7 @@ E59ABA0D11CBAAD77179E9C6, 41105E536155E394E54BDD35, 5F6584B675E30761521A9F42, + 59B08C7B13B8EA5137ACA77A, 8C281F2F8EA3AD614ADF7955, 4073A12E196BDDADE211E19F, 58139D8D454051C59E77609B, ); name = BinaryData; sourceTree = ""; }; @@ -677,7 +687,7 @@ A6C4AE13FB409DE414094CFA, 6FD8DBC0FF42C87D8BEE2452, 00515BA4EC5A7D4DC078ED37, ); name = Helpers; sourceTree = ""; }; - 71AF6BA7575AF4EB0CB9F43C = {isa = PBXGroup; children = ( + B4972C4048154E5E783D3934 = {isa = PBXGroup; children = ( 191330B20DAC08B890656EA0, C76271530EB4458B6146D463, ); name = PIPs; sourceTree = ""; }; 15F56361B9CF3E0BE705E64D = {isa = PBXGroup; children = ( @@ -700,7 +710,7 @@ 28D0199327887FFABF9C3F20, ); name = UI; sourceTree = ""; }; 2B1F885AA027E1A76A1C32E3 = {isa = PBXGroup; children = ( AA2CBF47682AE479C1A387BE, - 71AF6BA7575AF4EB0CB9F43C, + B4972C4048154E5E783D3934, DD068F16F341D15E150CE6F1, ); name = Utility; sourceTree = ""; }; 73BAA89A783BBDD79AA27964 = {isa = PBXGroup; children = ( A69024A225F2AC31F17B1314, @@ -733,6 +743,7 @@ 2B1F885AA027E1A76A1C32E3, 73BAA89A783BBDD79AA27964, ); name = Projucer; sourceTree = ""; }; 8A24D1B6925535A868974986 = {isa = PBXGroup; children = ( + 58DE91CE6B05AFBACADDB251, BA159A3B7D129771F5C15EA3, AA1C44E89D792DDC4867B2C8, 69555CEFC6ED613AA3949298, @@ -744,6 +755,7 @@ 8702F43110E4CCA5E5F827F5, 472F9A90F685220D730EBF6C, 4F687965FBE86EAFDB3ACFEC, + 805A3A5FBA3B9E28363DD77B, DB9C8E35DF815B803CB4A9CF, D766BB9D8C32B5560F0493F3, 1DE5BBC777FB64798D823002, @@ -938,6 +950,7 @@ 954A036F5DDB375DB23FFB3E, 95B44E6C74B1DED31DBE37EB, AA9D0B8E23F3D87A23DE9F8A, + 98F9BB4612E82EE59689E15C, 09C4EDDF7F8B6E75EA3CE3A9, 71713DE4716DCEDB45A206E2, 940CE4E081E9E685243C07AA, @@ -987,6 +1000,7 @@ 518DD443B6F17A5AFD707263, B7EBA1A83575F48CD08140B9, 3C5267E06A897B0DC0F7EA50, + 202DC8CF15ACBE096CC327EA, 5DD883699B85E4C492CAD065, D5C9125F65493CA481F18E53, 02E8F35A8E0D4A0DF6F38D60, diff --git a/extras/Projucer/Builds/VisualStudio2013/Projucer_App.vcxproj b/extras/Projucer/Builds/VisualStudio2013/Projucer_App.vcxproj index 03c0364af7..64a3224907 100644 --- a/extras/Projucer/Builds/VisualStudio2013/Projucer_App.vcxproj +++ b/extras/Projucer/Builds/VisualStudio2013/Projucer_App.vcxproj @@ -155,6 +155,7 @@ + true @@ -248,6 +249,18 @@ + + true + + + true + + + true + + + true + true @@ -1416,6 +1429,7 @@ true + @@ -1429,7 +1443,7 @@ - + @@ -1440,6 +1454,7 @@ + @@ -1606,6 +1621,11 @@ + + + + + @@ -2032,6 +2052,7 @@ + diff --git a/extras/Projucer/Builds/VisualStudio2013/Projucer_App.vcxproj.filters b/extras/Projucer/Builds/VisualStudio2013/Projucer_App.vcxproj.filters index c72329bbd7..6253dd8aac 100644 --- a/extras/Projucer/Builds/VisualStudio2013/Projucer_App.vcxproj.filters +++ b/extras/Projucer/Builds/VisualStudio2013/Projucer_App.vcxproj.filters @@ -86,6 +86,15 @@ {7DBEF27C-2AFE-DA02-1DBF-E80FAAC99EA7} + + {E3CEC08A-FA14-D343-5BFF-3D6A4A4FD713} + + + {B3BC836A-3932-C1E4-CA3C-A1C0D83281BA} + + + {97F7F593-75F8-D6B2-DC96-C946C3976226} + {42F7BE9D-3C8A-AE26-289B-8F355C068036} @@ -313,6 +322,9 @@ Projucer\Application + + Projucer\Application + Projucer\BinaryData\Templates @@ -502,6 +514,18 @@ Projucer\Wizards + + JUCE Modules\juce_analytics\analytics + + + JUCE Modules\juce_analytics\analytics + + + JUCE Modules\juce_analytics\destinations + + + JUCE Modules\juce_analytics + JUCE Modules\juce_core\containers @@ -1756,6 +1780,9 @@ JUCE Library Code + + JUCE Library Code + JUCE Library Code @@ -1791,7 +1818,7 @@ Projucer\Application\Windows - + Projucer\Application\Windows @@ -1824,6 +1851,9 @@ Projucer\Application + + Projucer\Application + Projucer\BinaryData\Templates @@ -2322,6 +2352,21 @@ Projucer\Wizards + + JUCE Modules\juce_analytics\analytics + + + JUCE Modules\juce_analytics\analytics + + + JUCE Modules\juce_analytics\destinations + + + JUCE Modules\juce_analytics\destinations + + + JUCE Modules\juce_analytics + JUCE Modules\juce_core\containers @@ -3596,6 +3641,9 @@ Projucer\BinaryData + + Projucer\BinaryData + Projucer\BinaryData diff --git a/extras/Projucer/Builds/VisualStudio2015/Projucer_App.vcxproj b/extras/Projucer/Builds/VisualStudio2015/Projucer_App.vcxproj index 12632cdf9e..ad9e142942 100644 --- a/extras/Projucer/Builds/VisualStudio2015/Projucer_App.vcxproj +++ b/extras/Projucer/Builds/VisualStudio2015/Projucer_App.vcxproj @@ -155,6 +155,7 @@ + true @@ -248,6 +249,18 @@ + + true + + + true + + + true + + + true + true @@ -1416,6 +1429,7 @@ true + @@ -1429,7 +1443,7 @@ - + @@ -1440,6 +1454,7 @@ + @@ -1606,6 +1621,11 @@ + + + + + @@ -2032,6 +2052,7 @@ + diff --git a/extras/Projucer/Builds/VisualStudio2015/Projucer_App.vcxproj.filters b/extras/Projucer/Builds/VisualStudio2015/Projucer_App.vcxproj.filters index 2e93dad4a5..55ede87578 100644 --- a/extras/Projucer/Builds/VisualStudio2015/Projucer_App.vcxproj.filters +++ b/extras/Projucer/Builds/VisualStudio2015/Projucer_App.vcxproj.filters @@ -86,6 +86,15 @@ {7DBEF27C-2AFE-DA02-1DBF-E80FAAC99EA7} + + {E3CEC08A-FA14-D343-5BFF-3D6A4A4FD713} + + + {B3BC836A-3932-C1E4-CA3C-A1C0D83281BA} + + + {97F7F593-75F8-D6B2-DC96-C946C3976226} + {42F7BE9D-3C8A-AE26-289B-8F355C068036} @@ -313,6 +322,9 @@ Projucer\Application + + Projucer\Application + Projucer\BinaryData\Templates @@ -502,6 +514,18 @@ Projucer\Wizards + + JUCE Modules\juce_analytics\analytics + + + JUCE Modules\juce_analytics\analytics + + + JUCE Modules\juce_analytics\destinations + + + JUCE Modules\juce_analytics + JUCE Modules\juce_core\containers @@ -1756,6 +1780,9 @@ JUCE Library Code + + JUCE Library Code + JUCE Library Code @@ -1791,7 +1818,7 @@ Projucer\Application\Windows - + Projucer\Application\Windows @@ -1824,6 +1851,9 @@ Projucer\Application + + Projucer\Application + Projucer\BinaryData\Templates @@ -2322,6 +2352,21 @@ Projucer\Wizards + + JUCE Modules\juce_analytics\analytics + + + JUCE Modules\juce_analytics\analytics + + + JUCE Modules\juce_analytics\destinations + + + JUCE Modules\juce_analytics\destinations + + + JUCE Modules\juce_analytics + JUCE Modules\juce_core\containers @@ -3596,6 +3641,9 @@ Projucer\BinaryData + + Projucer\BinaryData + Projucer\BinaryData diff --git a/extras/Projucer/Builds/VisualStudio2017/Projucer_App.vcxproj b/extras/Projucer/Builds/VisualStudio2017/Projucer_App.vcxproj index 04a21240dd..d53772954e 100644 --- a/extras/Projucer/Builds/VisualStudio2017/Projucer_App.vcxproj +++ b/extras/Projucer/Builds/VisualStudio2017/Projucer_App.vcxproj @@ -155,6 +155,7 @@ + true @@ -248,6 +249,18 @@ + + true + + + true + + + true + + + true + true @@ -1416,6 +1429,7 @@ true + @@ -1429,7 +1443,7 @@ - + @@ -1440,6 +1454,7 @@ + @@ -1606,6 +1621,11 @@ + + + + + @@ -2032,6 +2052,7 @@ + diff --git a/extras/Projucer/Builds/VisualStudio2017/Projucer_App.vcxproj.filters b/extras/Projucer/Builds/VisualStudio2017/Projucer_App.vcxproj.filters index 08264f8f8b..8212b0f5ac 100644 --- a/extras/Projucer/Builds/VisualStudio2017/Projucer_App.vcxproj.filters +++ b/extras/Projucer/Builds/VisualStudio2017/Projucer_App.vcxproj.filters @@ -86,6 +86,15 @@ {7DBEF27C-2AFE-DA02-1DBF-E80FAAC99EA7} + + {E3CEC08A-FA14-D343-5BFF-3D6A4A4FD713} + + + {B3BC836A-3932-C1E4-CA3C-A1C0D83281BA} + + + {97F7F593-75F8-D6B2-DC96-C946C3976226} + {42F7BE9D-3C8A-AE26-289B-8F355C068036} @@ -313,6 +322,9 @@ Projucer\Application + + Projucer\Application + Projucer\BinaryData\Templates @@ -502,6 +514,18 @@ Projucer\Wizards + + JUCE Modules\juce_analytics\analytics + + + JUCE Modules\juce_analytics\analytics + + + JUCE Modules\juce_analytics\destinations + + + JUCE Modules\juce_analytics + JUCE Modules\juce_core\containers @@ -1756,6 +1780,9 @@ JUCE Library Code + + JUCE Library Code + JUCE Library Code @@ -1791,7 +1818,7 @@ Projucer\Application\Windows - + Projucer\Application\Windows @@ -1824,6 +1851,9 @@ Projucer\Application + + Projucer\Application + Projucer\BinaryData\Templates @@ -2322,6 +2352,21 @@ Projucer\Wizards + + JUCE Modules\juce_analytics\analytics + + + JUCE Modules\juce_analytics\analytics + + + JUCE Modules\juce_analytics\destinations + + + JUCE Modules\juce_analytics\destinations + + + JUCE Modules\juce_analytics + JUCE Modules\juce_core\containers @@ -3596,6 +3641,9 @@ Projucer\BinaryData + + Projucer\BinaryData + Projucer\BinaryData diff --git a/extras/Projucer/JuceLibraryCode/AppConfig.h b/extras/Projucer/JuceLibraryCode/AppConfig.h index 42b266e344..1846127fb2 100644 --- a/extras/Projucer/JuceLibraryCode/AppConfig.h +++ b/extras/Projucer/JuceLibraryCode/AppConfig.h @@ -65,6 +65,7 @@ #define JUCE_USE_DARK_SPLASH_SCREEN 1 //============================================================================== +#define JUCE_MODULE_AVAILABLE_juce_analytics 1 #define JUCE_MODULE_AVAILABLE_juce_core 1 #define JUCE_MODULE_AVAILABLE_juce_cryptography 1 #define JUCE_MODULE_AVAILABLE_juce_data_structures 1 diff --git a/extras/Projucer/JuceLibraryCode/BinaryData.cpp b/extras/Projucer/JuceLibraryCode/BinaryData.cpp index 616832c9a8..b596ae62bb 100644 --- a/extras/Projucer/JuceLibraryCode/BinaryData.cpp +++ b/extras/Projucer/JuceLibraryCode/BinaryData.cpp @@ -7184,8 +7184,14 @@ static const unsigned char temp_binary_data_54[] = const char* colourscheme_light_xml = (const char*) temp_binary_data_54; -//================== offlinepage.html ================== +//================== nothingtoseehere.txt ================== static const unsigned char temp_binary_data_55[] = +"VUEtMTk3NTkzMTgtNA=="; + +const char* nothingtoseehere_txt = (const char*) temp_binary_data_55; + +//================== offlinepage.html ================== +static const unsigned char temp_binary_data_56[] = "\n" " \n" " \n" @@ -7229,10 +7235,10 @@ static const unsigned char temp_binary_data_55[] = " \n" ""; -const char* offlinepage_html = (const char*) temp_binary_data_55; +const char* offlinepage_html = (const char*) temp_binary_data_56; //================== projucer_EULA.txt ================== -static const unsigned char temp_binary_data_56[] = +static const unsigned char temp_binary_data_57[] = "\r\n" "IMPORTANT NOTICE: PLEASE READ CAREFULLY BEFORE INSTALLING THE SOFTWARE:\r\n" "\r\n" @@ -7396,10 +7402,10 @@ static const unsigned char temp_binary_data_56[] = "\r\n" "10.6. Please note that this License, its subject matter and its formation, are governed by English law. You and we both agree to that the courts of England and Wales will have exclusive jurisdiction.\r\n"; -const char* projucer_EULA_txt = (const char*) temp_binary_data_56; +const char* projucer_EULA_txt = (const char*) temp_binary_data_57; //================== RecentFilesMenuTemplate.nib ================== -static const unsigned char temp_binary_data_57[] = +static const unsigned char temp_binary_data_58[] = { 98,112,108,105,115,116,48,48,212,0,1,0,2,0,3,0,4,0,5,0,6,1,53,1,54,88,36,118,101,114,115,105,111,110,88,36,111,98,106,101,99,116,115,89,36,97,114,99,104,105,118,101,114,84,36,116,111,112,18,0,1,134,160,175,16,74,0,7,0,8,0,31,0,35,0,36,0,42,0,46,0,50, 0,53,0,57,0,74,0,77,0,78,0,86,0,87,0,97,0,112,0,113,0,114,0,119,0,120,0,121,0,124,0,128,0,129,0,132,0,143,0,144,0,145,0,149,0,153,0,162,0,163,0,164,0,169,0,173,0,180,0,181,0,182,0,185,0,192,0,193,0,200,0,201,0,208,0,209,0,216,0,217,0,224,0,225,0,226, 0,229,0,230,0,232,0,249,1,11,1,29,1,30,1,31,1,32,1,33,1,34,1,35,1,36,1,37,1,38,1,39,1,40,1,41,1,42,1,43,1,44,1,47,1,50,85,36,110,117,108,108,219,0,9,0,10,0,11,0,12,0,13,0,14,0,15,0,16,0,17,0,18,0,19,0,20,0,21,0,22,0,23,0,24,0,25,0,26,0,27,0,28,0,29,0, @@ -7436,7 +7442,7 @@ static const unsigned char temp_binary_data_57[] = 7,157,7,159,7,161,7,163,7,165,7,167,7,169,7,171,7,173,7,175,7,177,7,179,7,181,7,190,7,192,7,225,7,227,7,229,7,231,7,233,7,235,7,237,7,239,7,241,7,243,7,245,7,247,7,249,7,251,7,253,7,255,8,2,8,5,8,8,8,11,8,14,8,17,8,20,8,23,8,26,8,29,8,32,8,35,8,38,8, 41,8,44,8,53,8,55,8,56,8,65,8,67,8,68,8,77,8,92,8,97,8,115,8,120,8,134,0,0,0,0,0,0,2,2,0,0,0,0,0,0,1,57,0,0,0,0,0,0,0,0,0,0,0,0,0,0,8,136,0,0 }; -const char* RecentFilesMenuTemplate_nib = (const char*) temp_binary_data_57; +const char* RecentFilesMenuTemplate_nib = (const char*) temp_binary_data_58; const char* getNamedResource (const char*, int&) throw(); @@ -7504,6 +7510,7 @@ const char* getNamedResource (const char* resourceNameUTF8, int& numBytes) throw case 0xf4ca9e9a: numBytes = 2446; return jucer_PIPMain_cpp; case 0x763d39dc: numBytes = 1050; return colourscheme_dark_xml; case 0xe8b08520: numBytes = 1050; return colourscheme_light_xml; + case 0x938e96ec: numBytes = 20; return nothingtoseehere_txt; case 0xf11580d8: numBytes = 1155; return offlinepage_html; case 0xd6bb7d1d: numBytes = 14361; return projucer_EULA_txt; case 0xa41e649d: numBytes = 2842; return RecentFilesMenuTemplate_nib; @@ -7571,6 +7578,7 @@ const char* namedResourceList[] = "jucer_PIPMain_cpp", "colourscheme_dark_xml", "colourscheme_light_xml", + "nothingtoseehere_txt", "offlinepage_html", "projucer_EULA_txt", "RecentFilesMenuTemplate_nib" diff --git a/extras/Projucer/JuceLibraryCode/BinaryData.h b/extras/Projucer/JuceLibraryCode/BinaryData.h index 911711796e..5a86497df4 100644 --- a/extras/Projucer/JuceLibraryCode/BinaryData.h +++ b/extras/Projucer/JuceLibraryCode/BinaryData.h @@ -173,6 +173,9 @@ namespace BinaryData extern const char* colourscheme_light_xml; const int colourscheme_light_xmlSize = 1050; + extern const char* nothingtoseehere_txt; + const int nothingtoseehere_txtSize = 20; + extern const char* offlinepage_html; const int offlinepage_htmlSize = 1155; @@ -186,7 +189,7 @@ namespace BinaryData extern const char* namedResourceList[]; // Number of elements in the namedResourceList array. - const int namedResourceListSize = 58; + const int namedResourceListSize = 59; // If you provide the name of one of the binary resource variables above, this function will // return the corresponding data and its size (or a null pointer if the name isn't found). diff --git a/extras/Projucer/JuceLibraryCode/JuceHeader.h b/extras/Projucer/JuceLibraryCode/JuceHeader.h index c3872d9833..d55e0d89bd 100644 --- a/extras/Projucer/JuceLibraryCode/JuceHeader.h +++ b/extras/Projucer/JuceLibraryCode/JuceHeader.h @@ -14,6 +14,7 @@ #include "AppConfig.h" +#include #include #include #include diff --git a/extras/Projucer/JuceLibraryCode/include_juce_analytics.cpp b/extras/Projucer/JuceLibraryCode/include_juce_analytics.cpp new file mode 100644 index 0000000000..3dfd4d2179 --- /dev/null +++ b/extras/Projucer/JuceLibraryCode/include_juce_analytics.cpp @@ -0,0 +1,9 @@ +/* + + IMPORTANT! This file is auto-generated each time you save your + project - if you alter its contents, your changes may be overwritten! + +*/ + +#include "AppConfig.h" +#include diff --git a/extras/Projucer/Projucer.jucer b/extras/Projucer/Projucer.jucer index 5c32876fac..0f51731ccd 100644 --- a/extras/Projucer/Projucer.jucer +++ b/extras/Projucer/Projucer.jucer @@ -25,6 +25,7 @@ + + + @@ -78,6 +81,7 @@ + + @@ -110,8 +115,8 @@ compile="0" resource="0" file="Source/Application/Windows/jucer_EditorColourSchemeWindowComponent.h"/> - + + + @@ -246,13 +255,15 @@ resource="1" file="Source/BinaryData/Templates/jucer_OpenGLComponentTemplate.cpp"/> - + - @@ -622,10 +633,10 @@ - - + - @@ -700,6 +711,7 @@ + diff --git a/extras/Projucer/Source/Application/jucer_Application.cpp b/extras/Projucer/Source/Application/jucer_Application.cpp index 72725c7d29..ed1e614e90 100644 --- a/extras/Projucer/Source/Application/jucer_Application.cpp +++ b/extras/Projucer/Source/Application/jucer_Application.cpp @@ -171,6 +171,12 @@ void ProjucerApplication::handleAsyncUpdate() #endif versionChecker = new LatestVersionChecker(); + + if (licenseController != nullptr) + { + setAnalyticsEnabled (licenseController->getState().applicationUsageDataState == LicenseState::ApplicationUsageData::enabled); + Analytics::getInstance()->logEvent ("Startup", {}, ProjucerAnalyticsEvent::appEvent); + } } void ProjucerApplication::initialiseWindows (const String& commandLine) @@ -232,6 +238,8 @@ void ProjucerApplication::shutdown() Logger::writeToLog ("Shutdown"); deleteLogger(); + + Analytics::getInstance()->logEvent ("Shutdown", {}, ProjucerAnalyticsEvent::appEvent); } struct AsyncQuitRetrier : private Timer @@ -669,6 +677,11 @@ void ProjucerApplication::findAndLaunchExample (int selectedIndex) jassert (example != File()); findWindowAndOpenPIP (example); + + StringPairArray data; + data.set ("label", example.getFileNameWithoutExtension()); + + Analytics::getInstance()->logEvent ("Example Opened", data, ProjucerAnalyticsEvent::exampleEvent); } File ProjucerApplication::findDemoRunnerExecutable() const noexcept @@ -765,6 +778,11 @@ void ProjucerApplication::launchDemoRunner() AlertWindow::showMessageBoxAsync (AlertWindow::WarningIcon, "Error", "There was an error opening the Demo Runner file."); succeeded = false; } + + StringPairArray data; + data.set ("label", succeeded ? "Success" : "Failure"); + + Analytics::getInstance()->logEvent ("Launch DemoRunner", data, ProjucerAnalyticsEvent::exampleEvent); } else if (findDemoRunnerProject() != File()) { @@ -784,6 +802,11 @@ void ProjucerApplication::launchDemoRunner() { demoRunnerAlert.reset (nullptr); + StringPairArray data; + data.set ("label", retVal == 1 ? "Opened" : "Cancelled"); + + Analytics::getInstance()->logEvent ("Open DemoRunner Project", data, ProjucerAnalyticsEvent::exampleEvent); + if (retVal == 1) { auto projectFile = findDemoRunnerProject(); @@ -1286,6 +1309,42 @@ void ProjucerApplication::deleteTemporaryFiles() const noexcept tempDirectory.deleteRecursively(); } +void ProjucerApplication::setAnalyticsEnabled (bool enabled) +{ + resetAnalytics(); + + if (enabled) + setupAnalytics(); +} + +void ProjucerApplication::resetAnalytics() noexcept +{ + auto analyticsInstance = Analytics::getInstance(); + + analyticsInstance->setUserId ({}); + analyticsInstance->setUserProperties ({}); + analyticsInstance->getDestinations().clear(); +} + +void ProjucerApplication::setupAnalytics() +{ + Analytics::getInstance()->addDestination (new ProjucerAnalyticsDestination()); + + auto deviceString = SystemStats::getDeviceIdentifiers().joinIntoString (":"); + auto deviceIdentifier = String::toHexString (deviceString.hashCode64()); + + Analytics::getInstance()->setUserId (deviceIdentifier); + + StringPairArray userData; + userData.set ("cd1", getApplicationName()); + userData.set ("cd2", getApplicationVersion()); + userData.set ("cd3", SystemStats::getDeviceDescription()); + userData.set ("cd4", deviceString); + userData.set ("cd5", SystemStats::getOperatingSystemName()); + + Analytics::getInstance()->setUserProperties (userData); +} + void ProjucerApplication::selectEditorColourSchemeWithName (const String& schemeName) { auto& appearanceSettings = getAppSettings().appearance; diff --git a/extras/Projucer/Source/Application/jucer_Application.h b/extras/Projucer/Source/Application/jucer_Application.h index faace6ca63..7df6fad6bb 100644 --- a/extras/Projucer/Source/Application/jucer_Application.h +++ b/extras/Projucer/Source/Application/jucer_Application.h @@ -32,6 +32,7 @@ #include "../CodeEditor/jucer_SourceCodeEditor.h" #include "../Utility/UI/jucer_ProjucerLookAndFeel.h" #include "../Licenses/jucer_LicenseController.h" +#include "jucer_ProjucerAnalytics.h" struct ChildProcessCache; @@ -129,6 +130,9 @@ public: static bool isEditorColourSchemeADefaultScheme (const StringArray& schemes, int editorColourSchemeIndex); static int getEditorColourSchemeForGUIColourScheme (const StringArray& schemes, int guiColourSchemeIndex); + //============================================================================== + void setAnalyticsEnabled (bool); + //============================================================================== ProjucerLookAndFeel lookAndFeel; @@ -187,6 +191,9 @@ private: ChildProcess makeProcess; #endif + void resetAnalytics() noexcept; + void setupAnalytics(); + //============================================================================== void setColourScheme (int index, bool saveSetting); diff --git a/extras/Projucer/Source/Application/jucer_ProjucerAnalytics.cpp b/extras/Projucer/Source/Application/jucer_ProjucerAnalytics.cpp new file mode 100644 index 0000000000..4ae958f761 --- /dev/null +++ b/extras/Projucer/Source/Application/jucer_ProjucerAnalytics.cpp @@ -0,0 +1,245 @@ +/* + ============================================================================== + + This file is part of the JUCE library. + Copyright (c) 2017 - ROLI Ltd. + + JUCE is an open source library subject to commercial or open-source + licensing. + + By using JUCE, you agree to the terms of both the JUCE 5 End-User License + Agreement and JUCE 5 Privacy Policy (both updated and effective as of the + 27th April 2017). + + End User License Agreement: www.juce.com/juce-5-licence + Privacy Policy: www.juce.com/juce-5-privacy-policy + + Or: You may also use this code under the terms of the GPL v3 (see + www.gnu.org/licenses). + + JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER + EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE + DISCLAIMED. + + ============================================================================== +*/ + +#include "jucer_ProjucerAnalytics.h" + +//============================================================================== +ProjucerAnalyticsDestination::ProjucerAnalyticsDestination() + : ThreadedAnalyticsDestination ("ProjucerAnalyticsThread") +{ + { + MemoryOutputStream mo; + if (Base64::convertFromBase64 (mo, BinaryData::nothingtoseehere_txt)) + apiKey = mo.toString(); + } + + auto dataDir = File::getSpecialLocation (File::userApplicationDataDirectory) + .getChildFile ("Projucer") + .getChildFile ("Analytics"); + + if (! dataDir.exists()) + dataDir.createDirectory(); + + savedEventsFile = dataDir.getChildFile ("analytics_events.xml"); + + startAnalyticsThread (initialPeriodMs); +} + +ProjucerAnalyticsDestination::~ProjucerAnalyticsDestination() +{ + Thread::sleep (initialPeriodMs); + + stopAnalyticsThread (1000); +} + +//============================================================================== +static void setData (const AnalyticsDestination::AnalyticsEvent& event, StringPairArray& data) +{ + data.set ("ea", event.name); + + if (event.parameters.getAllKeys().contains ("label")) + data.set ("el", event.parameters.getValue ("label", {})); + + data.addArray (event.userProperties); +} + +bool ProjucerAnalyticsDestination::logBatchedEvents (const Array& events) +{ + String appData ("v=1&aip=1&tid=" + apiKey); + + StringArray postData; + + for (auto& event : events) + { + StringPairArray data; + + data.set ("t", "event"); + data.set ("cid", event.userID); + + switch (event.eventType) + { + case ProjucerAnalyticsEvent::appEvent: + { + data.set ("ec", "App"); + setData (event, data); + + break; + } + + case ProjucerAnalyticsEvent::projectEvent: + { + data.set ("ec", "Project"); + setData (event, data); + + break; + } + + case ProjucerAnalyticsEvent::userEvent: + { + data.set ("ec", "User"); + setData (event, data); + + break; + } + + case ProjucerAnalyticsEvent::exampleEvent: + { + data.set ("ec", "Example"); + setData (event, data); + + break; + } + + default: + { + // unknown event type! + jassertfalse; + break; + } + } + + StringArray eventData; + + for (auto& key : data.getAllKeys()) + eventData.add (key + "=" + URL::addEscapeChars (data[key], true)); + + postData.add (appData + "&" + eventData.joinIntoString ("&")); + } + + auto url = URL ("https://www.google-analytics.com/batch") + .withPOSTData (postData.joinIntoString ("\n")); + + { + const ScopedLock lock (webStreamCreation); + + if (shouldExit) + return false; + + webStream.reset (new WebInputStream (url, true)); + } + + auto success = webStream->connect (nullptr); + + // Do an exponential backoff if we failed to connect. + if (success) + periodMs = initialPeriodMs; + else + periodMs *= 2; + + setBatchPeriod (periodMs); + + return success; +} + +void ProjucerAnalyticsDestination::stopLoggingEvents() +{ + const ScopedLock lock (webStreamCreation); + + shouldExit = true; + + if (webStream.get() != nullptr) + webStream->cancel(); +} + +//============================================================================== +void ProjucerAnalyticsDestination::saveUnloggedEvents (const std::deque& eventsToSave) +{ + XmlDocument previouslySavedEvents (savedEventsFile); + std::unique_ptr xml (previouslySavedEvents.getDocumentElement()); + + if (xml.get() == nullptr || xml->getTagName() != "events") + xml.reset (new XmlElement ("events")); + + for (auto& event : eventsToSave) + { + auto* xmlEvent = new XmlElement ("google_analytics_event"); + xmlEvent->setAttribute ("name", event.name); + xmlEvent->setAttribute ("type", event.eventType); + xmlEvent->setAttribute ("timestamp", (int) event.timestamp); + xmlEvent->setAttribute ("user_id", event.userID); + + auto* parameters = new XmlElement ("parameters"); + + for (auto& key : event.parameters.getAllKeys()) + parameters->setAttribute (key, event.parameters[key]); + + xmlEvent->addChildElement (parameters); + + auto* userProperties = new XmlElement ("user_properties"); + + for (auto& key : event.userProperties.getAllKeys()) + userProperties->setAttribute (key, event.userProperties[key]); + + xmlEvent->addChildElement (userProperties); + + xml->addChildElement (xmlEvent); + } + + xml->writeToFile (savedEventsFile, {}); +} + +void ProjucerAnalyticsDestination::restoreUnloggedEvents (std::deque& restoredEventQueue) +{ + XmlDocument savedEvents (savedEventsFile); + std::unique_ptr xml (savedEvents.getDocumentElement()); + + if (xml.get() == nullptr || xml->getTagName() != "events") + return; + + auto numEvents = xml->getNumChildElements(); + + for (int iEvent = 0; iEvent < numEvents; ++iEvent) + { + auto* xmlEvent = xml->getChildElement (iEvent); + + StringPairArray parameters; + auto* xmlParameters = xmlEvent->getChildByName ("parameters"); + auto numParameters = xmlParameters->getNumAttributes(); + + for (int iParam = 0; iParam < numParameters; ++iParam) + parameters.set (xmlParameters->getAttributeName (iParam), + xmlParameters->getAttributeValue (iParam)); + + StringPairArray userProperties; + auto* xmlUserProperties = xmlEvent->getChildByName ("user_properties"); + auto numUserProperties = xmlUserProperties->getNumAttributes(); + + for (int iProp = 0; iProp < numUserProperties; ++iProp) + userProperties.set (xmlUserProperties->getAttributeName (iProp), + xmlUserProperties->getAttributeValue (iProp)); + + restoredEventQueue.push_back ({ + xmlEvent->getStringAttribute ("name"), + xmlEvent->getIntAttribute ("type"), + static_cast (xmlEvent->getIntAttribute ("timestamp")), + parameters, + xmlEvent->getStringAttribute ("user_id"), + userProperties + }); + } + + savedEventsFile.deleteFile(); +} diff --git a/extras/Projucer/Source/Application/jucer_ProjucerAnalytics.h b/extras/Projucer/Source/Application/jucer_ProjucerAnalytics.h new file mode 100644 index 0000000000..22bbdfedae --- /dev/null +++ b/extras/Projucer/Source/Application/jucer_ProjucerAnalytics.h @@ -0,0 +1,68 @@ +/* + ============================================================================== + + This file is part of the JUCE library. + Copyright (c) 2017 - ROLI Ltd. + + JUCE is an open source library subject to commercial or open-source + licensing. + + By using JUCE, you agree to the terms of both the JUCE 5 End-User License + Agreement and JUCE 5 Privacy Policy (both updated and effective as of the + 27th April 2017). + + End User License Agreement: www.juce.com/juce-5-licence + Privacy Policy: www.juce.com/juce-5-privacy-policy + + Or: You may also use this code under the terms of the GPL v3 (see + www.gnu.org/licenses). + + 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_Headers.h" + +//============================================================================== +enum ProjucerAnalyticsEvent +{ + appEvent, + projectEvent, + userEvent, + exampleEvent +}; + +//============================================================================== +class ProjucerAnalyticsDestination : public ThreadedAnalyticsDestination +{ +public: + ProjucerAnalyticsDestination(); + ~ProjucerAnalyticsDestination(); + + //============================================================================== + bool logBatchedEvents (const Array&) override; + void stopLoggingEvents() override; + + int getMaximumBatchSize() override { return 20; } + +private: + void saveUnloggedEvents (const std::deque&) override; + void restoreUnloggedEvents (std::deque&) override; + + //============================================================================== + String apiKey; + + const int initialPeriodMs = 1000; + int periodMs = initialPeriodMs; + + CriticalSection webStreamCreation; + bool shouldExit = false; + std::unique_ptr webStream; + + File savedEventsFile; +}; diff --git a/extras/Projucer/Source/BinaryData/nothingtoseehere.txt b/extras/Projucer/Source/BinaryData/nothingtoseehere.txt new file mode 100644 index 0000000000..99a42c64ab --- /dev/null +++ b/extras/Projucer/Source/BinaryData/nothingtoseehere.txt @@ -0,0 +1 @@ +VUEtMTk3NTkzMTgtNA== \ No newline at end of file diff --git a/extras/Projucer/Source/ComponentEditor/UI/jucer_JucerDocumentEditor.cpp b/extras/Projucer/Source/ComponentEditor/UI/jucer_JucerDocumentEditor.cpp index b0aefe3dc2..a05aa28197 100644 --- a/extras/Projucer/Source/ComponentEditor/UI/jucer_JucerDocumentEditor.cpp +++ b/extras/Projucer/Source/ComponentEditor/UI/jucer_JucerDocumentEditor.cpp @@ -354,6 +354,12 @@ JucerDocumentEditor::JucerDocumentEditor (JucerDocument* const doc) refreshPropertiesPanel(); changeListenerCallback (nullptr); + + if (auto* project = document->getCppDocument().getProject()) + { + if (project->shouldSendGUIBuilderAnalyticsEvent()) + Analytics::getInstance()->logEvent ("GUI Builder", {}, ProjucerAnalyticsEvent::projectEvent); + } } } diff --git a/extras/Projucer/Source/Licenses/jucer_LicenseController.cpp b/extras/Projucer/Source/Licenses/jucer_LicenseController.cpp index 1dbeeb9e3e..4ab9d2d891 100644 --- a/extras/Projucer/Source/Licenses/jucer_LicenseController.cpp +++ b/extras/Projucer/Source/Licenses/jucer_LicenseController.cpp @@ -182,6 +182,8 @@ void LicenseController::setApplicationUsageDataState (LicenseState::ApplicationU if (state.applicationUsageDataState != newState) { state.applicationUsageDataState = newState; + ProjucerApplication::getApp().setAnalyticsEnabled (newState == LicenseState::ApplicationUsageData::enabled); + updateState (state); } } @@ -257,10 +259,20 @@ void LicenseController::updateState (const LicenseState& newState) { auto& props = ProjucerApplication::getApp().settings->getGlobalProperties(); + auto oldLicenseType = state.type; + state = newState; licenseStateToSettings (state, props); auto stateParam = getState(); listeners.call ([&] (StateChangedCallback& l) { l.licenseStateChanged (stateParam); }); + + if (oldLicenseType != state.type) + { + StringPairArray data; + data.set ("label", state.licenseTypeToString (state.type)); + + Analytics::getInstance()->logEvent ("License Type", data, ProjucerAnalyticsEvent::userEvent); + } } LicenseState LicenseController::licenseStateFromOldSettings (XmlElement* licenseXml) diff --git a/extras/Projucer/Source/Project/UI/Sidebar/jucer_ModuleTreeItems.h b/extras/Projucer/Source/Project/UI/Sidebar/jucer_ModuleTreeItems.h index de6eca2346..2f0a5d1f33 100644 --- a/extras/Projucer/Source/Project/UI/Sidebar/jucer_ModuleTreeItems.h +++ b/extras/Projucer/Source/Project/UI/Sidebar/jucer_ModuleTreeItems.h @@ -585,6 +585,7 @@ public: void handlePopupMenuResult (int resultCode) override { auto& modules = project.getModules(); + auto numModulesBefore = modules.getNumModules(); if (resultCode == 1001) { @@ -599,6 +600,14 @@ public: else if (resultCode < 400) modules.addModuleInteractive (getAvailableModulesInExporterPaths() [resultCode - 300]); } + + if (modules.getNumModules() == numModulesBefore + 1) + { + StringPairArray data; + data.set ("label", modules.getModuleID (modules.getNumModules() - 1)); + + Analytics::getInstance()->logEvent ("Module Added", data, ProjucerAnalyticsEvent::projectEvent); + } } StringArray getAvailableModulesInGlobalJucePath() diff --git a/extras/Projucer/Source/Project/UI/jucer_HeaderComponent.cpp b/extras/Projucer/Source/Project/UI/jucer_HeaderComponent.cpp index 9341178abf..1f191496a0 100644 --- a/extras/Projucer/Source/Project/UI/jucer_HeaderComponent.cpp +++ b/extras/Projucer/Source/Project/UI/jucer_HeaderComponent.cpp @@ -248,6 +248,14 @@ void HeaderComponent::timerCallback() } //====================================================================== +static void sendProjectButtonAnalyticsEvent (StringRef label) +{ + StringPairArray data; + data.set ("label", label); + + Analytics::getInstance()->logEvent ("Project Button", data, ProjucerAnalyticsEvent::projectEvent); +} + void HeaderComponent::initialiseButtons() noexcept { auto& icons = getIcons(); @@ -255,6 +263,8 @@ void HeaderComponent::initialiseButtons() noexcept addAndMakeVisible (projectSettingsButton = new IconButton ("Project Settings", &icons.settings)); projectSettingsButton->onClick = [this] { + sendProjectButtonAnalyticsEvent ("Project Settings"); + if (auto* pcc = findParentComponentOfClass()) pcc->showProjectSettings(); }; @@ -263,6 +273,8 @@ void HeaderComponent::initialiseButtons() noexcept saveAndOpenInIDEButton->isIDEButton = true; saveAndOpenInIDEButton->onClick = [this] { + sendProjectButtonAnalyticsEvent ("Save and Open in IDE (" + exporterBox.getText() + ")"); + if (auto* pcc = findParentComponentOfClass()) pcc->openInSelectedIDE (true); }; @@ -271,6 +283,8 @@ void HeaderComponent::initialiseButtons() noexcept userSettingsButton->isUserButton = true; userSettingsButton->onClick = [this] { + sendProjectButtonAnalyticsEvent ("User Settings"); + if (auto* pcc = findParentComponentOfClass()) showUserSettings(); }; @@ -278,6 +292,8 @@ void HeaderComponent::initialiseButtons() noexcept addAndMakeVisible (runAppButton = new IconButton ("Run Application", &icons.play)); runAppButton->onClick = [this] { + sendProjectButtonAnalyticsEvent ("Run Application"); + if (childProcess != nullptr) childProcess->launchApp(); }; diff --git a/extras/Projucer/Source/Project/UI/jucer_ProjectContentComponent.cpp b/extras/Projucer/Source/Project/UI/jucer_ProjectContentComponent.cpp index f001372451..1f0ce9363e 100644 --- a/extras/Projucer/Source/Project/UI/jucer_ProjectContentComponent.cpp +++ b/extras/Projucer/Source/Project/UI/jucer_ProjectContentComponent.cpp @@ -666,7 +666,14 @@ static void newExporterMenuCallback (int result, ProjectContentComponent* comp) auto exporterName= ProjectExporter::getExporterNames() [result - 1]; if (exporterName.isNotEmpty()) + { p->addNewExporter (exporterName); + + StringPairArray data; + data.set ("label", exporterName); + + Analytics::getInstance()->logEvent ("Exporter Added", data, ProjucerAnalyticsEvent::projectEvent); + } } } } @@ -1164,6 +1171,11 @@ void ProjectContentComponent::setBuildEnabled (bool isEnabled, bool displayError LiveBuildProjectSettings::setBuildDisabled (*project, ! isEnabled); killChildProcess(); refreshTabsIfBuildStatusChanged(); + + StringPairArray data; + data.set ("label", isEnabled ? "Enabled" : "Disabled"); + + Analytics::getInstance()->logEvent ("Live-Build", data, ProjucerAnalyticsEvent::projectEvent); } } @@ -1187,6 +1199,11 @@ void ProjectContentComponent::handleCrash (const String& message) setBuildEnabled (false, true); showBuildTab(); } + + StringPairArray data; + data.set ("label", "Crash"); + + Analytics::getInstance()->logEvent ("Live-Build", data, ProjucerAnalyticsEvent::projectEvent); } bool ProjectContentComponent::isBuildEnabled() const diff --git a/extras/Projucer/Source/Project/jucer_Module.cpp b/extras/Projucer/Source/Project/jucer_Module.cpp index 986fde54ef..830331b1fb 100644 --- a/extras/Projucer/Source/Project/jucer_Module.cpp +++ b/extras/Projucer/Source/Project/jucer_Module.cpp @@ -28,6 +28,7 @@ #include "jucer_Module.h" #include "../ProjectSaving/jucer_ProjectSaver.h" #include "../ProjectSaving/jucer_ProjectExport_Xcode.h" +#include "../Application/jucer_ProjucerAnalytics.h" //============================================================================== static var parseModuleDesc (const StringArray& lines) @@ -799,6 +800,11 @@ void EnabledModuleList::addModule (const File& moduleFolder, bool copyLocally, b for (Project::ExporterIterator exporter (project); exporter.next();) exporter->getPathForModuleValue (moduleID) = path.toUnixStyle(); + + StringPairArray data; + data.set ("label", moduleID); + + Analytics::getInstance()->logEvent ("Module Added", data, ProjucerAnalyticsEvent::projectEvent); } } } diff --git a/extras/Projucer/Source/Project/jucer_Project.cpp b/extras/Projucer/Source/Project/jucer_Project.cpp index 05033e3ae1..b9ef72f66e 100644 --- a/extras/Projucer/Source/Project/jucer_Project.cpp +++ b/extras/Projucer/Source/Project/jucer_Project.cpp @@ -501,6 +501,14 @@ void Project::moveTemporaryDirectory (const File& newParentDirectory) } //============================================================================== +static void sendProjectSettingAnalyticsEvent (StringRef label) +{ + StringPairArray data; + data.set ("label", label); + + Analytics::getInstance()->logEvent ("Project Setting", data, ProjucerAnalyticsEvent::projectEvent); +} + void Project::valueTreePropertyChanged (ValueTree& tree, const Identifier& property) { if (tree.getRoot() == tree) @@ -508,6 +516,8 @@ void Project::valueTreePropertyChanged (ValueTree& tree, const Identifier& prope if (property == Ids::projectType) { sendChangeMessage(); + + sendProjectSettingAnalyticsEvent ("Project Type = " + projectTypeValue.get().toString()); } else if (property == Ids::name) { @@ -517,6 +527,10 @@ void Project::valueTreePropertyChanged (ValueTree& tree, const Identifier& prope { parsedPreprocessorDefs = parsePreprocessorDefs (preprocessorDefsValue.get()); } + else if (property == Ids::cppLanguageStandard) + { + sendProjectSettingAnalyticsEvent ("C++ Standard = " + cppStandardValue.get().toString()); + } changed(); } @@ -1561,6 +1575,18 @@ String Project::getUniqueTargetFolderSuffixForExporter (const String& exporterNa return "_" + String (num); } +//============================================================================== +bool Project::shouldSendGUIBuilderAnalyticsEvent() noexcept +{ + if (! hasSentGUIBuilderAnalyticsEvent) + { + hasSentGUIBuilderAnalyticsEvent = true; + return true; + } + + return false; +} + //============================================================================== String Project::getFileTemplate (const String& templateName) { diff --git a/extras/Projucer/Source/Project/jucer_Project.h b/extras/Projucer/Source/Project/jucer_Project.h index 5c67275f79..caddd7c238 100644 --- a/extras/Projucer/Source/Project/jucer_Project.h +++ b/extras/Projucer/Source/Project/jucer_Project.h @@ -344,6 +344,9 @@ public: void setOpenInIDEAfterSaving (bool open) noexcept { openInIDEAfterSaving = open; } bool shouldOpenInIDEAfterSaving() const noexcept { return openInIDEAfterSaving; } + //============================================================================== + bool shouldSendGUIBuilderAnalyticsEvent() noexcept; + private: ValueTree projectRoot { Ids::JUCERPROJECT }; diff --git a/extras/Projucer/Source/Wizards/jucer_NewProjectWizard.h b/extras/Projucer/Source/Wizards/jucer_NewProjectWizard.h index c6cb9c21b9..39a65b473d 100644 --- a/extras/Projucer/Source/Wizards/jucer_NewProjectWizard.h +++ b/extras/Projucer/Source/Wizards/jucer_NewProjectWizard.h @@ -158,6 +158,11 @@ struct NewProjectWizard return nullptr; } + StringPairArray data; + data.set ("label", "Project Type = " + project->getProjectTypeString()); + + Analytics::getInstance()->logEvent ("Project Setting", data, ProjucerAnalyticsEvent::projectEvent); + return project.release(); }