-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathProjectsService.cs
234 lines (209 loc) · 8.08 KB
/
ProjectsService.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel.Composition;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Xml;
namespace HAF {
[Export(typeof(IProjectsService)), PartCreationPolicy(CreationPolicy.Shared)]
public class ProjectsService: Service, IProjectsService {
private Event onProjectsChanged = new Event(nameof(OnProjectsChanged));
public IReadOnlyEvent OnProjectsChanged => this.onProjectsChanged;
public ICompoundState MayChangeProject { get; private set; } = new CompoundState();
public IRelayCommand DoRefresh { get; private set; }
public IRelayCommand<IProject> DoLoadProject { get; private set; }
public IRelayCommand<IProject> DoDeleteProject { get; private set; }
public IRelayCommand<IProject> DoSetDefaultProject { get; private set; }
public IRelayCommand DoOpenDirectory { get; private set; }
public IRelayCommand DoAddProject { get; private set; }
public IRelayCommand DoSaveProject { get; private set; }
private readonly RangeObservableCollection<IProject> projects = new RangeObservableCollection<IProject>();
public IReadOnlyObservableCollection<IProject> Projects => this.projects;
private List<IService> configuredServices = new List<IService>();
public IReadOnlyList<IService> ConfiguredServices => this.configuredServices;
private IProject currentProject = null;
public IProject CurrentProject {
get { return this.currentProject; }
set {
if(this.SetValue(ref this.currentProject, value)) {
foreach(var project in this.projects) {
project.IsCurrent = project == value;
}
this.DoLoadProject.RaiseCanExecuteChanged();
this.DoDeleteProject.RaiseCanExecuteChanged();
this.DoSaveProject.RaiseCanExecuteChanged();
this.onProjectsChanged.Fire();
}
}
}
private IProject defaultProject = null;
public IProject DefaultProject {
get { return this.defaultProject; }
set {
if(this.SetValue(ref this.defaultProject, value)) {
foreach(var project in this.projects) {
project.IsDefault = project == value;
}
this.DoSetDefaultProject.RaiseCanExecuteChanged();
this.onProjectsChanged.Fire();
}
}
}
private string editName = null;
public string EditName {
get { return this.editName; }
set {
if(this.SetValue(ref this.editName, value)) {
this.DoAddProject.RaiseCanExecuteChanged();
}
}
}
public async Task LoadProjects(string defaultProjectName) {
// get potential projects
var projects = Directory.GetFiles(Core.ConfigurationDirectory, "*.xml", SearchOption.TopDirectoryOnly)
.Where(filePath => {
// filter out non-project xmls
try {
var document = new XmlDocument();
document.Load(filePath);
if(document.SelectSingleNode("/project") != null) {
return true;
}
} catch { }
return false;
})
.Select(p => new Project() {
Name = Path.GetFileNameWithoutExtension(p),
FilePath = p,
});
this.projects.Clear();
this.projects.AddRange(projects);
IProject defaultProject = null;
// add default project if none exist
if(this.projects.Count == 0) {
var project = new Project() {
Name = "default project",
FilePath = Path.Combine(Core.ConfigurationDirectory, "default project.xml"),
};
this.projects.Add(project);
defaultProject = project;
} else {
defaultProject = this.projects.FirstOrDefault(p => p.Name == defaultProjectName);
}
if(defaultProject == null) {
defaultProject = this.projects[0];
}
this.DefaultProject = defaultProject;
await this.LoadProject(defaultProject);
}
public ProjectsService() {
this.DoLoadProject = new RelayCommand<IProject>(async (project) => {
// load new project
await this.LoadProject(project);
}, (project) => {
return this.currentProject != project && this.MayChangeProject.Value;
});
this.DoDeleteProject = new RelayCommand<IProject>((project) => {
this.DeleteProject(project);
}, (project) => {
return this.currentProject != project && this.projects.Count > 1;
});
this.DoSetDefaultProject = new RelayCommand<IProject>((project) => {
this.DefaultProject = project;
}, (project) => {
return this.defaultProject != project;
});
this.DoRefresh = new RelayCommand(async () => {
// save changes to current project
await this.SaveProject(this.currentProject);
// reload projects
await this.LoadProjects(this.defaultProject?.Name);
}, this.MayChangeProject);
this.DoOpenDirectory = new RelayCommand(() => {
System.Diagnostics.Process.Start(Core.ConfigurationDirectory);
});
this.DoSaveProject = new RelayCommand(() => {
_ = this.SaveProject(this.currentProject);
}, () => this.currentProject != null);
this.MayChangeProject.RegisterUpdate(() => {
this.DoLoadProject.RaiseCanExecuteChanged();
});
this.DoAddProject = new RelayCommand(async () => {
await this.AddProject(this.editName);
this.EditName = "";
}, () => {
return !string.IsNullOrWhiteSpace(this.editName) && !this.projects.Any(p => p.Name == this.editName);
});
this.projects.CollectionChanged += (sender, e) => {
this.DoDeleteProject.RaiseCanExecuteChanged();
this.onProjectsChanged.Fire();
};
}
public async Task SaveProject(IProject project) {
var configuration = new ServiceConfiguration("project");
foreach(var service in this.ConfiguredServices) {
await service.SaveConfiguration(configuration);
}
configuration.SaveToFile(project.FilePath);
}
public async Task LoadProject(IProject project) {
// save current project
if(this.currentProject != null) {
await this.SaveProject(this.currentProject);
}
// clear project
await this.ClearProject();
// load project from configuration
var configuration = ServiceConfiguration.FromFile(project.FilePath, "project");
foreach(var service in this.ConfiguredServices) {
await service.LoadConfiguration(configuration);
}
// set current project
this.CurrentProject = project;
}
public async Task ClearProject() {
foreach(var service in this.ConfiguredServices) {
await service.Reset();
}
}
public override async Task LoadConfiguration(ServiceConfiguration configuration) {
var defaultProject = configuration.ReadValue("defaultProject", null);
await this.LoadProjects(defaultProject);
}
public override async Task SaveConfiguration(ServiceConfiguration configuration) {
configuration.WriteValue("defaultProject", this.defaultProject?.Name);
if(this.CurrentProject != null) {
await this.SaveProject(this.currentProject);
}
}
public async Task AddProject(string name) {
await this.ClearProject();
var project = new Project() {
Name = name,
FilePath = Path.Combine(Core.ConfigurationDirectory, name + ".xml"),
};
this.projects.Add(project);
this.CurrentProject = project;
await this.SaveProject(project);
}
public void DeleteProject(IProject project) {
if(this.currentProject == project) {
return;
}
this.projects.Remove(project);
File.Delete(project.FilePath);
if(this.defaultProject == project) {
this.DefaultProject = this.projects.FirstOrDefault();
}
}
public void RegisterService(IService service) {
if(this.configuredServices.Contains(service)) {
throw new InvalidOperationException($"the service of type {service.GetType().Name} was already registered");
}
this.configuredServices.Add(service);
}
}
}