EDBGS/EliteBGS/MainWindow.xaml.cs

717 lines
23 KiB
C#
Raw Normal View History

2022-11-24 19:38:19 +01:00
using System;
using System.Linq;
using System.Collections.Generic;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using Ookii.Dialogs.Wpf;
using EDPlayerJournal;
using EDPlayerJournal.BGS;
using EDPlayerJournal.Entries;
using EliteBGS.BGS;
using EliteBGS.Util;
using System.Globalization;
2022-12-14 19:28:23 +01:00
using System.Windows.Controls.Primitives;
using MahApps.Metro.Controls;
2023-02-23 20:55:17 +01:00
using ControlzEx.Theming;
using System.Windows.Media;
using System.Diagnostics;
2022-11-24 19:38:19 +01:00
namespace EliteBGS;
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
2023-02-26 10:09:50 +01:00
public partial class MainWindow : MetroWindow {
2022-11-24 19:38:19 +01:00
private PlayerJournal journal;
private Report report;
public Config Config { get; set; } = new Config();
private LoadEntriesWindow loadentries = null;
private static readonly List<DiscordLogGenerator> logtypes = new List<DiscordLogGenerator>() {
new GenericDiscordLog(),
new NonaDiscordLog(),
new OneLineDiscordLog(),
2022-11-24 19:38:19 +01:00
};
public MainWindow() {
InitializeComponent();
try {
Config.LoadGlobal();
} catch (Exception) {
/* ignored */
}
Webhooks.ItemsSource = Config.Global.Webhooks;
RefreshPostMenu();
2022-11-24 19:38:19 +01:00
foreach (DiscordLogGenerator type in logtypes) {
LogType.Items.Add(type);
}
string lastused = Config.Global.LastUsedDiscordTemplate;
int lastindex = logtypes.FindIndex(x => x.ToString() == lastused);
if (lastindex > -1) {
LogType.SelectedIndex = lastindex;
} else {
LogType.SelectedIndex = 0;
}
this.NoInfluenceSupport.IsOn = Config.Global.IgnoreInfluenceSupport;
2023-04-19 09:25:36 +02:00
this.NoMarketBuy.IsOn = Config.Global.IgnoreMarketBuy;
this.NoFleetCarrier.IsOn = Config.Global.IgnoreFleetCarrier;
// Apply theme
try {
2023-02-23 20:55:17 +01:00
AddCustomThemes();
string[] colours = ThemeManager.Current.Themes
.Select(x => x.ColorScheme)
.DistinctBy(x => x)
.OrderBy(x => x)
.ToArray()
;
2023-02-23 20:55:17 +01:00
foreach (var colour in colours) {
Colour.Items.Add(colour);
2023-02-23 20:55:17 +01:00
if (!string.IsNullOrEmpty(Config.Global.Colour) &&
string.Compare(colour, Config.Global.Colour, true) == 0) {
Colour.SelectedIndex = Colour.Items.Count - 1;
}
}
if (Colour.SelectedIndex < 0) {
Colour.SelectedIndex = 0;
}
SwitchTheme.IsOn = (string.Compare(Config.Global.Theme, "dark", true) == 0);
ThemeManager.Current.ChangeTheme(this, Config.Global.FullTheme);
} catch (Exception) {
2023-02-23 20:55:17 +01:00
// Theme is invalid, revert back to our standard dark theme
2023-02-26 10:09:50 +01:00
Config.Global.Colour = "Amber";
2023-02-23 20:55:17 +01:00
Config.Global.Theme = "Dark";
}
2022-11-24 19:38:19 +01:00
journal = new PlayerJournal(Config.Global.JournalLocation);
// Set both to now
2022-12-14 19:07:05 +01:00
InitialiseTime();
2022-11-24 19:38:19 +01:00
journallocation.Text = Config.Global.JournalLocation;
}
2023-02-23 20:55:17 +01:00
private void AddCustomThemes() {
Dictionary<string, Color> colorThemes = new() {
2023-02-23 20:57:43 +01:00
//{ "HouseSalus", Color.FromRgb(0xBC, 0x94, 0x39) },
{ "HouseSalus", Color.FromRgb(0xED, 0xDA, 0x70) },
2023-02-23 20:55:17 +01:00
{ "NovaNavy", Color.FromRgb(0xA1, 0xA4, 0xDB) },
2024-04-13 12:18:33 +02:00
// Official Red of the Polish Flag
{ "PolskaGurom", Color.FromRgb(0xD4, 0x21, 0x3D) },
2024-04-28 12:46:01 +02:00
// Official Blue in the Armenian Flag
{ "ArmeniaBlue", Color.FromRgb(0x00, 0x33, 0xA0) },
2023-02-23 20:55:17 +01:00
};
foreach (var colourtheme in colorThemes) {
var brush = new SolidColorBrush(colourtheme.Value);
// Add light theme
ThemeManager.Current.AddTheme(new Theme(
"Light." + colourtheme.Key,
"Light." + colourtheme.Key,
"Light",
colourtheme.Key,
colourtheme.Value,
brush,
true,
false)
);
// Add dark theme
ThemeManager.Current.AddTheme(new Theme(
"Dark." + colourtheme.Key,
"Dark." + colourtheme.Key,
"Dark",
colourtheme.Key,
colourtheme.Value,
brush,
true,
false)
);
}
}
2022-12-14 19:07:05 +01:00
private void InitialiseTime() {
DateTime today = DateTime.Today;
DateTime tomorrow = today.AddDays(1);
// HOCHKULTUR
startdate.Culture = enddate.Culture = CultureInfo.GetCultureInfo("de-AT");
2022-12-14 19:07:05 +01:00
startdate.SelectedDateTime = today;
enddate.SelectedDateTime = tomorrow;
}
2022-11-24 19:38:19 +01:00
private void TreeView_CheckBox_Updated(object sender, RoutedEventArgs args) {
GenerateLog();
}
private void Report_OnLog(string message) {
StringBuilder builder = new StringBuilder();
builder.Append(DateTime.Now.ToString());
builder.Append(": ");
builder.Append(message);
builder.Append("\n");
log.AppendText(builder.ToString());
}
private void Log(string message) {
Report_OnLog(message);
}
private void HandleEntries(List<Entry> entries, DateTime start, DateTime end) {
2022-11-24 19:38:19 +01:00
try {
TransactionParser parser = new();
TransactionParserOptions options = new();
options.IgnoreInfluenceSupport = Config.Global.IgnoreInfluenceSupport;
options.IgnoreMarketBuy = Config.Global.IgnoreMarketBuy;
options.IgnoreFleetCarrierFaction = Config.Global.IgnoreFleetCarrier;
List<Transaction> transactions = parser.Parse(entries, options);
2022-11-25 15:58:06 +01:00
Commanders.ItemsSource = parser.Commanders;
if (Commanders.Items.Count > 0) {
Commanders.SelectedIndex = 0;
}
// Filter the transactions down to the given time frame
transactions = transactions
.Where(t => t.CompletedAtDateTime >= start && t.CompletedAtDateTime <= end)
.ToList()
;
List<IncompleteTransaction> incompletes = transactions.OfType<IncompleteTransaction>().ToList();
2022-11-25 15:58:06 +01:00
// Log incomplete and remove them from the results.
foreach (var incomplete in incompletes) {
2022-11-25 15:58:06 +01:00
Log(incomplete.Reason);
}
transactions.RemoveAll(x => incompletes.Contains(x));
2022-11-24 19:38:19 +01:00
report = new Report(transactions);
this.entries.ItemsSource = report.SystemObjectives;
2022-11-24 19:38:19 +01:00
} catch (Exception exception) {
Log("Something went terribly wrong while parsing the E:D player journal.");
Log("Please send this to CMDR Hekateh:");
Log(exception.ToString());
}
}
private void HandleEntries(List<Entry> entries) {
HandleEntries(entries, startdate.SelectedDateTime ?? DateTime.Now, enddate.SelectedDateTime ?? DateTime.Now);
2022-11-24 19:38:19 +01:00
}
private void Loadentries_EntriesLoaded(List<Entry> lines) {
HandleEntries(lines);
2022-11-24 19:38:19 +01:00
}
private void ParseJournal_Click(object sender, RoutedEventArgs e) {
try {
TransactionParser parser = new TransactionParser();
DateTime start = startdate.SelectedDateTime ?? DateTime.Now;
DateTime end = enddate.SelectedDateTime ?? DateTime.Now;
2022-11-24 19:38:19 +01:00
journal.Open(); // Load all files
// Log files only get rotated if you restart the game client. This means that there might
// be - say - entries from the 4th of May in the file with a timestamp of 3rd of May. This
// happens if you happen to play a session late into the night.
// At first I tried extracting the first and last line of a file to see the date range, but
// if you have a lot of files this becomes quite slow, and quite the memory hog (as journal
// files have to be read in their entirety to check this). So we assume that you can't play
// three days straight, and keep the code fast.
DateTime actualstart = start.AddDays(-3);
DateTime actualend = end.AddDays(1);
2022-11-24 19:38:19 +01:00
List<Entry> entries = journal.Files
.Where(f => f.NormalisedDateTime >= actualstart && f.NormalisedDateTime <= actualend)
2022-11-24 19:38:19 +01:00
.SelectMany(e => e.Entries)
.ToList()
;
HandleEntries(entries, start, end);
2022-11-24 19:38:19 +01:00
GenerateLog();
2023-10-25 11:30:44 +02:00
var errors = journal.AllErrors;
foreach (var error in errors) {
Log("An error has occured in the Journal file, please send this to CMDR Hekateh:");
Log(error.ToString());
}
2022-11-24 19:38:19 +01:00
} catch (Exception exception) {
Log("Something went terribly wrong while parsing the E:D player journal.");
Log("Please send this to CMDR Hekateh:");
Log(exception.ToString());
}
}
private void GenerateLog() {
try {
DiscordLogGenerator discord = LogType.SelectedItem as DiscordLogGenerator;
string report = discord.GenerateDiscordLog(this.report);
DiscordLog.Text = report;
} catch (Exception exception) {
Log("Something went terribly wrong while generating the Discord log.");
Log("Please send this to CMDR Hekateh:");
Log(exception.ToString());
}
}
private void GenerateDiscord_Click(object sender, RoutedEventArgs e) {
GenerateLog();
}
private void RemoveCurrentObjective() {
if (entries.SelectedItem == null) {
return;
}
object obj = entries.SelectedItem;
bool removed = false;
2024-04-13 12:07:38 +02:00
if (obj.GetType() == typeof(SystemObjectives)) {
removed = report.SystemObjectives.Remove(obj as SystemObjectives);
} else if (obj.GetType() == typeof(Objective)) {
report
.SystemObjectives
.ForEach(x => {
if (x.Objectives.Remove(obj as Objective)) {
removed = true;
}
});
2022-11-24 19:38:19 +01:00
} else if (obj.GetType() == typeof(UITransaction) ||
2024-04-13 12:07:38 +02:00
obj.GetType().IsSubclassOf(typeof(UITransaction))) {
report
.SystemObjectives
.SelectMany(x =>
x.Objectives
.Where(x => x.UITransactions.Contains(obj as UITransaction))
)
.ToList()
.ForEach(x => removed = x.UITransactions.Remove(obj as UITransaction))
;
2022-11-24 19:38:19 +01:00
}
if (removed) {
2022-11-25 16:03:32 +01:00
RefreshView();
2022-11-24 19:38:19 +01:00
}
}
private void entries_KeyUp(object sender, KeyEventArgs e) {
2022-11-24 19:38:19 +01:00
if (e.Key == Key.Delete) {
RemoveCurrentObjective();
}
}
private void browsejournallocation_Click(object sender, RoutedEventArgs e) {
var dialog = new VistaFolderBrowserDialog();
if ((bool)!dialog.ShowDialog()) {
return;
}
Config.Global.JournalLocation = dialog.SelectedPath;
journallocation.Text = Config.Global.JournalLocation;
journal = new PlayerJournal(Config.Global.JournalLocation);
}
2022-12-14 19:28:23 +01:00
private Objective GetObjectiveFromControl(object sender) {
Control control = sender as Control;
if (control == null || control.DataContext == null) {
2022-12-14 19:28:23 +01:00
return null;
2022-11-24 19:38:19 +01:00
}
2022-12-14 19:28:23 +01:00
return control.DataContext as Objective;
}
private void AddCombatZone_Click(object sender, RoutedEventArgs e) {
Objective objective = GetObjectiveFromControl(sender);
if (objective == null) {
2022-11-24 19:38:19 +01:00
return;
}
CombatZone zone = new CombatZone {
Faction = objective.Faction,
System = objective.System,
Grade = "Low",
Type = "Ship",
2022-11-24 19:38:19 +01:00
};
2022-11-26 17:15:23 +01:00
UITransaction uitransaction = new UITransaction(zone);
objective.UITransactions.Add(uitransaction);
2022-11-25 16:03:32 +01:00
RefreshView();
}
private void RefreshView() {
entries.Items.Refresh();
2022-11-24 19:38:19 +01:00
GenerateLog();
}
private void LogType_SelectionChanged(object sender, SelectionChangedEventArgs e) {
if (LogType.SelectedItem == null) {
return;
}
string template = LogType.SelectedItem.ToString();
Config.Global.LastUsedDiscordTemplate = template;
GenerateLog();
}
private void ManuallyParse_Click(object sender, RoutedEventArgs e) {
if (loadentries != null) {
loadentries.Show();
return;
}
loadentries = new LoadEntriesWindow();
loadentries.Closed += Loadentries_Closed;
loadentries.EntriesLoaded += Loadentries_EntriesLoaded;
loadentries.Show();
}
private void Loadentries_Closed(object sender, EventArgs e) {
loadentries = null;
}
private void window_Closing(object sender, System.ComponentModel.CancelEventArgs e) {
loadentries?.Close();
loadentries = null;
try {
Config.SaveGlobal();
} catch (Exception error) {
MessageBox.Show("There was an error saving your settings: " + error.Message);
}
2022-11-24 19:38:19 +01:00
}
private void Transaction_Initialized(object sender, EventArgs e) {
}
private TransactionType GetTransaction<TransactionType>(object sender) where TransactionType : Transaction {
Control button = sender as Control;
if (button == null || button.DataContext == null) {
return null;
}
UITransaction transaction = button.DataContext as UITransaction;
if (transaction == null) {
return null;
}
return transaction.Transaction as TransactionType;
}
private void Low_Click(object sender, RoutedEventArgs e) {
CombatZone transaction = GetTransaction<CombatZone>(sender);
if (transaction == null) {
return;
}
transaction.Grade = CombatZones.DifficultyLow;
RefreshView();
}
private void Med_Click(object sender, RoutedEventArgs e) {
CombatZone transaction = GetTransaction<CombatZone>(sender);
if (transaction == null) {
return;
}
transaction.Grade = CombatZones.DifficultyMedium;
RefreshView();
}
private void High_Click(object sender, RoutedEventArgs e) {
CombatZone transaction = GetTransaction<CombatZone>(sender);
if (transaction == null) {
return;
}
transaction.Grade = CombatZones.DifficultyHigh;
RefreshView();
}
private void VeryHigh_Click(object sender, RoutedEventArgs e) {
CombatZone transaction = GetTransaction<CombatZone>(sender);
if (transaction == null) {
return;
}
transaction.Grade = CombatZones.DifficultyVeryHigh;
RefreshView();
}
2022-11-29 17:52:27 +01:00
private void Ground_Click(object sender, RoutedEventArgs e) {
CombatZone transaction = GetTransaction<CombatZone>(sender);
if (transaction == null) {
return;
}
transaction.Type = CombatZones.GroundCombatZone;
RefreshView();
}
private void Ship_Click(object sender, RoutedEventArgs e) {
CombatZone transaction = GetTransaction<CombatZone>(sender);
if (transaction == null) {
return;
}
transaction.Type = CombatZones.ShipCombatZone;
RefreshView();
}
2022-12-03 14:47:31 +01:00
private void Thargoid_Click(object sender, RoutedEventArgs e) {
CombatZone transaction = GetTransaction<CombatZone>(sender);
if (transaction == null) {
return;
}
transaction.Type = CombatZones.AXCombatZone;
2022-12-03 14:47:31 +01:00
RefreshView();
}
2022-11-29 18:05:08 +01:00
private void Profit_LostFocus(object sender, RoutedEventArgs e) {
RefreshView();
}
2022-11-29 18:05:08 +01:00
private void Profit_KeyUp(object sender, System.Windows.Input.KeyEventArgs e) {
if (e.Key == Key.Enter) {
RefreshView();
}
}
2022-12-14 19:07:05 +01:00
private DateTime ResetTimeToZero(DateTime d) {
DateTime obj = d;
obj = obj.AddHours(d.Hour * -1);
obj = obj.AddMinutes(d.Minute * -1);
obj = obj.AddSeconds(d.Second * -1);
return obj;
}
private void ResetTime_Click(object sender, RoutedEventArgs e) {
DateTime? d = startdate.SelectedDateTime;
2022-12-14 19:07:05 +01:00
if (d != null) {
startdate.SelectedDateTime = ResetTimeToZero(d.Value);
2022-12-14 19:07:05 +01:00
}
d = enddate.SelectedDateTime;
2022-12-14 19:07:05 +01:00
if (d != null) {
enddate.SelectedDateTime = ResetTimeToZero(d.Value);
2022-12-14 19:07:05 +01:00
}
}
2022-12-14 19:28:23 +01:00
private void ToggleAll_Click(object sender, RoutedEventArgs e) {
ToggleButton button = sender as ToggleButton;
Objective objective = GetObjectiveFromControl(sender);
if (objective == null) {
return;
}
objective.UITransactions
.ForEach(x => x.IsEnabled = (button.IsChecked ?? true))
;
}
private void UpdateTheme() {
ThemeManager.Current.ChangeTheme(this, Config.Global.FullTheme);
}
private void SwitchTheme_Toggled(object sender, RoutedEventArgs e) {
ToggleSwitch toggle = sender as ToggleSwitch;
if (toggle.IsOn) {
Config.Global.Theme = "Dark";
} else {
Config.Global.Theme = "Light";
}
UpdateTheme();
}
private void Colour_SelectionChanged(object sender, SelectionChangedEventArgs e) {
if (Colour.SelectedItem == null) {
return;
}
Config.Global.Colour = Colour.SelectedItem.ToString();
UpdateTheme();
}
private void URL_RequestNavigate(object sender, System.Windows.Navigation.RequestNavigateEventArgs e) {
ProcessStartInfo info = new ProcessStartInfo();
info.UseShellExecute = true;
info.FileName = e.Uri.AbsoluteUri;
Process.Start(info);
e.Handled = true;
}
private void NoInfluenceSupport_Toggled(object sender, RoutedEventArgs e) {
Config.Global.IgnoreInfluenceSupport = this.NoInfluenceSupport.IsOn;
}
private void NoMarketBuy_Toggled(object sender, RoutedEventArgs e) {
Config.Global.IgnoreMarketBuy = this.NoMarketBuy.IsOn;
}
private void NoFleetCarrier_Toggled(object sender, RoutedEventArgs e) {
Config.Global.IgnoreFleetCarrier = this.NoFleetCarrier.IsOn;
}
2023-05-15 18:44:11 +02:00
private void OpenInExplorer_Click(object sender, RoutedEventArgs e) {
try {
Process.Start(new ProcessStartInfo(Config.Global.JournalLocation) {
UseShellExecute = true,
});
} catch (Exception) {
}
}
private void SelectAll_Click(object sender, RoutedEventArgs e) {
if (report == null) {
return;
}
report.SystemObjectives.ForEach(t => { t.IsEnabled = (bool)SelectAll.IsChecked; });
}
private void AddWebHook_Click(object sender, RoutedEventArgs e) {
Config.Global.Webhooks.Add(new DiscordWebhook {
Name = "Discord Server Name",
Webhook = "..."
});
Webhooks.Items.Refresh();
RefreshPostMenu();
}
private void RemoveWebHook_Click(object sender, RoutedEventArgs e) {
if (Webhooks.SelectedItems.Count <= 0) {
return;
}
var selection = Webhooks.SelectedItems
.OfType<DiscordWebhook>()
.ToList()
;
foreach (var item in selection) {
Config.Global.Webhooks.Remove(item);
}
Webhooks.Items.Refresh();
RefreshPostMenu();
}
private void Webhooks_KeyUp(object sender, KeyEventArgs e) {
DataGridCell cell = e.OriginalSource as DataGridCell;
/* We also get keypresses from DataGridCells that are currently
* editing their content. Filter those out. We don't want to delete
* the row when the user presses DEL while editing the cells content
*/
if (cell == null || cell.IsEditing) {
return;
}
if (e.Key == Key.Delete) {
RemoveWebHook_Click(this, new RoutedEventArgs());
}
}
private void Webhooks_CellEditEnding(object sender, DataGridCellEditEndingEventArgs e) {
try {
Config.SaveGlobal();
} catch (Exception) { }
e.Cancel = false;
RefreshPostMenu();
}
private void RefreshPostMenu() {
MenuItem menu;
PostToDiscord.Items.Clear();
if (Config.Global.Webhooks.Count <= 0) {
PostToDiscord.IsEnabled = false;
} else {
PostToDiscord.IsEnabled = true;
foreach (var item in Config.Global.Webhooks) {
menu = new MenuItem();
menu.Header = item.Name;
menu.Click += DiscordWebhook_Click;
PostToDiscord.Items.Add(menu);
}
PostToDiscord.Items.Add(new Separator());
menu = new MenuItem();
menu.Header = "Post To All";
menu.Click += PostToAll_Click;
PostToDiscord.Items.Add(menu);
}
}
2024-09-18 21:10:41 +02:00
private void PostToDiscordWebhook(IEnumerable<DiscordWebhook> hooks) {
if (string.IsNullOrEmpty(DiscordLog.Text)) {
return;
}
2024-09-18 21:10:41 +02:00
DiscordLogGenerator discord = LogType.SelectedItem as DiscordLogGenerator;
string[] chunks;
try {
2024-09-18 21:10:41 +02:00
chunks = discord.SplitLog(DiscordLog.Text);
} catch (Exception) {
MessageBox.Show(
"The log could not be split into discord appropriate length.\n" +
"This happens with the bigger logs formats if you do lots of things in one system.\n" +
"Try posting the log in the OneLine format.",
"Sorry!", MessageBoxButton.OK, MessageBoxImage.Error
);
return;
}
string commander = "EDBGS";
if (Commanders.SelectedIndex >= 0) {
commander = Commanders.SelectedItem.ToString();
}
2024-09-18 21:10:41 +02:00
foreach (var hook in hooks) {
try {
foreach (var chunk in chunks) {
DiscordPoster.PostToDiscord(hook, chunk, commander);
2024-09-18 21:10:41 +02:00
}
Log(string.Format("successfully posted to discord webhook `{0}`", hook.Name));
} catch (Exception ex) {
Log(string.Format("failed to post to discord webhook `{0}`: {1}",
hook.Name, ex.Message));
}
}
}
private void DiscordWebhook_Click(object sender, RoutedEventArgs e) {
MenuItem item = sender as MenuItem;
if (item == null) {
return;
}
DiscordWebhook hook = Config.Global.Webhooks
.Find(x => string.Compare(x.Name, item.Header.ToString()) == 0)
;
if (hook == null) {
return;
}
2024-09-18 21:10:41 +02:00
PostToDiscordWebhook(new DiscordWebhook[] { hook });
}
private void PostToAll_Click(object sender, RoutedEventArgs e) {
2024-09-18 21:10:41 +02:00
PostToDiscordWebhook(Config.Global.Webhooks);
}
2022-11-24 19:38:19 +01:00
}