Skip to content

Commit 27e35ea

Browse files
authored
Allow loading of model systems that have issues stored as warnings. (#181)
1 parent 6866289 commit 27e35ea

12 files changed

Lines changed: 202 additions & 69 deletions

File tree

README.md

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,17 +4,19 @@
44
# XTMF2
55
The eXtensible Travel Modelling Framework 2
66

7-
This repository contains the core DLL for operating with and using XTMF problematically.
7+
This repository contains the core DLL for operating with and a desktop user interface a desktop user interface.
8+
89
The modules curated by TMG can be found in different repositories.
910
* [TMG-Framework](https://github.com/TravelModellingGroup/TMG-Framework) contains
1011
the core modules for building travel demand models.
12+
1113
* [TMG.Tasha2](https://github.com/TravelModellingGroup/TMG.Tasha2) contains the modules for
1214
running TASHA (included in GTAModel V4) and TASHA2 (to be included in GTAModel V5).
15+
1316
* [TMG.EMME](https://github.com/TravelModellingGroup/TMG.EMME) contains the modules
1417
for interacting with INRO's EMME software. Additionally it contains TMG's TMGToolbox2 for EMME.
1518

16-
[XTMF2.Web](https://github.com/TravelModellingGroup/XTMF2.Web) provides a web user experience for
17-
operating XTMF2.
19+
* [TMG.Visum](https://github.com/TravelModellingGroup/TMG.Visum) contains the modules for interacting with PTV Groups' VISUM from XTMF2.
1820

1921
## Building XTMF2
2022

@@ -32,6 +34,9 @@ operating XTMF2.
3234
3335
> dotnet test -c Release
3436
37+
### Running from the command line
38+
39+
> dotnet run -c Release --project src/XTMF2.GUI/XTMF2.GUI.csproj
3540
3641
## Main Branches
3742

src/XTMF2.GUI/ViewModels/ModelSystemsViewModel.cs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -319,11 +319,13 @@ private async Task ExportModelSystem()
319319
/// <param name="header">The model system to edit.</param>
320320
/// <param name="session">The new session, or <see langword="null"/> on failure.</param>
321321
/// <param name="error">Error information on failure.</param>
322+
/// <param name="warnings">Non-fatal warnings generated while loading the model system.</param>
322323
/// <returns><see langword="true"/> if the session was created successfully.</returns>
323324
public bool TryEditModelSystem(ModelSystemHeader header,
324325
out ModelSystemSession? session,
325-
out CommandError? error)
326-
=> _session.EditModelSystem(_user, header, out session, out error);
326+
out CommandError? error,
327+
out List<string>? warnings)
328+
=> _session.EditModelSystem(_user, header, out session, out error, out warnings);
327329

328330
/// <summary>
329331
/// Loads a read-only snapshot of a model system for diff comparison.

src/XTMF2.GUI/Views/ModelSystemsView.axaml.cs

Lines changed: 35 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -116,7 +116,7 @@ private void OpenModelSystem(ModelSystemHeader header)
116116
var mainWindow = TopLevel.GetTopLevel(this) as MainWindow;
117117
if (mainWindow is null || _viewModel is null) return;
118118

119-
if (!_viewModel.TryEditModelSystem(header, out var session, out var error) || session is null)
119+
if (!_viewModel.TryEditModelSystem(header, out var session, out var error, out var warnings) || session is null)
120120
{
121121
// Show an error dialog if we have a parent window
122122
if (mainWindow is not null)
@@ -132,6 +132,25 @@ private void OpenModelSystem(ModelSystemHeader header)
132132
return;
133133
}
134134

135+
if (warnings is { Count: > 0 })
136+
{
137+
Avalonia.Threading.Dispatcher.UIThread.Post(async () =>
138+
{
139+
var dialog = new ValidationIssueDialog(
140+
Strings.ModelSystems_OpenFailedTitle,
141+
string.Join(Environment.NewLine, warnings));
142+
await dialog.ShowDialog(mainWindow);
143+
if (!dialog.Result)
144+
{
145+
session.Dispose();
146+
return;
147+
}
148+
149+
mainWindow.OpenModelSystemTab(session, _viewModel.CurrentUser);
150+
});
151+
return;
152+
}
153+
135154
mainWindow.OpenModelSystemTab(session, _viewModel.CurrentUser);
136155
}
137156

@@ -229,8 +248,22 @@ await Avalonia.Threading.Dispatcher.UIThread.InvokeAsync(
229248
return existing;
230249
}
231250
// Otherwise open a new editing session.
232-
if (!capturedViewModel.TryEditModelSystem(header, out var session, out _))
251+
if (!capturedViewModel.TryEditModelSystem(header, out var session, out var error, out var warnings))
233252
return null;
253+
254+
if (warnings is { Count: > 0 })
255+
{
256+
var warningDialog = new ValidationIssueDialog(
257+
Strings.ModelSystems_OpenFailedTitle,
258+
string.Join(Environment.NewLine, warnings));
259+
await warningDialog.ShowDialog(mainWindow);
260+
if (!warningDialog.Result)
261+
{
262+
session?.Dispose();
263+
return null;
264+
}
265+
}
266+
234267
return mainWindow.OpenModelSystemTabAndGet(session!, capturedViewModel.CurrentUser);
235268
});
236269
});

