public SettingsViewModel(Library library, ViewSettings viewSettings, CoreSettings coreSettings, IWindowManager windowManager, Guid accessToken, MobileApiInfo mobileApiInfo) { if (library == null) Throw.ArgumentNullException(() => library); if (viewSettings == null) Throw.ArgumentNullException(() => viewSettings); if (coreSettings == null) Throw.ArgumentNullException(() => coreSettings); if (mobileApiInfo == null) throw new ArgumentNullException("mobileApiInfo"); this.library = library; this.viewSettings = viewSettings; this.coreSettings = coreSettings; this.windowManager = windowManager; this.accessToken = accessToken; this.canCreateAdmin = this .WhenAnyValue(x => x.CreationPassword, x => !string.IsNullOrWhiteSpace(x) && !this.isAdminCreated) .ToProperty(this, x => x.CanCreateAdmin); this.CreateAdminCommand = ReactiveCommand.Create(this.WhenAnyValue(x => x.CanCreateAdmin), ImmediateScheduler.Instance); // Immediate execution, because we set the password to an empty string afterwards this.CreateAdminCommand.Subscribe(p => { this.library.LocalAccessControl.SetLocalPassword(this.accessToken, this.CreationPassword); this.isAdminCreated = true; }); this.ChangeToPartyCommand = ReactiveCommand.Create(this.CreateAdminCommand.Select(x => true).StartWith(false)); this.ChangeToPartyCommand.Subscribe(p => { this.library.LocalAccessControl.DowngradeLocalAccess(this.accessToken); this.ShowSettings = false; }); this.canLogin = this.WhenAnyValue(x => x.LoginPassword, x => !string.IsNullOrWhiteSpace(x)) .ToProperty(this, x => x.CanLogin); this.LoginCommand = ReactiveCommand.Create(this.WhenAnyValue(x => x.CanLogin), ImmediateScheduler.Instance); // Immediate execution, because we set the password to an empty string afterwards this.LoginCommand.Subscribe(p => { try { this.library.LocalAccessControl.UpgradeLocalAccess(this.accessToken, this.LoginPassword); this.IsWrongPassword = false; this.ShowLogin = false; this.ShowSettings = true; } catch (WrongPasswordException) { this.IsWrongPassword = true; } }); this.OpenLinkCommand = ReactiveCommand.Create(); this.OpenLinkCommand.Cast<string>().Subscribe(x => { try { Process.Start(x); } catch (Win32Exception ex) { this.Log().ErrorException(String.Format("Could not open link {0}", x), ex); } }); this.ReportBugCommand = ReactiveCommand.Create(); this.ReportBugCommand.Subscribe(p => this.windowManager.ShowWindow(new BugReportViewModel())); this.ChangeAccentColorCommand = ReactiveCommand.Create(); this.ChangeAccentColorCommand.Subscribe(x => this.viewSettings.AccentColor = (string)x); this.ChangeAppThemeCommand = ReactiveCommand.Create(); this.ChangeAppThemeCommand.Subscribe(x => this.viewSettings.AppTheme = (string)x); this.UpdateLibraryCommand = ReactiveCommand.Create(this.library.WhenAnyValue(x => x.IsUpdating, x => !x) .ObserveOn(RxApp.MainThreadScheduler) .CombineLatest(this.library.WhenAnyValue(x => x.SongSourcePath).Select(x => !String.IsNullOrEmpty(x)), (x1, x2) => x1 && x2)); this.UpdateLibraryCommand.Subscribe(_ => this.library.UpdateNow()); this.librarySource = this.library.WhenAnyValue(x => x.SongSourcePath) .ToProperty(this, x => x.LibrarySource); this.port = this.coreSettings.Port; this.ChangePortCommand = ReactiveCommand.Create(this.WhenAnyValue(x => x.Port, NetworkHelpers.IsPortValid)); this.ChangePortCommand.Subscribe(_ => this.coreSettings.Port = this.Port); this.remoteControlPassword = this.coreSettings.RemoteControlPassword; this.ChangeRemoteControlPasswordCommand = ReactiveCommand.Create(this.WhenAnyValue(x => x.RemoteControlPassword) .Select(x => !String.IsNullOrWhiteSpace(x))); this.ChangeRemoteControlPasswordCommand.Subscribe(x => this.library.RemoteAccessControl.SetRemotePassword(this.accessToken, this.RemoteControlPassword)); this.showRemoteControlPasswordError = this.WhenAnyValue(x => x.RemoteControlPassword, x => x.LockRemoteControl, (password, lockRemoteControl) => String.IsNullOrWhiteSpace(password) && lockRemoteControl) .ToProperty(this, x => x.ShowRemoteControlPasswordError); this.isRemoteAccessReallyLocked = this.library.RemoteAccessControl.WhenAnyValue(x => x.IsRemoteAccessReallyLocked) .ToProperty(this, x => x.IsRemoteAccessReallyLocked); this.isPortOccupied = mobileApiInfo.IsPortOccupied.ToProperty(this, x => x.IsPortOccupied); this.enableChangelog = this.viewSettings.WhenAnyValue(x => x.EnableChangelog) .ToProperty(this, x => x.EnableChangelog); this.defaultPlaybackEngine = this.coreSettings.WhenAnyValue(x => x.DefaultPlaybackEngine) .ToProperty(this, x => x.DefaultPlaybackEngine); }
private protected DynamicMethod CreateMethodInvokerAsDynamicMethod(MethodBase methodBase, DynamicMethodOptions options) { #region Local Methods (string name, List <Type> parameters) GetNameAndParams(MethodBase methodOrCtor, DynamicMethodOptions o) { List <Type> parameters = new List <Type>(); string name; bool forceMethod = (o & DynamicMethodOptions.TreatCtorAsMethod) != DynamicMethodOptions.None; if (methodOrCtor is ConstructorInfo && !forceMethod) { // ReSharper disable once PossibleNullReferenceException - already checked by caller name = ctorInvokerPrefix + methodOrCtor.DeclaringType.Name; parameters.Add(typeof(object[])); // ctor parameters } else { name = methodInvokerPrefix + methodOrCtor.Name; parameters.Add(Reflector.ObjectType); // instance parameter // not a property setter if ((o & DynamicMethodOptions.TreatAsPropertySetter) == DynamicMethodOptions.None) { if ((o & DynamicMethodOptions.OmitParameters) == DynamicMethodOptions.None) { parameters.Add(typeof(object[])); // method parameters } } // property setter else { parameters.Add(Reflector.ObjectType); // value if (ParameterTypes.Length > 0) { parameters.Add(typeof(object[])); // indexer parameters } } } return(name, parameters); } void GenerateLocalsForRefParams(MethodBase methodorCtor, ILGenerator il, DynamicMethodOptions o) { if ((o & DynamicMethodOptions.HandleByRefParameters) == DynamicMethodOptions.None) { return; } ParameterInfo[] parameters = methodorCtor.GetParameters(); for (int i = 0, localsIndex = 0; i < ParameterTypes.Length; i++) { if (!ParameterTypes[i].IsByRef) { continue; } Type paramType = ParameterTypes[i].GetElementType(); // ReSharper disable once AssignNullToNotNullAttribute - not null because of the if above il.DeclareLocal(paramType); // initializing locals of ref (non-out) parameters if (!parameters[i].IsOut) { il.Emit(methodorCtor is MethodInfo || (o & DynamicMethodOptions.TreatCtorAsMethod) != DynamicMethodOptions.None ? OpCodes.Ldarg_1 : OpCodes.Ldarg_0); // loading parameters argument il.Emit(OpCodes.Ldc_I4, i); // loading index of processed argument il.Emit(OpCodes.Ldelem_Ref); // loading the pointed element in arguments il.Emit(paramType.IsValueType ? OpCodes.Unbox_Any : OpCodes.Castclass, paramType); il.Emit(OpCodes.Stloc, localsIndex); // storing value in local variable } localsIndex++; } } void LoadParameters(MethodBase methodOrCtor, ILGenerator il, DynamicMethodOptions o) { for (int i = 0, localsIndex = 0; i < ParameterTypes.Length; i++) { // ref/out parameters: from local variables if (ParameterTypes[i].IsByRef) { il.Emit(OpCodes.Ldloca, localsIndex++); // loading address of local variable } // normal parameters: from object[] parameters argument else { // loading parameters argument il.Emit(methodOrCtor is ConstructorInfo && (o & DynamicMethodOptions.TreatCtorAsMethod) == DynamicMethodOptions.None ? OpCodes.Ldarg_0 : (o & DynamicMethodOptions.TreatAsPropertySetter) == DynamicMethodOptions.None ? OpCodes.Ldarg_1 : OpCodes.Ldarg_2); il.Emit(OpCodes.Ldc_I4, i); // loading index of processed argument il.Emit(OpCodes.Ldelem_Ref); // loading the pointed element in arguments il.Emit(ParameterTypes[i].IsValueType ? OpCodes.Unbox_Any : OpCodes.Castclass, ParameterTypes[i]); } } } void AssignRefParams(MethodBase methodOrCtor, ILGenerator il, DynamicMethodOptions o) { if ((options & DynamicMethodOptions.HandleByRefParameters) != DynamicMethodOptions.None) { for (int i = 0, localsIndex = 0; i < ParameterTypes.Length; i++) { if (!ParameterTypes[i].IsByRef) { continue; } Type paramType = ParameterTypes[i].GetElementType(); il.Emit(methodOrCtor is MethodInfo || (o & DynamicMethodOptions.TreatCtorAsMethod) != DynamicMethodOptions.None ? OpCodes.Ldarg_1 : OpCodes.Ldarg_0); // loading parameters argument il.Emit(OpCodes.Ldc_I4, i); // loading index of processed argument il.Emit(OpCodes.Ldloc, localsIndex++); // loading local variable // ReSharper disable once PossibleNullReferenceException - not null because of the if above if (paramType.IsValueType) { il.Emit(OpCodes.Box, paramType); // boxing value type into object } il.Emit(OpCodes.Stelem_Ref); // storing the variable into the pointed array index } } } #endregion if (methodBase == null) { Throw.ArgumentNullException(Argument.methodBase); } Type declaringType = methodBase.DeclaringType; if (declaringType == null) { Throw.ArgumentException(Argument.methodBase, Res.ReflectionDeclaringTypeExpected); } MethodInfo method = methodBase as MethodInfo; ConstructorInfo ctor = methodBase as ConstructorInfo; if (method == null && ctor == null) { Throw.ArgumentException(Argument.methodBase, Res.ReflectionInvalidMethodBase); } bool treatCtorAsMethod = (options & DynamicMethodOptions.TreatCtorAsMethod) != DynamicMethodOptions.None; Type returnType = method != null ? method.ReturnType : treatCtorAsMethod ? Reflector.VoidType : declaringType; Type dmReturnType = returnType == Reflector.VoidType ? Reflector.VoidType : Reflector.ObjectType; (string methodName, List <Type> methodParameters) = GetNameAndParams(methodBase, options); DynamicMethod dm = new DynamicMethod(methodName, // method name dmReturnType, // return type methodParameters.ToArray(), // parameters declaringType, true); // owner ILGenerator ilGenerator = dm.GetILGenerator(); // generating local variables for ref/out parameters and initializing ref parameters GenerateLocalsForRefParams(methodBase, ilGenerator, options); // return value is the last local variable LocalBuilder returnValue = returnType == Reflector.VoidType ? null : ilGenerator.DeclareLocal(returnType); // if instance method: if ((method != null && !method.IsStatic) || treatCtorAsMethod) { ilGenerator.Emit(OpCodes.Ldarg_0); // loading 0th argument (instance) if (declaringType.IsValueType) { // Note: this is a tricky solution that could not be made in C#: // We are just unboxing the value type without storing it in a typed local variable // This makes possible to preserve the modified content of a value type without using ref parameter ilGenerator.Emit(OpCodes.Unbox, declaringType); // unboxing the instance // If instance parameter was a ref parameter, then it should be unboxed into a local variable: //LocalBuilder unboxedInstance = il.DeclareLocal(declaringType); //il.Emit(OpCodes.Ldarg_0); // loading 0th argument (instance) //il.Emit(OpCodes.Ldind_Ref); // as a reference - in dm instance parameter must be defined as: Reflector.ObjectType.MakeByRefType() //il.Emit(OpCodes.Unbox_Any, declaringType); // unboxing the instance //il.Emit(OpCodes.Stloc_0); // saving value into 0. local //il.Emit(OpCodes.Ldloca_S, unboxedInstance); } } // loading parameters for the method call (property setter: indexer parameters) LoadParameters(methodBase, ilGenerator, options); // property value is the last parameter in a setter method if ((options & DynamicMethodOptions.TreatAsPropertySetter) != DynamicMethodOptions.None) { PropertyInfo pi = MemberInfo as PropertyInfo; if (pi == null) { Throw.InvalidOperationException(Res.ReflectionCannotTreatPropertySetter); } ilGenerator.Emit(OpCodes.Ldarg_1); // loading value parameter (always the 1st param in setter delegate because static properties are set by expressions) ilGenerator.Emit(pi.PropertyType.IsValueType ? OpCodes.Unbox_Any : OpCodes.Castclass, pi.PropertyType); } if (ctor != null) { if (treatCtorAsMethod) { // calling the constructor as method ilGenerator.Emit(ctor.IsVirtual ? OpCodes.Callvirt : OpCodes.Call, ctor); } else { // invoking the constructor ilGenerator.Emit(OpCodes.Newobj, ctor); } } else { // calling the method ilGenerator.Emit(methodBase.IsVirtual ? OpCodes.Callvirt : OpCodes.Call, method); } // If instance parameter was a ref parameter, then local variable should be boxed back: //il.Emit(OpCodes.Ldarg_0); // loading instance parameter //il.Emit(OpCodes.Ldloc_0); // loading unboxedInstance local variable //il.Emit(OpCodes.Box, declaringType); // boxing //il.Emit(OpCodes.Stind_Ref); // storing the boxed object value // assigning back ref/out parameters AssignRefParams(methodBase, ilGenerator, options); // setting return value if (returnValue != null) { ilGenerator.Emit(OpCodes.Stloc, returnValue); // storing return value to local variable ilGenerator.Emit(OpCodes.Ldloc, returnValue); // loading return value from its local variable if (returnType.IsValueType) { ilGenerator.Emit(OpCodes.Box, returnType); // boxing if value type } } // returning ilGenerator.Emit(OpCodes.Ret); return(dm); }
/// <summary> /// Removes <paramref name="count"/> amount of items from the <paramref name="target"/> <see cref="IList{T}"/> at the specified <paramref name="index"/>, and /// inserts the specified <paramref name="collection"/> at the same position. The number of elements in <paramref name="collection"/> can be different from the amount of removed items. /// </summary> /// <typeparam name="T">The type of the elements in the collections.</typeparam> /// <param name="target">The target collection.</param> /// <param name="index">The zero-based index of the first item to remove and also the index at which <paramref name="collection"/> items should be inserted.</param> /// <param name="count">The number of items to remove.</param> /// <param name="collection">The collection to insert into the <paramref name="target"/> list.</param> /// <exception cref="ArgumentNullException"><paramref name="target"/> or <paramref name="collection"/> is <see langword="null"/>.</exception> /// <exception cref="ArgumentOutOfRangeException"><paramref name="index"/> is not a valid index in the <see cref="CircularList{T}"/>.</exception> /// <remarks> /// <note>If <paramref name="target"/> is neither a <see cref="List{T}"/> or an <see cref="ISupportsRangeList{T}"/> implementation, /// then after overwriting the elements of the overlapping range, the difference will be removed or inserted one by one.</note> /// </remarks> public static void ReplaceRange <T>(this IList <T> target, int index, int count, IEnumerable <T> collection) { if (target == null) { Throw.ArgumentNullException(Argument.target); } if (collection == null) { Throw.ArgumentNullException(Argument.collection); } switch (target) { case ISupportsRangeList <T> supportsRangeList: supportsRangeList.ReplaceRange(index, count, collection); return; default: int len = target.Count; if ((uint)index >= (uint)len) { Throw.ArgumentOutOfRangeException(Argument.index); } if (count < 0) { Throw.ArgumentOutOfRangeException(Argument.count); } if (index + count > len) { Throw.ArgumentException(Res.IListInvalidOffsLen); } using (IEnumerator <T> enumerator = collection.GetEnumerator()) { // Copying elements while possible int elementsCopied = 0; while (count > 0 && enumerator.MoveNext()) { target[index + elementsCopied] = enumerator.Current; elementsCopied += 1; count -= 1; } // all inserted, removing the rest if (count > 0) { target.RemoveRange(index + elementsCopied, count); return; } // all removed (overwritten), inserting the rest IList <T> rest = collection is IList <T> list ? new ListSegment <T>(list, elementsCopied) : enumerator.RestToList(); if (rest.Count > 0) { target.InsertRange(index + elementsCopied, rest); } return; } } }
/// <summary> /// Gets the zero-based index of the first occurrence in the specified <see cref="string"/> <paramref name="s"/> of any of the strings in the specified <paramref name="set"/> using a specific <paramref name="comparison"/>. /// </summary> /// <param name="comparison">The <see cref="StringComparison"/> to use.</param> /// <param name="s">A <see cref="string"/> instance that is to be compared to each element of the <paramref name="set"/>.</param> /// <param name="set">An <see cref="Array"/> of strings.</param> /// <returns>The zero-based index of the first occurrence in the specified <see cref="string"/> <paramref name="s"/> of any of the strings in the specified <paramref name="set"/>, /// or -1 if none of the strings of <paramref name="set"/> are found in <paramref name="s"/>.</returns> /// <exception cref="ArgumentNullException"><paramref name="s"/> is <see langword="null"/> /// <br/>-or- /// <br/><paramref name="set"/> is <see langword="null"/>.</exception> /// <exception cref="ArgumentOutOfRangeException"><paramref name="comparison"/> is not a defined <see cref="StringComparison"/> value.</exception> /// <exception cref="ArgumentException"><paramref name="set"/>contains a <see langword="null"/> element.</exception> public static int IndexOfAny(this string s, StringComparison comparison, params string[] set) { if (s == null) { Throw.ArgumentNullException(Argument.s); } if (set == null) { Throw.ArgumentNullException(Argument.set); } if (!Enum <StringComparison> .IsDefined(comparison)) { Throw.EnumArgumentOutOfRange(Argument.comparison, comparison); } int len = s.Length; if (len == 0) { foreach (string str in set) { if (str == null) { Throw.ArgumentException(Argument.set, Res.ArgumentContainsNull); } if (str.Length == 0) { return(0); } } return(-1); } var index = -1; for (int i = 0; i < len; i++) { foreach (string str in set) { if (str == null) { Throw.ArgumentException(Argument.set, Res.ArgumentContainsNull); } if (str.Length == 0) { return(0); } int strLen = str.Length; if (s[i] != str[0] || strLen > len - i) { continue; } if (strLen == 1 || String.Compare(s, i, str, 0, strLen, comparison) == 0) { return(i); } } } return(index); }
internal static bool TryParse(string s, Type type, CultureInfo culture, bool tryKnownTypes, out object value, out Exception error) { if (type == null) { Throw.ArgumentNullException(Argument.type); } error = null; value = null; if (s == null) { if (type.CanAcceptValue(null)) { return(true); } Throw.ArgumentNullException(Argument.s); } type = Nullable.GetUnderlyingType(type) ?? type; if (type.IsByRef) { type = type.GetElementType(); } if (culture == null) { culture = CultureInfo.InvariantCulture; } try { // ReSharper disable once PossibleNullReferenceException if (type.IsEnum) { #if NET35 || NET40 || NET45 || NET472 || NETSTANDARD2_0 value = Enum.Parse(type, s); return(true); #else return(Enum.TryParse(type, s, out value)); #endif } if (type.IsInstanceOfType(s)) { value = s; return(true); } if (tryKnownTypes && knownTypes.TryGetValue(type, out var tryParseMethod)) { return(tryParseMethod.Invoke(s, culture, out value)); } if (type.In(Reflector.Type, Reflector.RuntimeType #if !NET35 && !NET40 , Reflector.TypeInfo #endif )) { value = Reflector.ResolveType(s); return(value != null); } // a registered converter from string switch (Reflector.StringType.GetConversions(type, true).ElementAtOrDefault(0)) { case ConversionAttempt conversionAttempt: if (conversionAttempt.Invoke(s, type, culture, out value) && type.CanAcceptValue(value)) { return(true); } break; case Conversion conversion: value = conversion.Invoke(s, type, culture); if (type.CanAcceptValue(value)) { return(true); } break; } // Trying type converter as a fallback TypeConverter converter = TypeDescriptor.GetConverter(type); if (converter.CanConvertFrom(Reflector.StringType)) { // ReSharper disable once AssignNullToNotNullAttribute - false alarm, context can be null value = converter.ConvertFrom(null, culture, s); return(true); } return(false); } catch (Exception e) when(!e.IsCritical()) { error = e; value = null; return(false); } }
public LocalViewModel(Library library, ViewSettings viewSettings, CoreSettings coreSettings, Guid accessToken) : base(library, coreSettings, accessToken) { if (viewSettings == null) { Throw.ArgumentNullException(() => viewSettings); } this.viewSettings = viewSettings; this.artistUpdateSignal = new Subject <Unit>(); this.allArtistsViewModel = new ArtistViewModel("All Artists"); this.allArtists = new ReactiveList <ArtistViewModel> { this.allArtistsViewModel }; this.Artists = this.allArtists.CreateDerivedCollection(x => x, x => x.IsAllArtists || this.filteredSongs.Contains(x.Name), (x, y) => x.CompareTo(y), this.artistUpdateSignal); // We need a default sorting order this.ApplyOrder(SortHelpers.GetOrderByArtist <LocalSongViewModel>, ref this.artistOrder); this.SelectedArtist = this.allArtistsViewModel; var gate = new object(); this.Library.SongsUpdated .Buffer(TimeSpan.FromSeconds(1), RxApp.TaskpoolScheduler) .Where(x => x.Any()) .Select(_ => Unit.Default) .Merge(this.WhenAny(x => x.SearchText, _ => Unit.Default) .Do(_ => this.SelectedArtist = this.allArtistsViewModel)) .Synchronize(gate) .ObserveOn(RxApp.MainThreadScheduler) .Subscribe(_ => { this.UpdateSelectableSongs(); this.UpdateArtists(); }); this.WhenAnyValue(x => x.SelectedArtist) .Skip(1) .Synchronize(gate) .Subscribe(_ => this.UpdateSelectableSongs()); this.playNowCommand = ReactiveCommand.CreateAsyncTask(this.Library.LocalAccessControl.ObserveAccessPermission(accessToken) .Select(x => x == AccessPermission.Admin || !coreSettings.LockPlayPause), _ => { int songIndex = this.SelectableSongs.TakeWhile(x => x.Model != this.SelectedSongs.First().Model).Count(); return(this.Library.PlayInstantlyAsync(this.SelectableSongs.Skip(songIndex).Select(x => x.Model), accessToken)); }); this.showAddSongsHelperMessage = this.Library.SongsUpdated .StartWith(Unit.Default) .Select(_ => this.Library.Songs.Count == 0) .TakeWhile(x => x) .Concat(Observable.Return(false)) .ToProperty(this, x => x.ShowAddSongsHelperMessage); this.isUpdating = this.Library.WhenAnyValue(x => x.IsUpdating) .ToProperty(this, x => x.IsUpdating); this.OpenTagEditor = ReactiveCommand.Create(this.WhenAnyValue(x => x.SelectedSongs, x => x.Any())); }