7
// Copyright (C) 2005 Novell, Inc (http://www.novell.com)
9
// Permission is hereby granted, free of charge, to any person obtaining
10
// a copy of this software and associated documentation files (the
11
// "Software"), to deal in the Software without restriction, including
12
// without limitation the rights to use, copy, modify, merge, publish,
13
// distribute, sublicense, and/or sell copies of the Software, and to
14
// permit persons to whom the Software is furnished to do so, subject to
15
// the following conditions:
17
// The above copyright notice and this permission notice shall be
18
// included in all copies or substantial portions of the Software.
20
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
21
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
22
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
23
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
24
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
25
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
26
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
30
using System.Collections;
31
using System.Collections.Generic;
32
using System.Collections.ObjectModel;
33
using System.Collections.Specialized;
36
using MonoDevelop.Core;
37
using MonoDevelop.Projects;
38
using MonoDevelop.Core.Serialization;
40
namespace MonoDevelop.Projects.Formats.MD1
42
interface ICombineReader {
43
object ReadCombine (XmlReader reader);
46
class CombineReaderV2: XmlConfigurationReader, ICombineReader
48
DataSerializer serializer;
49
ArrayList entries = new ArrayList ();
50
IProgressMonitor monitor;
54
public CombineReaderV2 (DataSerializer serializer, IProgressMonitor monitor, Type objectType)
56
this.serializer = serializer;
57
this.objectType = objectType;
58
baseFile = serializer.SerializationContext.BaseFile;
59
this.monitor = monitor;
62
public object ReadCombine (XmlReader reader)
64
DataItem data = (DataItem) Read (reader);
66
// Both combine and SolutionFolder use the same element name, but the types are different
67
if (data.Name == "Combine" && objectType == typeof(SolutionFolder))
68
data.Name = "SolutionFolder";
70
SolutionFolder folder;
71
IExtendedDataItem obj = (IExtendedDataItem) serializer.CreateInstance (objectType, data);
72
Solution sol = obj as Solution;
74
folder = sol.RootFolder;
75
sol.ConvertToFormat (MD1ProjectService.FileFormat, false);
76
sol.FileName = serializer.SerializationContext.BaseFile;
77
folder.ExtendedProperties ["FileName"] = serializer.SerializationContext.BaseFile;
80
folder = (SolutionFolder) obj;
81
obj.ExtendedProperties ["FileName"] = serializer.SerializationContext.BaseFile;
84
// The folder entries must be added before deserializing the folder
85
// since other folder members depend on it
87
foreach (SolutionItem ce in entries)
88
folder.Items.Add (ce);
90
serializer.Deserialize (obj, data);
93
CreateSolutionConfigurations (sol);
94
LoadStartupMode (sol);
101
protected override DataNode ReadChild (XmlReader reader, DataItem parent)
103
if (reader.LocalName == "Entries") {
104
if (reader.IsEmptyElement) { reader.Skip(); return null; }
105
string basePath = Path.GetDirectoryName (baseFile);
106
reader.ReadStartElement ();
108
ArrayList files = new ArrayList ();
109
while (MoveToNextElement (reader)) {
110
string nodefile = reader.GetAttribute ("filename");
111
nodefile = FileService.RelativeToAbsolutePath (basePath, nodefile);
112
files.Add (nodefile);
116
monitor.BeginTask (GettextCatalog.GetString ("Loading solution: {0}", baseFile), files.Count);
118
foreach (string nodefile in files) {
120
if (Path.GetExtension (nodefile).ToLower () == ".mds") {
121
entries.Add (ReadSolutionFolder (nodefile, monitor));
124
SolutionEntityItem entry = (SolutionEntityItem) Services.ProjectService.ReadSolutionItem (monitor, nodefile);
127
} catch (Exception ex) {
128
UnknownSolutionItem entry = new UnknownSolutionItem ();
129
entry.FileName = nodefile;
130
entry.LoadError = ex.Message;
132
monitor.ReportError (GettextCatalog.GetString ("Could not load item: {0}", nodefile), ex);
140
reader.ReadEndElement ();
144
return base.ReadChild (reader, parent);
147
void CreateSolutionConfigurations (Solution sol)
149
CombineConfigurationSet configs = (CombineConfigurationSet) sol.ExtendedProperties ["Configurations"];
150
foreach (CombineConfiguration config in configs.Configurations) {
151
SolutionConfiguration sconf = config.SolutionConfiguration ?? new SolutionConfiguration (config.Name);
152
sol.Configurations.Add (sconf);
155
foreach (SolutionEntityItem item in sol.GetAllSolutionItems<SolutionEntityItem> ()) {
157
List<IExtendedDataItem> chain = new List<IExtendedDataItem> ();
158
SolutionItem it = item;
160
chain.Insert (0, it);
161
it = it.ParentFolder;
165
foreach (SolutionConfiguration sconfig in sol.Configurations) {
166
SolutionConfigurationEntry se = sconfig.AddItem (item);
167
string itemConfig = FindItemConfiguration (chain, sconfig.Id);
168
if (itemConfig != null) {
170
se.ItemConfiguration = itemConfig;
177
sol.DefaultConfigurationId = configs.Active;
180
void LoadStartupMode (Solution sol)
182
// Recursively look for startup items. If there is more than one,
183
// it means it is a multi startup solution.
184
List<SolutionEntityItem> items = new List<SolutionEntityItem> ();
185
FindStartupItems (sol, sol.RootFolder, items);
187
if (items.Count == 1) {
188
sol.SingleStartup = true;
189
sol.StartupItem = items [0];
190
} else if (items.Count > 1) {
191
sol.SingleStartup = false;
192
sol.MultiStartupItems.AddRange (items);
196
void FindStartupItems (Solution sol, SolutionFolder folder, List<SolutionEntityItem> items)
198
CombineStartupMode startupMode = (CombineStartupMode) folder.ExtendedProperties ["StartMode"];
199
if (startupMode != null) {
200
if (startupMode.SingleStartup) {
201
SolutionItem it = FindItemByName (folder, startupMode.StartEntryName);
202
if (it is SolutionFolder)
203
FindStartupItems (sol, (SolutionFolder)it, items);
204
else if (it is SolutionEntityItem)
205
items.Add ((SolutionEntityItem) it);
208
foreach (CombineStartupEntry cse in startupMode.Entries) {
209
if (cse.Type == "Execute") {
210
SolutionItem it = FindItemByName (folder, cse.Entry);
211
if (it is SolutionFolder)
212
FindStartupItems (sol, (SolutionFolder)it, items);
213
else if (it is SolutionEntityItem)
214
items.Add ((SolutionEntityItem) it);
221
SolutionItem FindItemByName (SolutionFolder folder, string name)
223
foreach (SolutionItem it in folder.Items)
229
string FindItemConfiguration (List<IExtendedDataItem> chain, string configId)
231
for (int n=0; n < chain.Count - 1; n++) {
232
CombineConfigurationSet configs = (CombineConfigurationSet) chain[n].ExtendedProperties ["Configurations"];
235
SolutionItem item = (SolutionItem) chain [n+1];
236
CombineConfiguration combineConfig = configs.GetConfig (configId);
237
if (combineConfig == null) {
238
monitor.ReportWarning ("Configuration '" + configId + "' not found in solution item '" + item.Name + "'.");
241
string mappedConfigId = combineConfig.GetMappedConfig (item.Name);
242
if (mappedConfigId == null)
244
if (mappedConfigId != string.Empty)
245
configId = mappedConfigId;
250
object ReadSolutionFolder (string file, IProgressMonitor monitor)
252
XmlTextReader reader = new XmlTextReader (new StreamReader (file));
253
reader.MoveToContent ();
255
string version = reader.GetAttribute ("version");
257
version = reader.GetAttribute ("fileversion");
259
DataSerializer serializer = new DataSerializer (MD1ProjectService.DataContext, file);
262
if (version != "2.0")
263
throw new MD1UnknownProjectVersion (file, version);
264
ICombineReader combineReader = new CombineReaderV2 (serializer, monitor, typeof(SolutionFolder));
265
return combineReader.ReadCombine (reader);
266
} catch (Exception ex) {
267
monitor.ReportError (GettextCatalog.GetString ("Could not load solution: {0}", file), ex);
274
protected override XmlConfigurationReader GetChildReader (MonoDevelop.Core.Serialization.DataItem parent)
276
// Don't reuse this serializer for children, since it has solution-specific serialization code
277
return XmlConfigurationReader.DefaultReader;
282
class CombineWriterV2: XmlConfigurationWriter
284
SolutionFolder folder;
285
DataSerializer serializer;
286
IProgressMonitor monitor;
289
public CombineWriterV2 (DataSerializer serializer, IProgressMonitor monitor, Type objectType)
291
this.serializer = serializer;
292
this.monitor = monitor;
293
this.objectType = objectType;
296
public void WriteCombine (XmlWriter writer, object item)
298
if (item is Solution) {
299
Solution sol = (Solution) item;
300
folder = sol.RootFolder;
301
CreateCombineConfigurations (sol.RootFolder);
302
CreateStartupModes (sol);
305
folder = (SolutionFolder) item;
307
DataItem data = (DataItem) serializer.Serialize (item, objectType);
309
// Both combine and SolutionFolder use the same element name, but the types are different
310
if (data.Name == "SolutionFolder" && objectType == typeof(SolutionFolder))
311
data.Name = "Combine";
313
Write (writer, data);
316
void CreateStartupModes (Solution sol)
318
// Initialize the startup modes
319
ReadOnlyCollection<SolutionFolder> folders = sol.GetAllSolutionItems<SolutionFolder> ();
320
foreach (SolutionFolder folder in folders) {
321
CombineStartupMode startupMode = new CombineStartupMode ();
322
startupMode.SingleStartup = true;
323
startupMode.StartEntryName = null;
324
foreach (SolutionItem it in folder.Items)
325
startupMode.AddEntry (it.Name);
326
folder.ExtendedProperties ["StartMode"] = startupMode;
329
// Get the list of startup items
330
IEnumerable<SolutionEntityItem> items;
331
if (sol.SingleStartup)
332
items = new SolutionEntityItem [] { sol.StartupItem };
334
items = sol.MultiStartupItems;
336
// Setup the startup modes
337
foreach (SolutionEntityItem it in items) {
340
SolutionFolder folder = it.ParentFolder;
341
SolutionItem prevItem = it;
342
while (folder != null) {
343
CombineStartupMode startupMode = (CombineStartupMode) folder.ExtendedProperties ["StartMode"];
344
if (startupMode.SingleStartup) {
345
// If a start entry is already set, convert to multi startup mode
346
if (startupMode.StartEntryName == null)
347
startupMode.StartEntryName = prevItem.Name;
348
else if (startupMode.StartEntryName != prevItem.Name) {
349
startupMode.SingleStartup = false;
350
startupMode.MakeExecutable (startupMode.StartEntryName);
351
startupMode.MakeExecutable (prevItem.Name);
354
// Already multi startup, just add the new item
355
startupMode.MakeExecutable (prevItem.Name);
358
folder = folder.ParentFolder;
362
// Set the startup item for folders which don't have one
363
foreach (SolutionFolder folder in folders) {
364
CombineStartupMode startupMode = (CombineStartupMode) folder.ExtendedProperties ["StartMode"];
365
if (startupMode.SingleStartup && startupMode.StartEntryName == null) {
366
if (folder.Items.Count > 0)
367
startupMode.StartEntryName = folder.Items [0].Name;
372
void CreateCombineConfigurations (SolutionFolder folder)
374
IDictionary extendedProperties = folder.ExtendedProperties;
376
CombineConfigurationSet configs = CreateCombineConfigurationSet (folder.ParentSolution, folder.IsRoot);
377
configs.Active = folder.ParentSolution.DefaultConfigurationId;
379
extendedProperties ["Configurations"] = configs;
381
foreach (SolutionItem it in folder.Items) {
383
if (it is SolutionFolder) {
384
foreach (SolutionConfiguration conf in folder.ParentSolution.Configurations) {
385
CombineConfiguration cc = configs.GetConfig (conf.Id);
386
CombineConfigurationEntry ce = new CombineConfigurationEntry (it.Name, true, conf.Id);
389
CreateCombineConfigurations ((SolutionFolder) it);
391
else if (it is SolutionEntityItem) {
392
SolutionEntityItem sit = (SolutionEntityItem) it;
393
foreach (SolutionConfiguration conf in folder.ParentSolution.Configurations) {
394
CombineConfiguration cc = configs.GetConfig (conf.Id);
395
SolutionConfigurationEntry sce = conf.GetEntryForItem (sit);
396
CombineConfigurationEntry ce = null;
398
ce = new CombineConfigurationEntry (it.Name, true, conf.Id);
400
ce = new CombineConfigurationEntry (it.Name, sce.Build, sce.ItemConfiguration);
407
CombineConfigurationSet CreateCombineConfigurationSet (Solution sol, bool isRoot)
409
CombineConfigurationSet cset = new CombineConfigurationSet ();
410
foreach (SolutionConfiguration conf in sol.Configurations) {
411
CombineConfiguration cc = new CombineConfiguration ();
414
cc.SolutionConfiguration = conf;
415
cset.Configurations.Add (cc);
420
protected override void WriteChildren (XmlWriter writer, DataItem item)
422
base.WriteChildren (writer, item);
424
writer.WriteStartElement ("Entries");
425
foreach (SolutionItem entry in folder.Items) {
426
writer.WriteStartElement ("Entry");
428
string baseDir = Path.GetDirectoryName (serializer.SerializationContext.BaseFile);
431
if (entry is SolutionFolder) {
432
SolutionFolder cfolder = (SolutionFolder) entry;
433
fname = cfolder.ExtendedProperties ["FileName"] as string;
435
// Guess a good file name for the mds file.
436
if (Directory.Exists (Path.Combine (baseDir, cfolder.Name)))
437
fname = Path.Combine (Path.Combine (baseDir, cfolder.Name), cfolder.Name + ".mds");
439
fname = Path.Combine (baseDir, cfolder.Name + ".mds");
442
else if (entry is SolutionEntityItem) {
443
fname = ((SolutionEntityItem)entry).FileName;
446
throw new InvalidOperationException ("Don't know how to save item of type " + entry.GetType ());
448
string relfname = FileService.AbsoluteToRelativePath (baseDir, fname);
449
writer.WriteAttributeString ("filename", relfname);
450
writer.WriteEndElement ();
451
if (entry is SolutionEntityItem)
452
((SolutionEntityItem)entry).Save (monitor);
454
WriteSolutionFolder ((SolutionFolder) entry, fname, monitor);
456
writer.WriteEndElement ();
459
void WriteSolutionFolder (SolutionFolder folder, string file, IProgressMonitor monitor)
461
StreamWriter sw = new StreamWriter (file);
463
monitor.BeginTask (GettextCatalog.GetString ("Saving solution: {0}", file), 1);
464
XmlTextWriter tw = new XmlTextWriter (sw);
465
tw.Formatting = Formatting.Indented;
466
DataSerializer serializer = new DataSerializer (MD1ProjectService.DataContext, file);
467
CombineWriterV2 combineWriter = new CombineWriterV2 (serializer, monitor, typeof(SolutionFolder));
468
combineWriter.WriteCombine (tw, folder);
469
} catch (Exception ex) {
470
monitor.ReportError (GettextCatalog.GetString ("Could not save solution: {0}", file), ex);
478
protected override XmlConfigurationWriter GetChildWriter (MonoDevelop.Core.Serialization.DataNode data)
480
// Don't reuse this serializer for children, since it has solution-specific serialization code
481
return XmlConfigurationWriter.DefaultWriter;