1/*
2 * Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de.
3 * Copyright 2016, Rene Gollent, rene@gollent.com.
4 * Distributed under the terms of the MIT License.
5 */
6
7
8#include "DebuggerSettingsManager.h"
9
10#include <new>
11
12#include <Directory.h>
13#include <File.h>
14#include <FindDirectory.h>
15
16#include <AutoDeleter.h>
17#include <AutoLocker.h>
18
19#include "TeamSettings.h"
20
21
22static const char* const kSettingsDirPath		= "Debugger";
23static const char* const kGlobalSettingsName	= "Global";
24static const int32 kMaxRecentTeamSettings		= 10;
25
26
27DebuggerSettingsManager::DebuggerSettingsManager()
28	:
29	SettingsManager(),
30	fLock("settings manager"),
31	fRecentTeamSettings(kMaxRecentTeamSettings, true),
32	fUiSettingsFactory(NULL)
33{
34}
35
36
37DebuggerSettingsManager::~DebuggerSettingsManager()
38{
39	_Unset();
40}
41
42
43status_t
44DebuggerSettingsManager::Init(TeamUiSettingsFactory* factory)
45{
46	// check the lock
47	status_t error = fLock.InitCheck();
48	if (error != B_OK)
49		return error;
50
51	fUiSettingsFactory = factory;
52
53	// get and create our settings directory
54	if (find_directory(B_USER_SETTINGS_DIRECTORY, &fSettingsPath, true) == B_OK
55		&& fSettingsPath.Append(kSettingsDirPath) == B_OK
56		&& create_directory(fSettingsPath.Path(), 0700) == B_OK
57		&& fSettingsPath.Append(kGlobalSettingsName) == B_OK) {
58		// load the settings
59		_LoadSettings();
60	} else {
61		// something went wrong -- clear the path
62		fSettingsPath.Unset();
63	}
64
65	return B_OK;
66}
67
68
69status_t
70DebuggerSettingsManager::LoadTeamSettings(const char* teamName, TeamSettings& settings)
71{
72	AutoLocker<BLocker> locker(fLock);
73
74	int32 index = _TeamSettingsIndex(teamName);
75	if (index < 0)
76		return B_ENTRY_NOT_FOUND;
77
78	try {
79		settings = *fRecentTeamSettings.ItemAt(index);
80		return B_OK;
81	} catch (std::bad_alloc&) {
82		return B_NO_MEMORY;
83	}
84}
85
86
87status_t
88DebuggerSettingsManager::SaveTeamSettings(const TeamSettings& _settings)
89{
90	AutoLocker<BLocker> locker(fLock);
91
92	TeamSettings* settings;
93	int32 index = _TeamSettingsIndex(_settings.TeamName());
94	if (index >= 0) {
95		settings = fRecentTeamSettings.RemoveItemAt(index);
96	} else {
97		settings = new(std::nothrow) TeamSettings;
98		if (settings == NULL)
99			return B_NO_MEMORY;
100
101		// enforce recent limit
102		while (fRecentTeamSettings.CountItems() >= kMaxRecentTeamSettings)
103			delete fRecentTeamSettings.RemoveItemAt(0);
104
105	}
106	ObjectDeleter<TeamSettings> settingsDeleter(settings);
107
108	try {
109		*settings = _settings;
110		if (!fRecentTeamSettings.AddItem(settings))
111			return B_NO_MEMORY;
112		settingsDeleter.Detach();
113
114		return _SaveSettings();
115	} catch (std::bad_alloc&) {
116		return B_NO_MEMORY;
117	}
118}
119
120
121void
122DebuggerSettingsManager::_Unset()
123{
124	fRecentTeamSettings.MakeEmpty();
125}
126
127
128status_t
129DebuggerSettingsManager::_LoadSettings()
130{
131	_Unset();
132
133	if (fSettingsPath.Path() == NULL)
134		return B_ENTRY_NOT_FOUND;
135
136	// read the settings file
137	BFile file;
138	status_t error = file.SetTo(fSettingsPath.Path(), B_READ_ONLY);
139	if (error != B_OK)
140		return error;
141
142	BMessage archive;
143	error = archive.Unflatten(&file);
144	if (error != B_OK)
145		return error;
146
147	// unarchive the recent team settings
148	BMessage childArchive;
149	for (int32 i = 0; archive.FindMessage("teamSettings", i, &childArchive)
150			== B_OK; i++) {
151		TeamSettings* settings = new(std::nothrow) TeamSettings;
152		if (settings == NULL)
153			return B_NO_MEMORY;
154
155		error = settings->SetTo(childArchive, *fUiSettingsFactory);
156		if (error != B_OK) {
157			delete settings;
158			continue;
159		}
160
161		if (!fRecentTeamSettings.AddItem(settings)) {
162			delete settings;
163			return B_NO_MEMORY;
164		}
165	}
166
167	return B_OK;
168}
169
170
171status_t
172DebuggerSettingsManager::_SaveSettings()
173{
174	if (fSettingsPath.Path() == NULL)
175		return B_ENTRY_NOT_FOUND;
176
177	// archive the recent team settings
178	BMessage archive;
179	for (int32 i = 0; TeamSettings* settings = fRecentTeamSettings.ItemAt(i);
180			i++) {
181		BMessage childArchive;
182		status_t error = settings->WriteTo(childArchive);
183		if (error != B_OK)
184			return error;
185
186		error = archive.AddMessage("teamSettings", &childArchive);
187		if (error != B_OK)
188			return error;
189	}
190
191	// open the settings file
192	BFile file;
193	status_t error = file.SetTo(fSettingsPath.Path(),
194		B_WRITE_ONLY | B_CREATE_FILE | B_ERASE_FILE);
195	if (error != B_OK)
196		return error;
197
198	return archive.Flatten(&file);
199}
200
201
202int32
203DebuggerSettingsManager::_TeamSettingsIndex(const char* teamName) const
204{
205	for (int32 i = 0; TeamSettings* settings = fRecentTeamSettings.ItemAt(i);
206			i++) {
207		if (settings->TeamName() == teamName)
208			return i;
209	}
210
211	return -1;
212}
213