src/XTMF2.GUI/Views/ValidationIssueDialog.axaml

Lines changed: 24 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
x:DataType="local:ValidationIssueDialog"
77
Classes="neon-dialog"
88
Width="420"
9-
Height="180"
9+
Height="300"
1010
WindowStartupLocation="CenterOwner"
1111
CanResize="False">
1212

@@ -16,23 +16,28 @@
1616
FontSize="14"
1717
Margin="0,0,0,15"
1818
TextWrapping="Wrap"
19-
VerticalAlignment="Center"/>
20-
21-
<StackPanel Grid.Row="1"
22-
Orientation="Horizontal"
23-
HorizontalAlignment="Right"
24-
Spacing="10">
25-
<Button Content="OK"
26-
Classes="dlg-primary"
27-
Click="Ok_Click"
28-
IsDefault="True"
29-
Padding="20,8"
30-
MinWidth="80"/>
31-
<Button Content="Cancel"
32-
Click="Cancel_Click"
33-
IsCancel="True"
34-
Padding="20,8"
35-
MinWidth="80"/>
36-
</StackPanel>
19+
VerticalAlignment="Center"
20+
ScrollViewer.VerticalScrollBarVisibility="Visible"/>
21+
22+
<Border Grid.Row="1"
23+
BorderBrush="{DynamicResource DlgSep}" BorderThickness="0,1,0,0"
24+
Margin="0,8,0,0" Padding="0,8,0,0">
25+
<StackPanel Grid.Row="1"
26+
Orientation="Horizontal"
27+
HorizontalAlignment="Right"
28+
Spacing="10">
29+
<Button Content="OK"
30+
Classes="dlg-primary"
31+
Click="Ok_Click"
32+
IsDefault="True"
33+
Padding="20,8"
34+
MinWidth="80"/>
35+
<Button Content="Cancel"
36+
Click="Cancel_Click"
37+
IsCancel="True"
38+
Padding="20,8"
39+
MinWidth="80"/>
40+
</StackPanel>
41+
</Border>
3742
</Grid>
3843
</Window>

