1 // -*- coding: utf-8 -*-
2 //
3 // AddonManager.hxx --- Manager class for FlightGear add-ons
4 // Copyright (C) 2017  Florent Rougon
5 //
6 // This program is free software; you can redistribute it and/or modify
7 // it under the terms of the GNU General Public License as published by
8 // the Free Software Foundation; either version 2 of the License, or
9 // (at your option) any later version.
10 //
11 // This program is distributed in the hope that it will be useful,
12 // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 // GNU General Public License for more details.
15 //
16 // You should have received a copy of the GNU General Public License along
17 // with this program; if not, write to the Free Software Foundation, Inc.,
18 // 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19 
20 #ifndef FG_ADDONMANAGER_HXX
21 #define FG_ADDONMANAGER_HXX
22 
23 #include <string>
24 #include <map>
25 #include <memory>               // std::unique_ptr, std::shared_ptr
26 #include <vector>
27 
28 #include <simgear/misc/sg_path.hxx>
29 #include <simgear/props/props.hxx>
30 
31 #include "addon_fwd.hxx"
32 #include "Addon.hxx"
33 #include "AddonVersion.hxx"
34 
35 namespace flightgear
36 {
37 
38 namespace addons
39 {
40 
41 class AddonManager
42 {
43 public:
44   AddonManager(const AddonManager&) = delete;
45   AddonManager& operator=(const AddonManager&) = delete;
46   AddonManager(AddonManager&&) = delete;
47   AddonManager& operator=(AddonManager&&) = delete;
48   // The instance is created by createInstance() -> private constructor
49   // but it should be deleted by its owning std::unique_ptr -> public destructor
50   ~AddonManager() = default;
51 
52   // Static creator
53   static const std::unique_ptr<AddonManager>& createInstance();
54   // Singleton accessor
55   static const std::unique_ptr<AddonManager>& instance();
56   // Reset the static smart pointer, i.e., shut down the AddonManager.
57   static void reset();
58 
59   // Register an add-on and return its id.
60   // 'addonPath': directory containing the add-on to register
61   //
62   // This comprises the following steps, where $path = addonPath.realpath():
63   //  - load add-on metadata from $path/addon-metadata.xml and register it
64   //    inside _idToAddonMap (this step is done via registerAddonMetadata());
65   //  - load $path/addon-config.xml into the Property Tree;
66   //  - append $path to the list of aircraft paths;
67   //  - make part of the add-on metadata available in the Property Tree under
68   //    the /addons node (/addons/by-id/<addonId>/{id,version,path,...});
69   //  - append a ref to the Addon instance to _registeredAddons.
70   std::string registerAddon(const SGPath& addonPath);
71   // Return the list of registered add-ons in registration order (which, BTW,
72   // is the same as load order).
73   std::vector<AddonRef> registeredAddons() const;
74   bool isAddonRegistered(const std::string& addonId) const;
75 
76   // A loaded add-on is one whose addon-main.nas file has been loaded. The
77   // returned vector is sorted by add-on id (cheap sorting based on UTF-8 code
78   // units, only guaranteed correct for ASCII chars).
79   std::vector<AddonRef> loadedAddons() const;
80   bool isAddonLoaded(const std::string& addonId) const;
81 
82   AddonRef getAddon(const std::string& addonId) const;
83   AddonVersionRef addonVersion(const std::string& addonId) const;
84   SGPath addonBasePath(const std::string& addonId) const;
85 
86   // Base node pertaining to the add-on in the Global Property Tree
87   SGPropertyNode_ptr addonNode(const std::string& addonId) const;
88 
89   // Add the 'menu' nodes defined by each registered add-on to
90   // /sim/menubar/default
91   void addAddonMenusToFGMenubar() const;
92 
93 private:
94   // Constructor called from createInstance() only
95   explicit AddonManager() = default;
96 
97   static void loadConfigFileIfExists(const SGPath& configFile);
98   // Register add-on metadata inside _idToAddonMap and return the add-on id
99   std::string registerAddonMetadata(const SGPath& addonPath);
100 
101   // Map each add-on id to the corresponding Addon instance.
102   std::map<std::string, AddonRef> _idToAddonMap;
103   // The order in _registeredAddons is the registration order.
104   std::vector<AddonRef> _registeredAddons;
105   // 0 for the first loaded add-on, 1 for the second, etc.
106   // Also note that add-ons are loaded in their registration order.
107   int _loadSequenceNumber = 0;
108 };
109 
110 } // of namespace addons
111 
112 } // of namespace flightgear
113 
114 #endif  // of FG_ADDONMANAGER_HXX
115