From ca47896204482bf4a6979e3838bf7f09f61cebeb Mon Sep 17 00:00:00 2001 From: giy <giy@omp-system.ru> Date: Fri, 02 Sep 2022 14:16:56 +0300 Subject: [PATCH] Обновление до версии 2.9.0 --- QtVsTools.Package/Options/QtVersionsTable.cs | 348 +++++++++++++++++++++++++++++++++------------------------ 1 files changed, 202 insertions(+), 146 deletions(-) diff --git a/QtVsTools.Package/Options/QtVersionsTable.cs b/QtVsTools.Package/Options/QtVersionsTable.cs index dc6f9c5..cb09fff 100644 --- a/QtVsTools.Package/Options/QtVersionsTable.cs +++ b/QtVsTools.Package/Options/QtVersionsTable.cs @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2020 The Qt Company Ltd. +** Copyright (C) 2022 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt VS Tools. @@ -37,11 +37,12 @@ using System.Windows.Media; using System.Windows.Media.Imaging; using Microsoft.Win32; -using QtVsTools.Common; namespace QtVsTools.Options { - using static EnumExt; + using Common; + using QtVsTools.Core; + using static Common.EnumExt; public enum BuildHost { @@ -52,9 +53,28 @@ public partial class QtVersionsTable : UserControl { + LazyFactory Lazy { get; } = new LazyFactory(); + public QtVersionsTable() { InitializeComponent(); + } + + [Flags] public enum Column + { + IsDefault = 0x10, + VersionName = 0x20, + Host = 0x40, + Path = 0x80, + Compiler = 0x100 + } + + [Flags] public enum State + { + Unknown = 0x00, + Existing = 0x01, + Removed = 0x02, + Modified = 0x04 } public class Field @@ -62,57 +82,66 @@ public string Value { get; set; } public Control Control { get; set; } public DataGridCell Cell { get; set; } - public string ValidationError { get; set; } + private string error; + public string ValidationError { + set { + UpdateUi = value != error; + error = value; + } + get { return error; } + } public bool IsValid => string.IsNullOrEmpty(ValidationError); public ToolTip ToolTip => IsValid ? null : new ToolTip() { Content = ValidationError }; public int SelectionStart { get; set; } + public bool UpdateUi { get; private set; } = false; } public class Row { - public enum FieldNames { IsDefault, VersionName, Host, Path, Compiler } + static LazyFactory StaticLazy { get; } = new LazyFactory(); + LazyFactory Lazy { get; } = new LazyFactory(); - public Dictionary<FieldNames, Field> _Fields; - public Dictionary<FieldNames, Field> Fields => _Fields - ?? (_Fields = GetValues<FieldNames>() - .Select(field => new KeyValuePair<FieldNames, Field>(field, null)) + public Dictionary<Column, Field> Fields => Lazy.Get(() => + Fields, () => GetValues<Column>() + .Select(field => new KeyValuePair<Column, Field>(field, null)) .ToDictionary(keyValue => keyValue.Key, keyValue => keyValue.Value)); - public Field FieldDefault => Fields[FieldNames.IsDefault] - ?? (Fields[FieldNames.IsDefault] = new Field()); + public Field FieldDefault => Fields[Column.IsDefault] + ?? (Fields[Column.IsDefault] = new Field()); public bool IsDefault { get => (FieldDefault.Value == true.ToString()); set => FieldDefault.Value = value.ToString(); } - public Field FieldVersionName => Fields[FieldNames.VersionName] - ?? (Fields[FieldNames.VersionName] = new Field()); + public Field FieldVersionName => Fields[Column.VersionName] + ?? (Fields[Column.VersionName] = new Field()); public string VersionName { get => FieldVersionName.Value; set => FieldVersionName.Value = value; } + public string InitialVersionName { get; set; } - public Field FieldHost => Fields[FieldNames.Host] - ?? (Fields[FieldNames.Host] = new Field()); + public Field FieldHost => Fields[Column.Host] + ?? (Fields[Column.Host] = new Field()); public BuildHost Host { get => FieldHost.Value.Cast(defaultValue: BuildHost.Windows); set => FieldHost.Value = value.Cast<string>(); } - public Field FieldPath => Fields[FieldNames.Path] - ?? (Fields[FieldNames.Path] = new Field()); + public Field FieldPath => Fields[Column.Path] + ?? (Fields[Column.Path] = new Field()); public string Path { get => FieldPath.Value; set => FieldPath.Value = value; } - public Field FieldCompiler => Fields[FieldNames.Compiler] - ?? (Fields[FieldNames.Compiler] = new Field()); + public Field FieldCompiler => Fields[Column.Compiler] + ?? (Fields[Column.Compiler] = new Field()); public string Compiler { get => FieldCompiler.Value; @@ -124,7 +153,7 @@ public bool DefaultEnabled => !IsDefault && !LastRow; public bool NameEnabled => !LastRow; public bool CompilerEnabled => (Host != BuildHost.Windows); - public Visibility RowVisibility + public Visibility RowContentVisibility => LastRow ? Visibility.Hidden : Visibility.Visible; public Visibility ButtonAddVisibility => LastRow ? Visibility.Visible : Visibility.Hidden; @@ -135,17 +164,16 @@ public FontWeight FontWeight => IsDefault ? FontWeights.Bold : FontWeights.Normal; - public static ImageSource _ExplorerIcon; - public static ImageSource ExplorerIcon => _ExplorerIcon - ?? (_ExplorerIcon = GetExplorerIcon()); - } + public static ImageSource ExplorerIcon => StaticLazy.Get(() => + ExplorerIcon, () => GetExplorerIcon()); - public bool IsValid { get; private set; } + public State State { get; set; } = State.Unknown; + public bool RowVisible => State != State.Removed; + } Field FocusedField { get; set; } - List<Row> _Rows; - List<Row> Rows => _Rows ?? (_Rows = new List<Row>()); + List<Row> Rows => Lazy.Get(() => Rows, () => new List<Row>()); public IEnumerable<Row> Versions => Rows.TakeWhile(item => !item.LastRow); public void UpdateVersions(IEnumerable<Row> versions) @@ -154,15 +182,16 @@ Rows.AddRange(versions); Rows.Add(new Row { LastRow = true }); DataGrid.ItemsSource = Rows; - IsValid = true; FocusedField = null; Validate(true); + Rows.ForEach(item => item.State = State.Existing); } public IEnumerable<string> GetErrorMessages() { Validate(true); return Versions + .Where(v => v.State != State.Removed) .SelectMany(v => v.Fields.Values.Select(f => f.ValidationError)) .Where(s => !string.IsNullOrEmpty(s)) .Distinct(); @@ -170,95 +199,73 @@ void Validate(bool mustRefresh) { - ///////////////////////// - // Automatic cell values - foreach (var version in Versions) { - if (version.Host != BuildHost.Windows && version.Compiler == "msvc") { - version.Compiler = "g++"; - version.FieldCompiler.SelectionStart = version.Compiler.Length; - mustRefresh = true; - } else if (version.Host == BuildHost.Windows && version.Compiler != "msvc") { - version.Compiler = "msvc"; - version.FieldCompiler.SelectionStart = version.Compiler.Length; - mustRefresh = true; - } - } - //////////////////////// // Validate cell values - string previousValidation; - bool wasValid = IsValid; - IsValid = true; foreach (var version in Versions) { + if (!version.State.HasFlag(State.Modified)) + continue; ////////////////////// // Default validation - previousValidation = version.FieldDefault.ValidationError; - version.FieldDefault.ValidationError = null; - if (version.IsDefault && version.Host != BuildHost.Windows) { - version.FieldDefault.ValidationError = "Default version: host must be Windows"; - IsValid = false; + if (version.State.HasFlag((State)Column.IsDefault)) { + version.FieldDefault.ValidationError = null; + if (version.IsDefault && version.Host != BuildHost.Windows) + version.FieldDefault.ValidationError = "Default version: Host must be Windows"; + mustRefresh |= version.FieldDefault.UpdateUi; } - if (previousValidation != version.FieldDefault.ValidationError) - mustRefresh = true; /////////////////// // Name validation - previousValidation = version.FieldVersionName.ValidationError; - version.FieldVersionName.ValidationError = null; - if (string.IsNullOrEmpty(version.VersionName)) { - version.FieldVersionName.ValidationError = "Name cannot be empty"; - IsValid = false; - } else if (Versions - .Where(otherVersion => otherVersion != version - && otherVersion.VersionName == version.VersionName) - .Any()) { - version.FieldVersionName.ValidationError = "Duplicate version names"; - IsValid = false; + if (version.State.HasFlag((State)Column.VersionName)) { + version.FieldVersionName.ValidationError = null; + if (string.IsNullOrEmpty(version.VersionName)) { + version.FieldVersionName.ValidationError = "Name cannot be empty"; + } else if (Versions.Where(otherVersion => otherVersion != version + && otherVersion.VersionName == version.VersionName).Any()) { + version.FieldVersionName.ValidationError = "Duplicate version names"; + } + mustRefresh |= version.FieldVersionName.UpdateUi; } - if (previousValidation != version.FieldVersionName.ValidationError) - mustRefresh = true; /////////////////// // Host validation - previousValidation = version.FieldHost.ValidationError; - version.FieldHost.ValidationError = null; - if (version.IsDefault && version.Host != BuildHost.Windows) { - version.FieldHost.ValidationError = "Default version: host must be Windows"; - IsValid = false; + if (version.State.HasFlag((State)Column.Host)) { + version.FieldHost.ValidationError = null; + if (version.IsDefault && version.Host != BuildHost.Windows) + version.FieldHost.ValidationError = "Default version: Host must be Windows"; + mustRefresh |= version.FieldHost.UpdateUi; } - if (previousValidation != version.FieldHost.ValidationError) - mustRefresh = true; /////////////////// // Path validation - previousValidation = version.FieldPath.ValidationError; - version.FieldPath.ValidationError = null; - if (string.IsNullOrEmpty(version.Path)) { - version.FieldPath.ValidationError = "Path cannot be empty"; - IsValid = false; - } else if (version.Host == BuildHost.Windows && !Directory.Exists(version.Path)) { - version.FieldPath.ValidationError = "Path does not exist"; - IsValid = false; + if (version.State.HasFlag((State)Column.Path)) { + version.FieldPath.ValidationError = null; + if (string.IsNullOrEmpty(version.Path)) { + version.FieldPath.ValidationError = "Path cannot be empty"; + } else if (version.Host == BuildHost.Windows) { + string path = NormalizePath(version.Path); + if (path == null) { + version.FieldPath.ValidationError = "Invalid path format"; + } else { + if (!QMake.Exists(path)) + version.FieldPath.ValidationError = "Cannot find qmake.exe"; + } + } + mustRefresh |= version.FieldPath.UpdateUi; } - if (previousValidation != version.FieldPath.ValidationError) - mustRefresh = true; /////////////////////// // Compiler validation - previousValidation = version.FieldCompiler.ValidationError; - version.FieldCompiler.ValidationError = null; - if (string.IsNullOrEmpty(version.Compiler)) { - version.FieldCompiler.ValidationError = "Compiler cannot be empty"; - IsValid = false; + if (version.State.HasFlag((State)Column.Compiler)) { + version.FieldCompiler.ValidationError = null; + if (string.IsNullOrEmpty(version.Compiler)) + version.FieldCompiler.ValidationError = "Compiler cannot be empty"; + mustRefresh |= version.FieldCompiler.UpdateUi; } - if (previousValidation != version.FieldCompiler.ValidationError) - mustRefresh = true; } ////////////////////////////////////// // Refresh versions table if required - mustRefresh |= (wasValid != IsValid); if (mustRefresh) { // Reset bindings foreach (var version in Versions) { @@ -304,22 +311,20 @@ if (sender is Control control && GetBinding(control) is Row version) { if (version.LastRow) return; - - Row.FieldNames field; - if (string.IsNullOrEmpty(control.Name) || !control.Name.TryCast(out field)) + if (string.IsNullOrEmpty(control.Name) || !control.Name.TryCast(out Column column)) return; - var fieldBinding = version.Fields[field]; - fieldBinding.Control = control; - fieldBinding.Cell = FindContainingCell(control); - if (fieldBinding.Cell != null) { - fieldBinding.Cell.Background = - fieldBinding.IsValid ? Brushes.Transparent : InvalidCellBackground; + var field = version.Fields[column]; + field.Control = control; + field.Cell = FindContainingCell(control); + if (field.Cell != null) { + field.Cell.Background = + field.IsValid ? Brushes.Transparent : InvalidCellBackground; } - if (fieldBinding == FocusedField) + if (field == FocusedField) control.Focus(); - if (control is TextBox textBox && fieldBinding.SelectionStart >= 0) - textBox.Select(fieldBinding.SelectionStart, 0); + if (control is TextBox textBox && field.SelectionStart >= 0) + textBox.Select(field.SelectionStart, 0); } } @@ -339,24 +344,24 @@ void Control_GotFocus(object sender, RoutedEventArgs e) { if (sender is Control control && GetBinding(control) is Row version) { - Row.FieldNames field; - if (string.IsNullOrEmpty(control.Name) || !control.Name.TryCast(out field)) + if (string.IsNullOrEmpty(control.Name) || !control.Name.TryCast(out Column column)) return; - var fieldBinding = version.Fields[field]; - if (fieldBinding.Control != control) + + var field = version.Fields[column]; + if (field.Control != control) return; - FocusedField = fieldBinding; + FocusedField = field; } } void Control_LostFocus(object sender, RoutedEventArgs e) { if (sender is Control control && GetBinding(control) is Row version) { - Row.FieldNames field; - if (string.IsNullOrEmpty(control.Name) || !control.Name.TryCast(out field)) + if (string.IsNullOrEmpty(control.Name) || !control.Name.TryCast(out Column column)) return; - var fieldBinding = version.Fields[field]; - if (fieldBinding != FocusedField || fieldBinding.Control != control) + + var field = version.Fields[column]; + if (field != FocusedField || field.Control != control) return; FocusedField = null; } @@ -365,29 +370,32 @@ void TextBox_SelectionChanged(object sender, RoutedEventArgs e) { if (sender is TextBox textBox && GetBinding(textBox) is Row version) { - Row.FieldNames field; - if (string.IsNullOrEmpty(textBox.Name) || !textBox.Name.TryCast(out field)) + if (string.IsNullOrEmpty(textBox.Name) || !textBox.Name.TryCast(out Column column)) return; - var fieldBinding = version.Fields[field]; - if (fieldBinding.Control != textBox) + + var field = version.Fields[column]; + if (field.Control != textBox) return; - fieldBinding.SelectionStart = textBox.SelectionStart; + field.SelectionStart = textBox.SelectionStart; } } void TextBox_TextChanged(object sender, TextChangedEventArgs e) { if (sender is TextBox textBox && GetBinding(textBox) is Row version) { - Row.FieldNames field; - if (string.IsNullOrEmpty(textBox.Name) || !textBox.Name.TryCast(out field)) + if (string.IsNullOrEmpty(textBox.Name) || !textBox.Name.TryCast(out Column column)) return; - var fieldBinding = version.Fields[field]; - if (fieldBinding == null - || fieldBinding.Control != textBox - || fieldBinding.Value == textBox.Text) + + var field = version.Fields[column]; + if (field == null + || field.Control != textBox + || field.Value == textBox.Text) return; - fieldBinding.SelectionStart = textBox.SelectionStart; - fieldBinding.Value = textBox.Text; + + field.SelectionStart = textBox.SelectionStart; + field.Value = textBox.Text; + version.State |= State.Modified | (State)column; + Validate(false); } } @@ -397,28 +405,49 @@ if (sender is ComboBox comboBox && GetBinding(comboBox) is Row version) { if (!comboBox.IsEnabled || comboBox.SelectedIndex < 0) return; + if (string.IsNullOrEmpty(comboBox.Name) || !comboBox.Name.TryCast(out Column column)) + return; + string comboBoxValue = comboBox.Items[comboBox.SelectedIndex] as string; - string controlName = comboBox.Name; - Row.FieldNames field; - if (string.IsNullOrEmpty(controlName) || !controlName.TryCast(out field)) + var field = version.Fields[column]; + if (field == null + || field.Control != comboBox + || field.Value == comboBoxValue) return; - var fieldBinding = version.Fields[field]; - if (fieldBinding == null - || fieldBinding.Control != comboBox - || fieldBinding.Value == comboBoxValue) - return; - fieldBinding.Value = comboBoxValue; - Validate(false); + + field.Value = comboBoxValue; + version.State |= State.Modified | (State)Column.Host; + + bool mustRefresh = false; + if (version.Host != BuildHost.Windows && version.Compiler == "msvc") { + version.Compiler = "g++"; + version.FieldCompiler.SelectionStart = version.Compiler.Length; + version.State |= (State)Column.Compiler; + mustRefresh = true; + } else if (version.Host == BuildHost.Windows && version.Compiler != "msvc") { + version.Compiler = "msvc"; + version.FieldCompiler.SelectionStart = version.Compiler.Length; + version.State |= (State)Column.Compiler; + mustRefresh = true; + } + + Validate(mustRefresh); } + } + + static void SetDefaultState(ref Row version, bool value) + { + version.IsDefault = value; + version.State |= State.Modified | (State)Column.IsDefault; } void Default_Click(object sender, RoutedEventArgs e) { if (sender is CheckBox checkBox && GetBinding(checkBox) is Row version) { - var defaultVersion = Rows.Where(row => row.IsDefault).FirstOrDefault(); + var defaultVersion = Rows.FirstOrDefault(row => row.IsDefault); if (defaultVersion != null) - defaultVersion.IsDefault = false; - version.IsDefault = true; + SetDefaultState(ref defaultVersion, false); + SetDefaultState(ref version, true); Validate(true); } } @@ -427,12 +456,16 @@ { var version = new Row() { - IsDefault = !Versions.Any(), + IsDefault = !Versions.Any(x => x.State != State.Removed), Host = BuildHost.Windows, Path = "", Compiler = "msvc", - LastRow = false + LastRow = false, + State = State.Modified | (State)Column.VersionName | (State)Column.Host + | (State)Column.Path | (State)Column.Compiler }; + if (version.IsDefault) + version.State |= (State)Column.IsDefault; Rows.Insert(Rows.Count - 1, version); FocusedField = version.FieldVersionName; Validate(true); @@ -441,10 +474,26 @@ void Remove_Click(object sender, RoutedEventArgs e) { if (sender is Button button && GetBinding(button) is Row version) { - Rows.Remove(version); - if (version.IsDefault && Versions.Any()) - Versions.First().IsDefault = true; + version.State = State.Removed; + if (version.IsDefault) { + var first = Versions.FirstOrDefault(x => x.State != State.Removed); + if (first != null) + SetDefaultState(ref first, true); + } Validate(true); + } + } + + static string NormalizePath(string path) + { + if (string.IsNullOrEmpty(path)) + return path; + try { + return Path.GetFullPath(new Uri(path).LocalPath) + .TrimEnd(Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar) + .ToUpperInvariant(); + } catch (UriFormatException) { + return null; } } @@ -462,6 +511,7 @@ if (openFileDialog.ShowDialog() == true) { var qmakePath = openFileDialog.FileName; var qmakeDir = Path.GetDirectoryName(qmakePath); + var previousPath = NormalizePath(version.Path); if (Path.GetFileName(qmakeDir) .Equals("bin", StringComparison.InvariantCultureIgnoreCase)) { qmakeDir = Path.GetDirectoryName(qmakeDir); @@ -469,12 +519,18 @@ } else { version.Path = qmakePath; } + + if (previousPath != NormalizePath(version.Path)) + version.State |= State.Modified | (State)Column.Path; + if (string.IsNullOrEmpty(version.VersionName)) { version.VersionName = string.Format("{0}_{1}", Path.GetFileName(Path.GetDirectoryName(qmakeDir)), Path.GetFileName(qmakeDir)) .Replace(" ", "_"); + version.State |= State.Modified | (State)Column.VersionName; } + Validate(true); } } @@ -503,9 +559,9 @@ static object GetBinding(FrameworkElement control) { if (control == null - || control.BindingGroup == null - || control.BindingGroup.Items == null - || control.BindingGroup.Items.Count == 0) { + || control.BindingGroup == null + || control.BindingGroup.Items == null + || control.BindingGroup.Items.Count == 0) { return null; } return control.BindingGroup.Items[0]; @@ -515,7 +571,7 @@ { while (control != null) { if (control is ContentPresenter contentPresenter - && contentPresenter.Parent is DataGridCell cell) { + && contentPresenter.Parent is DataGridCell cell) { return cell; } control = VisualTreeHelper.GetParent(control); -- Gitblit v1.9.1