Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 8 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,17 +4,19 @@
# XTMF2
The eXtensible Travel Modelling Framework 2

This repository contains the core DLL for operating with and using XTMF problematically.
This repository contains the core DLL for operating with and a desktop user interface a desktop user interface.

The modules curated by TMG can be found in different repositories.
* [TMG-Framework](https://github.com/TravelModellingGroup/TMG-Framework) contains
the core modules for building travel demand models.

* [TMG.Tasha2](https://github.com/TravelModellingGroup/TMG.Tasha2) contains the modules for
running TASHA (included in GTAModel V4) and TASHA2 (to be included in GTAModel V5).

* [TMG.EMME](https://github.com/TravelModellingGroup/TMG.EMME) contains the modules
for interacting with INRO's EMME software. Additionally it contains TMG's TMGToolbox2 for EMME.

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

## Building XTMF2

Expand All @@ -32,6 +34,9 @@ operating XTMF2.

> dotnet test -c Release

### Running from the command line

> dotnet run -c Release --project src/XTMF2.GUI/XTMF2.GUI.csproj

## Main Branches

Expand Down
6 changes: 4 additions & 2 deletions src/XTMF2.GUI/ViewModels/ModelSystemsViewModel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -319,11 +319,13 @@ private async Task ExportModelSystem()
/// <param name="header">The model system to edit.</param>
/// <param name="session">The new session, or <see langword="null"/> on failure.</param>
/// <param name="error">Error information on failure.</param>
/// <param name="warnings">Non-fatal warnings generated while loading the model system.</param>
/// <returns><see langword="true"/> if the session was created successfully.</returns>
public bool TryEditModelSystem(ModelSystemHeader header,
out ModelSystemSession? session,
out CommandError? error)
=> _session.EditModelSystem(_user, header, out session, out error);
out CommandError? error,
out List<string>? warnings)
=> _session.EditModelSystem(_user, header, out session, out error, out warnings);

/// <summary>
/// Loads a read-only snapshot of a model system for diff comparison.
Expand Down
37 changes: 35 additions & 2 deletions src/XTMF2.GUI/Views/ModelSystemsView.axaml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,7 @@ private void OpenModelSystem(ModelSystemHeader header)
var mainWindow = TopLevel.GetTopLevel(this) as MainWindow;
if (mainWindow is null || _viewModel is null) return;

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

if (warnings is { Count: > 0 })
{
Avalonia.Threading.Dispatcher.UIThread.Post(async () =>
{
var dialog = new ValidationIssueDialog(
Strings.ModelSystems_OpenFailedTitle,
string.Join(Environment.NewLine, warnings));
await dialog.ShowDialog(mainWindow);
if (!dialog.Result)
{
session.Dispose();
return;
}

mainWindow.OpenModelSystemTab(session, _viewModel.CurrentUser);
});
return;
}

mainWindow.OpenModelSystemTab(session, _viewModel.CurrentUser);
}

Expand Down Expand Up @@ -229,8 +248,22 @@ await Avalonia.Threading.Dispatcher.UIThread.InvokeAsync(
return existing;
}
// Otherwise open a new editing session.
if (!capturedViewModel.TryEditModelSystem(header, out var session, out _))
if (!capturedViewModel.TryEditModelSystem(header, out var session, out var error, out var warnings))
return null;

if (warnings is { Count: > 0 })
{
var warningDialog = new ValidationIssueDialog(
Strings.ModelSystems_OpenFailedTitle,
string.Join(Environment.NewLine, warnings));
await warningDialog.ShowDialog(mainWindow);
if (!warningDialog.Result)
{
session?.Dispose();
return null;
}
}

return mainWindow.OpenModelSystemTabAndGet(session!, capturedViewModel.CurrentUser);
});
});
Expand Down
43 changes: 24 additions & 19 deletions src/XTMF2.GUI/Views/ValidationIssueDialog.axaml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
x:DataType="local:ValidationIssueDialog"
Classes="neon-dialog"
Width="420"
Height="180"
Height="300"
WindowStartupLocation="CenterOwner"
CanResize="False">

Expand All @@ -16,23 +16,28 @@
FontSize="14"
Margin="0,0,0,15"
TextWrapping="Wrap"
VerticalAlignment="Center"/>

