| // <copyright file="ActionBuilder.cs" company="Selenium Committers"> |
| // Licensed to the Software Freedom Conservancy (SFC) under one |
| // or more contributor license agreements. See the NOTICE file |
| // distributed with this work for additional information |
| // regarding copyright ownership. The SFC licenses this file |
| // to you under the Apache License, Version 2.0 (the |
| // "License"); you may not use this file except in compliance |
| // with the License. You may obtain a copy of the License at |
| // |
| // http://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, |
| // software distributed under the License is distributed on an |
| // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| // KIND, either express or implied. See the License for the |
| // specific language governing permissions and limitations |
| // under the License. |
| // </copyright> |
| |
| using System; |
| using System.Collections.Generic; |
| using System.Text; |
| |
| namespace OpenQA.Selenium.Interactions; |
| |
| /// <summary> |
| /// Provides methods that allow the creation of action sequences to enable |
| /// advanced user interactions. |
| /// </summary> |
| public class ActionBuilder |
| { |
| private readonly Dictionary<InputDevice, ActionSequence> sequences = new Dictionary<InputDevice, ActionSequence>(); |
| |
| /// <summary> |
| /// Adds an action to the built set of actions. Adding an action will |
| /// add a "tick" to the set of all actions to be executed. |
| /// </summary> |
| /// <param name="actionToAdd">The action to add to the set of actions</param> |
| /// <returns>A self reference.</returns> |
| public ActionBuilder AddAction(Interaction actionToAdd) |
| { |
| this.AddActions(actionToAdd); |
| return this; |
| } |
| |
| /// <summary> |
| /// Adds an action to the built set of actions. Adding an action will |
| /// add a "tick" to the set of all actions to be executed. Only one action |
| /// for each input device may be added for a single tick. |
| /// </summary> |
| /// <param name="actionsToAdd">The set actions to add to the existing set of actions.</param> |
| /// <returns>A self reference.</returns> |
| public ActionBuilder AddActions(params Interaction[] actionsToAdd) |
| { |
| this.ProcessTick(actionsToAdd); |
| return this; |
| } |
| |
| /// <summary> |
| /// Converts the set of actions in this <see cref="ActionBuilder"/> to a <see cref="List{ActionSequence}"/>. |
| /// </summary> |
| /// <returns>A <see cref="IList{ActionSequence}"/> suitable for transmission across the wire. |
| /// The collection returned is read-only.</returns> |
| public IList<ActionSequence> ToActionSequenceList() |
| { |
| return new List<ActionSequence>(this.sequences.Values).AsReadOnly(); |
| } |
| |
| /// <summary> |
| /// Resets the list of sequences. |
| /// </summary> |
| public void ClearSequences() |
| { |
| this.sequences.Clear(); |
| } |
| |
| /// <summary> |
| /// Returns a string that represents the current <see cref="ActionBuilder"/>. |
| /// </summary> |
| /// <returns>A string that represents the current <see cref="ActionBuilder"/>.</returns> |
| public override string ToString() |
| { |
| StringBuilder builder = new StringBuilder(); |
| foreach (ActionSequence sequence in this.sequences.Values) |
| { |
| builder.AppendLine(sequence.ToString()); |
| } |
| |
| return builder.ToString(); |
| } |
| |
| private void ProcessTick(params Interaction[] interactionsToAdd) |
| { |
| List<InputDevice> usedDevices = new List<InputDevice>(); |
| foreach (Interaction interaction in interactionsToAdd) |
| { |
| if (usedDevices.Contains(interaction.SourceDevice)) |
| { |
| throw new ArgumentException("You can only add one action per device for a single tick."); |
| } |
| } |
| |
| List<InputDevice> unusedDevices = new List<InputDevice>(this.sequences.Keys); |
| foreach (Interaction interaction in interactionsToAdd) |
| { |
| ActionSequence sequence = this.GetOrAddSequence(interaction.SourceDevice); |
| sequence.AddAction(interaction); |
| |
| unusedDevices.Remove(interaction.SourceDevice); |
| } |
| |
| foreach (InputDevice unusedDevice in unusedDevices) |
| { |
| ActionSequence sequence = this.sequences[unusedDevice]; |
| sequence.AddAction(new PauseInteraction(unusedDevice, TimeSpan.Zero)); |
| } |
| } |
| |
| private ActionSequence GetOrAddSequence(InputDevice device) |
| { |
| if (this.sequences.TryGetValue(device, out ActionSequence? existingSequence)) |
| { |
| return existingSequence; |
| } |
| |
| int longestSequenceLength = 0; |
| foreach (KeyValuePair<InputDevice, ActionSequence> pair in this.sequences) |
| { |
| longestSequenceLength = Math.Max(longestSequenceLength, pair.Value.Count); |
| } |
| |
| ActionSequence sequence = new ActionSequence(device, longestSequenceLength); |
| this.sequences[device] = sequence; |
| |
| return sequence; |
| } |
| } |