1 /*
2 	This file is part of Warzone 2100.
3 	Copyright (C) 2020-2021  Warzone 2100 Project
4 
5 	Warzone 2100 is free software; you can redistribute it and/or modify
6 	it under the terms of the GNU General Public License as published by
7 	the Free Software Foundation; either version 2 of the License, or
8 	(at your option) any later version.
9 
10 	Warzone 2100 is distributed in the hope that it will be useful,
11 	but WITHOUT ANY WARRANTY; without even the implied warranty of
12 	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 	GNU General Public License for more details.
14 
15 	You should have received a copy of the GNU General Public License
16 	along with Warzone 2100; if not, write to the Free Software
17 	Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
18 */
19 /**
20  * @file
21  * Definitions for scrollable JSON table functions.
22  */
23 
24 #ifndef __INCLUDED_LIB_WIDGET_JSONTABLE_H__
25 #define __INCLUDED_LIB_WIDGET_JSONTABLE_H__
26 
27 #include "widget.h"
28 #include "form.h"
29 #include <3rdparty/json/json.hpp>
30 
31 #include <vector>
32 #include <memory>
33 #include <unordered_map>
34 
35 class ScrollableTableWidget;
36 
37 class PathBarWidget : public WIDGET
38 {
39 public:
40 	typedef std::function<void (PathBarWidget&, size_t componentIndex)> ONCLICK_PATH_HANDLER;
41 public:
PathBarWidget(const std::string & pathSeparator)42 	PathBarWidget(const std::string& pathSeparator)
43 	: WIDGET()
44 	, pathSeparatorStr(pathSeparator)
45 	{ }
~PathBarWidget()46 	~PathBarWidget() {}
47 public:
48 	static std::shared_ptr<PathBarWidget> make(const std::string& pathSeparator);
49 
50 	void display(int xOffset, int yOffset) override;
geometryChanged()51 	void geometryChanged() override { relayoutComponentButtons(); }
52 public:
53 	void pushPathComponent(const std::string& pathComponent);
54 	void popPathComponents(size_t numComponents = 1);
55 	void reset();
56 	const std::vector<std::string>& currentPath() const;
57 	std::string currentPathStr() const;
numPathComponents()58 	size_t numPathComponents() const { return pathComponents.size(); }
setOnClickPath(const ONCLICK_PATH_HANDLER & func)59 	void setOnClickPath(const ONCLICK_PATH_HANDLER& func)
60 	{
61 		onClickPath = func;
62 	}
63 private:
64 	std::shared_ptr<W_BUTTON> createPathComponentButton(const std::string& pathComponent, size_t newComponentIndex);
65 	void relayoutComponentButtons();
66 private:
67 	std::string pathSeparatorStr;
68 	std::shared_ptr<W_LABEL> pathSeparator;
69 	std::vector<std::string> pathComponents;
70 	std::unordered_map<size_t, std::shared_ptr<W_BUTTON>> componentButtons;
71 	std::shared_ptr<W_LABEL> ellipsis;
72 	ONCLICK_PATH_HANDLER onClickPath;
73 };
74 
75 class JSONTableWidget : public W_FORM
76 {
77 public:
78 	typedef std::function<void (JSONTableWidget&)> CallbackFunc;
79 	enum class SpecialJSONStringTypes
80 	{
81 		TYPE_DESCRIPTION
82 	};
83 	typedef std::unordered_map<std::string, SpecialJSONStringTypes> SpecialStrings;
84 public:
JSONTableWidget()85 	JSONTableWidget() : W_FORM() {}
86 	~JSONTableWidget();
87 
88 public:
89 	static std::shared_ptr<JSONTableWidget> make(const std::string& title = std::string());
90 	void updateData(const nlohmann::ordered_json& json, bool tryToPreservePath = false, const SpecialStrings& specialStrings = SpecialStrings());
91 	void updateData(const nlohmann::json& json, bool tryToPreservePath = false, const SpecialStrings& specialStrings = SpecialStrings());
92 	bool pushJSONPath(const std::string& keyInCurrentJSONPointer);
93 	size_t popJSONPath(size_t numLevels = 1);
94 	std::string currentJSONPathStr() const;
95 	std::string dumpDataAtCurrentPath() const;
96 	void setUpdateButtonFunc(const CallbackFunc& updateButtonFunc, optional<UDWORD> automaticUpdateInterval = nullopt);
97 	void setAutomaticUpdateInterval(optional<UDWORD> newAutomaticUpdateInterval = nullopt);
98 
99 public:
100 	virtual void display(int xOffset, int yOffset) override;
101 	virtual void geometryChanged() override;
102 	virtual void screenSizeDidChange(int oldWidth, int oldHeight, int newWidth, int newHeight) override;
103 	virtual void run(W_CONTEXT *psContext) override;
104 
105 private:
106 	void updateData_Internal(const std::function<void ()>& setJsonFunc, bool tryToPreservePath, const SpecialStrings& specialStrings);
107 	void setSpecialStrings_Internal(const SpecialStrings& specialStrings);
108 	bool rootJsonHasExpandableChildren() const;
109 	void refreshUpdateButtonState();
110 	void resizeColumnWidths(bool overrideUserColumnSizing);
111 	void rebuildTableFromJSON(bool overrideUserColumnSizing);
112 	bool pushJSONPath(const std::vector<std::string>& pathInCurrentJSONPointer, bool overrideUserColumnSizing);
113 	std::vector<std::string> currentPathFromRoot() const;
114 	void resetPath();
115 	void displayOptionsOverlay(const std::shared_ptr<WIDGET>& psParent);
116 	std::shared_ptr<WIDGET> createOptionsPopoverForm();
117 
118 private:
119 	CallbackFunc							updateButtonFunc;
120 	optional<UDWORD>						automaticUpdateInterval;
121 	UDWORD									lastUpdateTime;
122 
123 	std::shared_ptr<W_LABEL>				titleLabel;
124 	std::shared_ptr<PathBarWidget>			pathBar;
125 	std::shared_ptr<ScrollableTableWidget>	table;
126 
127 	std::shared_ptr<W_BUTTON>				optionsButton;
128 	std::shared_ptr<W_BUTTON>				updateButton;
129 	std::shared_ptr<W_SCREEN>				optionsOverlayScreen;
130 
131 	optional<nlohmann::ordered_json>		_orderedjson;
132 	std::vector<nlohmann::ordered_json*>	_orderedjson_currentPointer;
133 
134 	optional<nlohmann::json>				_json;
135 	std::vector<nlohmann::json*>			_json_currentPointer;
136 
137 	SpecialStrings							_specialStrings;
138 
139 	std::vector<int>						currentMaxColumnWidths = {0,0,0};
140 	std::vector<std::string>				actualPushedPathComponents;
141 
142 private:
143 	template<typename json_type>
144 	friend void setTableToJson(const json_type& json, JSONTableWidget& jsonTable);
145 };
146 
147 #endif // __INCLUDED_LIB_WIDGET_JSONTABLE_H__
148