src/XTMF2/Editing/ProjectSession.cs

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -305,7 +305,7 @@ public bool LoadModelSystemForDiff(User user, ModelSystemHeader modelSystemHeade
305305
if (System.IO.File.Exists(path))
306306
{
307307
using var stream = System.IO.File.OpenRead(path);
308-
ms = ModelSystem.Load(stream, GetModuleRepository(), modelSystemHeader, ref errorStr);
308+
ms = ModelSystem.Load(stream, GetModuleRepository(), modelSystemHeader, ref errorStr, out _);
309309
}
310310
else
311311
{
@@ -359,11 +359,15 @@ public bool LoadModelSystemFromExportedFile(User user, string exportedFilePath,
359359
/// <param name="error">An error message if the operation fails.</param>
360360
/// <returns>True if the operation succeeds, false otherwise with an error message.</returns>
361361
public bool EditModelSystem(User user, ModelSystemHeader modelSystemHeader, [NotNullWhen(true)] out ModelSystemSession? session, [NotNullWhen(false)] out CommandError? error)
362+
=> EditModelSystem(user, modelSystemHeader, out session, out error, out _);
363+
364+
public bool EditModelSystem(User user, ModelSystemHeader modelSystemHeader, [NotNullWhen(true)] out ModelSystemSession? session, [NotNullWhen(false)] out CommandError? error, out List<string>? warnings)
362365
{
363366
ArgumentNullException.ThrowIfNull(user);
364367
ArgumentNullException.ThrowIfNull(modelSystemHeader);
365368

366369
session = null;
370+
warnings = null;
367371
lock (_sessionLock)
368372
{
369373
if (!Project.CanAccess(user))
@@ -378,7 +382,7 @@ public bool EditModelSystem(User user, ModelSystemHeader modelSystemHeader, [Not
378382
}
379383
if (!_activeSessions.TryGetValue(modelSystemHeader, out session))
380384
{
381-
if (ModelSystem.Load(this, modelSystemHeader, out session, out error))
385+
if (ModelSystem.Load(this, modelSystemHeader, out session, out error, out warnings))
382386
{
383387
_activeSessions.Add(modelSystemHeader, session!);
384388
Interlocked.Increment(ref _references);

src/XTMF2/ModelSystemConstruct/Boundary.cs

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -945,7 +945,7 @@ internal bool AddLink(Link link, [NotNullWhen(false)] out CommandError? e)
945945

946946
internal bool Load(ModuleRepository modules, Dictionary<int, Type> typeLookup, Dictionary<int, Node> node, List<(Node toAssignTo, string parameterExpression)> scriptedParameters,
947947
List<(Boundary ContainedIn, int RefIndex, int SelfIndex, Rectangle Location, Guid Id)> deferredGhostNodes,
948-
ref Utf8JsonReader reader, [NotNullWhen(false)] ref string? error)
948+
ref Utf8JsonReader reader, [NotNullWhen(false)] ref string? error, List<string>? warnings = null)
949949
{
950950
if (reader.TokenType != JsonTokenType.StartObject)
951951
{
@@ -1016,11 +1016,12 @@ internal bool Load(ModuleRepository modules, Dictionary<int, Type> typeLookup, D
10161016
{
10171017
if (reader.TokenType != JsonTokenType.Comment)
10181018
{
1019-
if (!Node.Load(modules, typeLookup, node, scriptedParameters, this, ref reader, out var mss, ref error))
1019+
if (!Node.Load(modules, typeLookup, node, scriptedParameters, this, ref reader, out var mss, ref error, warnings))
10201020
{
10211021
return false;
10221022
}
1023-
_modules.Add(mss!);
1023+
if (mss is not null)
1024+
_modules.Add(mss);
10241025
}
10251026
}
10261027
}
@@ -1035,7 +1036,7 @@ internal bool Load(ModuleRepository modules, Dictionary<int, Type> typeLookup, D
10351036
if (reader.TokenType != JsonTokenType.Comment)
10361037
{
10371038
var boundary = new Boundary(this);
1038-
if (!boundary.Load(modules, typeLookup, node, scriptedParameters, deferredGhostNodes, ref reader, ref error))
1039+
if (!boundary.Load(modules, typeLookup, node, scriptedParameters, deferredGhostNodes, ref reader, ref error, warnings))
10391040
{
10401041
return false;
10411042
}
@@ -1053,11 +1054,12 @@ internal bool Load(ModuleRepository modules, Dictionary<int, Type> typeLookup, D
10531054
{
10541055
if (reader.TokenType != JsonTokenType.Comment)
10551056
{
1056-
if (!Link.Create(modules, node, ref reader, out var link, ref error))
1057+
if (!Link.Create(modules, node, ref reader, out var link, ref error, warnings))
10571058
{
10581059
return false;
10591060
}
1060-
_links.Add(link!);
1061+
if (link is not null)
1062+
_links.Add(link);
10611063
}
10621064
}
10631065
}
@@ -1087,12 +1089,10 @@ internal bool Load(ModuleRepository modules, Dictionary<int, Type> typeLookup, D
10871089
}
10881090
while(reader.Read() && reader.TokenType != JsonTokenType.EndArray)
10891091
{
1090-
if(reader.TokenType != JsonTokenType.Comment)
1092+
if (reader.TokenType != JsonTokenType.Comment)
10911093
{
1092-
if(!FunctionTemplate.Load(modules, typeLookup, node, scriptedParameters, deferredGhostNodes, ref reader, this, out var template, ref error))
1093-
{
1094+
if (!FunctionTemplate.Load(modules, typeLookup, node, scriptedParameters, deferredGhostNodes, ref reader, this, out var template, ref error, warnings))
10941095
return false;
1095-
}
10961096
_functionTemplates.Add(template!);
10971097
}
10981098
}

src/XTMF2/ModelSystemConstruct/FunctionTemplate.cs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -446,18 +446,18 @@ internal void Save(ref int index, Dictionary<Node, int> nodeDictionary, Dictiona
446446
/// <param name="error">An error message if we failed to load the function template or its children.</param>
447447
/// <returns>True if the operation succeeded, false otherwise with an error message.</returns>
448448
internal static bool Load(ModuleRepository modules, Dictionary<int, Type> typeLookup, Dictionary<int, Node> node, List<(Node toAssignTo, string parameterExpression)> scriptedParameters,
449-
ref Utf8JsonReader reader, Boundary parent, [NotNullWhen(true)] out FunctionTemplate? template, [NotNullWhen(false)] ref string? error)
449+
ref Utf8JsonReader reader, Boundary parent, [NotNullWhen(true)] out FunctionTemplate? template, [NotNullWhen(false)] ref string? error, List<string>? warnings = null)
450450
{
451451
List<(Boundary ContainedIn, int RefIndex, int SelfIndex, Rectangle Location, Guid Id)> deferredGhostNodes = new();
452-
return Load(modules, typeLookup, node, scriptedParameters, deferredGhostNodes, ref reader, parent, out template, ref error);
452+
return Load(modules, typeLookup, node, scriptedParameters, deferredGhostNodes, ref reader, parent, out template, ref error, warnings);
453453
}
454454

455455
internal static bool Load(ModuleRepository modules, Dictionary<int, Type> typeLookup, Dictionary<int, Node> node,
456456
List<(Node toAssignTo, string parameterExpression)> scriptedParameters,
457457
List<(Boundary ContainedIn, int RefIndex, int SelfIndex, Rectangle Location, Guid Id)> deferredGhostNodes,
458458
ref Utf8JsonReader reader, Boundary parent,
459459
[NotNullWhen(true)] out FunctionTemplate? template,
460-
[NotNullWhen(false)] ref string? error)
460+
[NotNullWhen(false)] ref string? error, List<string>? warnings = null)
461461
{
462462
template = null;
463463
Guid? id = null;
@@ -527,7 +527,7 @@ internal static bool Load(ModuleRepository modules, Dictionary<int, Type> typeLo
527527
else if (reader.ValueTextEquals(nameof(InternalModules)))
528528
{
529529
reader.Read();
530-
if (!innerModules.Load(modules, typeLookup, node, scriptedParameters, deferredGhostNodes, ref reader, ref error))
530+
if (!innerModules.Load(modules, typeLookup, node, scriptedParameters, deferredGhostNodes, ref reader, ref error, warnings))
531531
return false;
532532
}
533533
else if (reader.ValueTextEquals(EntryNodeProperty))

0 commit comments

Comments
 (0)