<StackPanel Grid.Row="1"
Orientation="Horizontal"
HorizontalAlignment="Right"
Spacing="10">
<Button Content="OK"
Classes="dlg-primary"
Click="Ok_Click"
IsDefault="True"
Padding="20,8"
MinWidth="80"/>
<Button Content="Cancel"
Click="Cancel_Click"
IsCancel="True"
Padding="20,8"
MinWidth="80"/>
</StackPanel>
VerticalAlignment="Center"
ScrollViewer.VerticalScrollBarVisibility="Visible"/>

<Border Grid.Row="1"
BorderBrush="{DynamicResource DlgSep}" BorderThickness="0,1,0,0"
Margin="0,8,0,0" Padding="0,8,0,0">
<StackPanel Grid.Row="1"
Orientation="Horizontal"
HorizontalAlignment="Right"
Spacing="10">
<Button Content="OK"
Classes="dlg-primary"
Click="Ok_Click"
IsDefault="True"
Padding="20,8"
MinWidth="80"/>
<Button Content="Cancel"
Click="Cancel_Click"
IsCancel="True"
Padding="20,8"
MinWidth="80"/>
</StackPanel>
</Border>
</Grid>
</Window>
8 changes: 6 additions & 2 deletions src/XTMF2/Editing/ProjectSession.cs
Original file line number Diff line number Diff line change
Expand Up @@ -305,7 +305,7 @@ public bool LoadModelSystemForDiff(User user, ModelSystemHeader modelSystemHeade
if (System.IO.File.Exists(path))
{
using var stream = System.IO.File.OpenRead(path);
ms = ModelSystem.Load(stream, GetModuleRepository(), modelSystemHeader, ref errorStr);
ms = ModelSystem.Load(stream, GetModuleRepository(), modelSystemHeader, ref errorStr, out _);
}
else
{
Expand Down Expand Up @@ -359,11 +359,15 @@ public bool LoadModelSystemFromExportedFile(User user, string exportedFilePath,
/// <param name="error">An error message if the operation fails.</param>
/// <returns>True if the operation succeeds, false otherwise with an error message.</returns>
public bool EditModelSystem(User user, ModelSystemHeader modelSystemHeader, [NotNullWhen(true)] out ModelSystemSession? session, [NotNullWhen(false)] out CommandError? error)
=> EditModelSystem(user, modelSystemHeader, out session, out error, out _);

public bool EditModelSystem(User user, ModelSystemHeader modelSystemHeader, [NotNullWhen(true)] out ModelSystemSession? session, [NotNullWhen(false)] out CommandError? error, out List<string>? warnings)
{
ArgumentNullException.ThrowIfNull(user);
ArgumentNullException.ThrowIfNull(modelSystemHeader);

session = null;
warnings = null;
lock (_sessionLock)
{
if (!Project.CanAccess(user))
Expand All @@ -378,7 +382,7 @@ public bool EditModelSystem(User user, ModelSystemHeader modelSystemHeader, [Not
}
if (!_activeSessions.TryGetValue(modelSystemHeader, out session))
{
if (ModelSystem.Load(this, modelSystemHeader, out session, out error))
if (ModelSystem.Load(this, modelSystemHeader, out session, out error, out warnings))
{
_activeSessions.Add(modelSystemHeader, session!);
Interlocked.Increment(ref _references);
Expand Down
20 changes: 10 additions & 10 deletions src/XTMF2/ModelSystemConstruct/Boundary.cs
Original file line number Diff line number Diff line change
Expand Up @@ -945,7 +945,7 @@ internal bool AddLink(Link link, [NotNullWhen(false)] out CommandError? e)

internal bool Load(ModuleRepository modules, Dictionary<int, Type> typeLookup, Dictionary<int, Node> node, List<(Node toAssignTo, string parameterExpression)> scriptedParameters,
List<(Boundary ContainedIn, int RefIndex, int SelfIndex, Rectangle Location, Guid Id)> deferredGhostNodes,
ref Utf8JsonReader reader, [NotNullWhen(false)] ref string? error)
ref Utf8JsonReader reader, [NotNullWhen(false)] ref string? error, List<string>? warnings = null)
{
if (reader.TokenType != JsonTokenType.StartObject)
{
Expand Down Expand Up @@ -1016,11 +1016,12 @@ internal bool Load(ModuleRepository modules, Dictionary<int, Type> typeLookup, D
{
if (reader.TokenType != JsonTokenType.Comment)
{
if (!Node.Load(modules, typeLookup, node, scriptedParameters, this, ref reader, out var mss, ref error))
if (!Node.Load(modules, typeLookup, node, scriptedParameters, this, ref reader, out var mss, ref error, warnings))
{
return false;
}
_modules.Add(mss!);
if (mss is not null)
_modules.Add(mss);
}
}
}
Expand All @@ -1035,7 +1036,7 @@ internal bool Load(ModuleRepository modules, Dictionary<int, Type> typeLookup, D
if (reader.TokenType != JsonTokenType.Comment)
{
var boundary = new Boundary(this);
if (!boundary.Load(modules, typeLookup, node, scriptedParameters, deferredGhostNodes, ref reader, ref error))
if (!boundary.Load(modules, typeLookup, node, scriptedParameters, deferredGhostNodes, ref reader, ref error, warnings))
{
return false;
}
Expand All @@ -1053,11 +1054,12 @@ internal bool Load(ModuleRepository modules, Dictionary<int, Type> typeLookup, D
{
if (reader.TokenType != JsonTokenType.Comment)
{
if (!Link.Create(modules, node, ref reader, out var link, ref error))
if (!Link.Create(modules, node, ref reader, out var link, ref error, warnings))
{
return false;
}
_links.Add(link!);
if (link is not null)
_links.Add(link);
}
}
}
Expand Down Expand Up @@ -1087,12 +1089,10 @@ internal bool Load(ModuleRepository modules, Dictionary<int, Type> typeLookup, D
}
while(reader.Read() && reader.TokenType != JsonTokenType.EndArray)
{
if(reader.TokenType != JsonTokenType.Comment)
if (reader.TokenType != JsonTokenType.Comment)
{
if(!FunctionTemplate.Load(modules, typeLookup, node, scriptedParameters, deferredGhostNodes, ref reader, this, out var template, ref error))
{
if (!FunctionTemplate.Load(modules, typeLookup, node, scriptedParameters, deferredGhostNodes, ref reader, this, out var template, ref error, warnings))
return false;
}
_functionTemplates.Add(template!);
}
}
Expand Down
8 changes: 4 additions & 4 deletions src/XTMF2/ModelSystemConstruct/FunctionTemplate.cs
Original file line number Diff line number Diff line change
Expand Up @@ -446,18 +446,18 @@ internal void Save(ref int index, Dictionary<Node, int> nodeDictionary, Dictiona
/// <param name="error">An error message if we failed to load the function template or its children.</param>
/// <returns>True if the operation succeeded, false otherwise with an error message.</returns>
internal static bool Load(ModuleRepository modules, Dictionary<int, Type> typeLookup, Dictionary<int, Node> node, List<(Node toAssignTo, string parameterExpression)> scriptedParameters,
ref Utf8JsonReader reader, Boundary parent, [NotNullWhen(true)] out FunctionTemplate? template, [NotNullWhen(false)] ref string? error)
ref Utf8JsonReader reader, Boundary parent, [NotNullWhen(true)] out FunctionTemplate? template, [NotNullWhen(false)] ref string? error, List<string>? warnings = null)
{
List<(Boundary ContainedIn, int RefIndex, int SelfIndex, Rectangle Location, Guid Id)> deferredGhostNodes = new();
return Load(modules, typeLookup, node, scriptedParameters, deferredGhostNodes, ref reader, parent, out template, ref error);
return Load(modules, typeLookup, node, scriptedParameters, deferredGhostNodes, ref reader, parent, out template, ref error, warnings);
}

internal static bool Load(ModuleRepository modules, Dictionary<int, Type> typeLookup, Dictionary<int, Node> node,
List<(Node toAssignTo, string parameterExpression)> scriptedParameters,
List<(Boundary ContainedIn, int RefIndex, int SelfIndex, Rectangle Location, Guid Id)> deferredGhostNodes,
ref Utf8JsonReader reader, Boundary parent,
[NotNullWhen(true)] out FunctionTemplate? template,
[NotNullWhen(false)] ref string? error)
[NotNullWhen(false)] ref string? error, List<string>? warnings = null)
{
template = null;
Guid? id = null;
Expand Down Expand Up @@ -527,7 +527,7 @@ internal static bool Load(ModuleRepository modules, Dictionary<int, Type> typeLo
else if (reader.ValueTextEquals(nameof(InternalModules)))
{
reader.Read();
if (!innerModules.Load(modules, typeLookup, node, scriptedParameters, deferredGhostNodes, ref reader, ref error))
if (!innerModules.Load(modules, typeLookup, node, scriptedParameters, deferredGhostNodes, ref reader, ref error, warnings))
return false;
}
else if (reader.ValueTextEquals(EntryNodeProperty))
Expand Down
Loading
Loading