public void MouseMove(object sender, MouseEventArgs e) { // Position the placement icon Point pos = e.GetPosition(m_canvas); m_placementIcon.SetValue(Canvas.LeftProperty, pos.X - 20.0); m_placementIcon.SetValue(Canvas.TopProperty, pos.Y - 20.0); // Show the placement icon if it wasn't already visible if (Visibility.Visible != m_placementIcon.Visibility) { m_placementIcon.Visibility = Visibility.Visible; } // Set border highlight if we're hoving over a stream endpoint DraggableStreamEndpoint endpoint = m_canvas.GetChildAt(pos, m_placementIcon) as DraggableStreamEndpoint; if (null == endpoint) { m_placementIcon.BorderThickness = new Thickness(0.0); } else { AbstractProcessUnit temp = (AbstractProcessUnit) Activator.CreateInstance(m_type, -1); m_placementIcon.BorderThickness = new Thickness(2.0); m_placementIcon.BorderBrush = (endpoint.CanConnectTo(temp) ? s_greenBrush : s_redBrush); } }
public AttachOutgoingStream(AbstractProcessUnit processUnit, AbstractStream outgoingStream) { if (null == processUnit || null == outgoingStream) { throw new ArgumentNullException(); } m_pu = processUnit; m_stream = outgoingStream; }
/// <summary> /// Removes this control from the canvas. This includes removal of controls that are /// "attached" to this control, such as the comment sticky note controls. /// This is considered disposal of the control and it should not be used anymore /// after calling this method. /// </summary> public void RemoveSelfFromCanvas(UI.DrawingCanvas canvas) { // Unsubscribe from events (important) m_stream.PropertyChanged -= this.Stream_PropertyChanged; m_stream.Comments.CollectionChanged -= this.Comments_CollectionChanged; if (null != m_sourceEventItem) { m_sourceEventItem.PropertyChanged -= this.SourceOrDest_PropertyChanged; m_sourceEventItem = null; } if (null != m_destEventItem) { m_destEventItem.PropertyChanged -= this.SourceOrDest_PropertyChanged; m_destEventItem = null; } if (null != m_table) { m_stream.PropertiesTable.PropertyChanged -= this.PropertiesTable_PropertyChanged; } canvas.RemoveChild(this); canvas.RemoveChild(m_sourceDragIcon); canvas.RemoveChild(m_dstDragIcon); canvas.RemoveChild(m_table); if (null != m_miniTable) { canvas.RemoveChild(m_miniTable); } if (null != m_square) { canvas.RemoveChild(m_square); } if (null != m_arrow) { canvas.RemoveChild(m_arrow); } // Remove all the lines foreach (Line line in m_lines) { canvas.RemoveChild(line); } m_lines.Clear(); foreach (StickyNoteControl snc in m_stickyNotes) { snc.RemoveSelfFromCanvas(canvas); } m_stickyNotes.Clear(); // Set the value to indiate that we've removed m_hasBeenRemoved = true; }
private void UpdateEquationModelElements(EquationModel equation) { List <object> relevantUnits = new List <object>(); //supply different PFD elements to the model depending on its scope switch (equation.Scope.Classification) { //With a single unit, all we care about is that unit and its related streams case EquationScopeClassification.SingleUnit: AbstractProcessUnit selectedUnit = (from element in m_workspace.ProcessUnits where (element as AbstractProcessUnit).Label == equation.Scope.Name select element).FirstOrDefault() as AbstractProcessUnit; if (selectedUnit != null) { relevantUnits = GetElementAndStreams(selectedUnit); } break; //ChemProV doesn't currently support sub processes, but this is where //that logic would go case EquationScopeClassification.SubProcess: break; //AC: Not sure what should happen here case EquationScopeClassification.Unknown: break; //Pull all source and sink units as well as their streams case EquationScopeClassification.Overall: default: // TODO: Fix or remove //List<GenericProcessUnit> units = (from element in PfdElements // where element is GenericProcessUnit // && // ( // (element as GenericProcessUnit).Description == ProcessUnitDescriptions.Sink // || // (element as GenericProcessUnit).Description == ProcessUnitDescriptions.Source // ) // select element as GenericProcessUnit).ToList(); //foreach (GenericProcessUnit unit in units) //{ // relevantUnits = relevantUnits.Union(GetElementAndStreams(unit)).ToList(); //} break; } //assign the updated list to the equation equation.RelatedElements = relevantUnits; }
public SetStreamDestination(AbstractStream stream, AbstractProcessUnit destForThis, AbstractProcessUnit destForOpposite, MathCore.Vector location) { m_stream = stream as AbstractStream; m_pu = destForThis; m_location = location; // Create the opposite action m_opposite = new SetStreamDestination(); m_opposite.m_location = location; m_opposite.m_opposite = this; m_opposite.m_pu = destForOpposite; m_opposite.m_stream = m_stream; }
public SetStreamSource(AbstractStream stream, AbstractProcessUnit sourceForThis, AbstractProcessUnit sourceForOpposite, MathCore.Vector locationForDSE) { m_stream = stream as AbstractStream; m_pu = sourceForThis; m_location = locationForDSE; // Create the opposite action m_opposite = new SetStreamSource(); m_opposite.m_location = locationForDSE; m_opposite.m_opposite = this; m_opposite.m_pu = sourceForOpposite; m_opposite.m_stream = m_stream; }
/// <summary> /// Removes this control from the canvas. This includes removal of controls that are /// "attached" to this control, such as the comment sticky note controls. /// This is considered "disposing" the control and it should not be used after this call. /// </summary> public void RemoveSelfFromCanvas(UI.DrawingCanvas owner) { // Unsubscribe from events m_pu.Comments.CollectionChanged -= this.CommentCollectionChanged; m_pu.PropertyChanged -= this.ProcessUnit_PropertyChanged; owner.RemoveChild(this); foreach (ChemProV.UI.StickyNoteControl snc in m_stickyNotes) { snc.RemoveSelfFromCanvas(owner); } // Set the process unit reference to null m_pu = null; }
/// <summary> /// Use CreateOnCanvas /// </summary> private ProcessUnitControl(DrawingCanvas canvas, AbstractProcessUnit processUnit) { InitializeComponent(); // Store a reference to the canvas and process unit m_pu = processUnit; m_canvas = canvas; // Create the icon image BitmapImage bmp = new BitmapImage(); bmp.UriSource = new Uri(GetIconSource(processUnit.GetType()), UriKind.Relative); ProcessUnitImage.SetValue(Image.SourceProperty, bmp); // Set the background color based on the subprocess Color clr; if (Core.App.TryParseColor(m_pu.Subprocess, out clr)) { ProcessUnitBorder.Background = new SolidColorBrush(clr); } ProcessUnitNameText.MouseLeftButtonDown += new MouseButtonEventHandler(ProcessUnitNameText_MouseLeftButtonDown); ProcessUnitNameBox.MouseLeftButtonDown += new MouseButtonEventHandler(ProcessUnitNameBox_MouseLeftButtonDown); ProcessUnitNameBox.LostFocus += new RoutedEventHandler(ProcessUnitNameBox_LostFocus); ProcessUnitNameBox.KeyDown += new KeyEventHandler(ProcessUnitNameBox_KeyDown); // Create the icon image ProcessUnitImage.SetValue(Image.SourceProperty, ProcessUnitImage.Source); // Set the default label ProcessUnitNameText.Text = ProcessUnitNameBox.Text = m_pu.Label; // Setup the event listener for the comment collection. It is the responsibility of this // control to create and manage the sticky note controls for its comments processUnit.Comments.CollectionChanged += CommentCollectionChanged; // Setup the event listener for property changes. When things like the location property // change, we'll need to update our position on the canvas. processUnit.PropertyChanged += this.ProcessUnit_PropertyChanged; // Just a note that we don't need to watch when the incoming or outgoing streams change // because that doesn't affect how we present the process unit in the UI // Invoke the comment change event to do the intial creation of comment controls CommentCollectionChanged(m_pu.Comments, new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset)); }
private List <object> GetElementAndStreams(AbstractProcessUnit unit) { List <object> elements = new List <object>(); // Add the process unit as well as its incoming and outgoing streams elements.Add(unit); foreach (AbstractStream element in unit.IncomingStreams) { elements.Add(element); } foreach (AbstractStream element in unit.OutgoingStreams) { elements.Add(element); } return(elements); }
public static ProcessUnitControl CreateOnCanvas(DrawingCanvas canvas, AbstractProcessUnit processUnit) { ProcessUnitControl pu = new ProcessUnitControl(canvas, processUnit); canvas.AddNewChild(pu); // Set the initial location pu.SetValue(Canvas.LeftProperty, processUnit.Location.X - pu.Width / 2.0); pu.SetValue(Canvas.TopProperty, processUnit.Location.Y - pu.Height / 2.0); // Make sure we have the right z-order pu.SetValue(Canvas.ZIndexProperty, 1); return(pu); }
public ProcessUnitControl GetProcessUnitControl(AbstractProcessUnit unit) { foreach (UIElement uie in Children) { if (!(uie is ProcessUnitControl)) { continue; } ProcessUnitControl pu = uie as ProcessUnitControl; if (object.ReferenceEquals(pu.ProcessUnit, unit)) { return(pu); } } return(null); }
public MovingStreamEndpoint(DraggableStreamEndpoint endpoint, DrawingCanvas canvas, bool creatingStream) { m_dragIcon = endpoint; m_canvas = canvas; m_creatingStream = creatingStream; m_stream = endpoint.ParentStream.Stream; if (m_dragIcon.IsSource) { m_startLocation = m_stream.SourceLocation; m_connectedToOnStart = m_stream.Source; } else { m_startLocation = m_stream.DestinationLocation; m_connectedToOnStart = m_stream.Destination; } }
/// <summary> /// Determines whether or not this endpoint can connect to the specified process unit /// </summary> public bool CanConnectTo(AbstractProcessUnit processUnit) { // The logic to determine this is already implemented in the process unit. We just // have to identify whether we're incoming or outgoing. if (EndpointType.StreamDestination == m_type) { return(processUnit.CanAcceptIncomingStream(m_owner.Stream) && !object.ReferenceEquals(processUnit, m_owner.Stream.Source)); } else if (EndpointType.StreamSource == m_type) { return(processUnit.CanAcceptOutgoingStream(m_owner.Stream) && !object.ReferenceEquals(processUnit, m_owner.Stream.Destination)); } // If we're already connected then we cannot connect to anything else. Endpoints attach // to only one item. return(false); }
private StreamControl(DrawingCanvas canvas, AbstractStream stream) { m_canvas = canvas; m_stream = stream; InitializeComponent(); if (null != canvas && null != stream) { // Create the brush for the stream line if (stream is HeatStream) { m_streamLineNotSelected = new SolidColorBrush(Colors.Red); } else { m_streamLineNotSelected = new SolidColorBrush(Colors.Black); } // Create the drag handle for the source m_sourceDragIcon = new DraggableStreamEndpoint( DraggableStreamEndpoint.EndpointType.StreamSource, this, canvas); m_sourceDragIcon.Width = m_sourceDragIcon.Height = 20.0; m_sourceDragIcon.Location = new Point(m_stream.SourceLocation.X, m_stream.SourceLocation.Y); // Add it to the canvas m_canvas.AddNewChild(m_sourceDragIcon); // Set the Z-index m_sourceDragIcon.SetValue(Canvas.ZIndexProperty, 2); // Setup mouse events m_sourceDragIcon.MouseLeftButtonDown += new MouseButtonEventHandler(DragIcon_MouseLeftButtonDown); // Create the drag handle for the destination m_dstDragIcon = new DraggableStreamEndpoint( DraggableStreamEndpoint.EndpointType.StreamDestination, this, canvas); // Add it to the canvas m_canvas.AddNewChild(m_dstDragIcon); // Set the Z-index m_dstDragIcon.SetValue(Canvas.ZIndexProperty, 2); // Show it if there's no destination, hide it otherwise m_dstDragIcon.Visibility = (null == m_stream.Destination) ? Visibility.Visible : System.Windows.Visibility.Collapsed; // Setup mouse events m_dstDragIcon.MouseLeftButtonDown += new MouseButtonEventHandler(DragIcon_MouseLeftButtonDown); // Create the arrow polygon control m_arrow = new Polygon(); // Set the fill m_arrow.Fill = m_streamLineNotSelected; // Add it to the canvas m_canvas.AddNewChild(m_arrow); // Set the Z-index m_arrow.SetValue(Canvas.ZIndexProperty, 2); // Add 3 points/vertices m_arrow.Points.Add(new Point()); m_arrow.Points.Add(new Point()); m_arrow.Points.Add(new Point()); // Hide it if there's no destination if (null == m_stream.Destination) { m_arrow.Visibility = Visibility.Collapsed; } // Setup mouse events if (!(m_stream.Destination is HeatExchangerWithUtility)) { m_arrow.MouseLeftButtonDown += new MouseButtonEventHandler(DestinationArrow_MouseLeftButtonDown); } UpdateStreamLocation(); // Create the table CreatePropertiesTable(m_stream.PropertiesTable); // Watch for when the table location changes m_stream.PropertiesTable.PropertyChanged += new PropertyChangedEventHandler(PropertiesTable_PropertyChanged); // Add it to the canvas and set it up m_canvas.AddNewChild(m_table as UIElement); UserControl tableAsUiElement = m_table as UserControl; //This sets the tables index to the greatest so it will be above everything tableAsUiElement.SetValue(System.Windows.Controls.Canvas.ZIndexProperty, 3); tableAsUiElement.MouseLeftButtonDown += new MouseButtonEventHandler((canvas as DrawingCanvas).MouseLeftButtonDownHandler); tableAsUiElement.MouseLeftButtonUp += new MouseButtonEventHandler((canvas as DrawingCanvas).MouseLeftButtonUpHandler); // Hook up event listeners to the stream if non-null. We need to monitor: // 1. Changes in the comment collection // 2. Changes to the source process units properties (position) // 3. Changes to the destination process units properties (position) // 4. Changes to the source or destination references // 1. // Setup the event listener for the comment collection. It is the responsibility of this // control to create and manage the sticky note controls for its comments m_stream.Comments.CollectionChanged += Comments_CollectionChanged; // Invoke the callback to create sticky notes for comments Comments_CollectionChanged(m_stream.Comments, null); // 2. if (null != stream.Source) { m_sourceEventItem = stream.Source; stream.Source.PropertyChanged += this.SourceOrDest_PropertyChanged; } // 3. if (null != stream.Destination) { m_destEventItem = stream.Destination; stream.Destination.PropertyChanged += this.SourceOrDest_PropertyChanged; } // 4. stream.PropertyChanged += new PropertyChangedEventHandler(Stream_PropertyChanged); } }
private void Stream_PropertyChanged(object sender, PropertyChangedEventArgs e) { // If we're told to ignore these then just return if (m_ignoreStreamPropertyChanges) { return; } // Set the ignore flag to avoid recursion m_ignoreStreamPropertyChanges = true; if (e.PropertyName.Equals("Source")) { // Unsubscribe from the old source if (null != m_sourceEventItem) { m_sourceEventItem.PropertyChanged -= this.SourceOrDest_PropertyChanged; } // Keep the reference to the new source m_sourceEventItem = m_stream.Source; // Subscribe to the new source if (null != m_stream.Source) { m_stream.Source.PropertyChanged += this.SourceOrDest_PropertyChanged; // Set the source location to that of the source process unit m_stream.SourceLocation = m_stream.Source.Location; } // Update the stream's location UpdateStreamLocation(); } else if (e.PropertyName.Equals("Destination")) { // Unsubscribe from the old destination if (null != m_destEventItem) { m_destEventItem.PropertyChanged -= this.SourceOrDest_PropertyChanged; } // Keep the reference to the new destination m_destEventItem = m_stream.Destination; // Subscribe to the new destination if (null != m_stream.Destination) { m_stream.Destination.PropertyChanged += this.SourceOrDest_PropertyChanged; // Hide the destination drag icon. We need to use the arrow. m_dstDragIcon.Visibility = System.Windows.Visibility.Collapsed; } else { // Null destination means we need to show the drag icon and not the arrow m_dstDragIcon.Visibility = System.Windows.Visibility.Visible; m_arrow.Visibility = System.Windows.Visibility.Collapsed; } // Update the stream's location UpdateStreamLocation(); } else if (e.PropertyName.Equals("SourceLocation")) { // Position the drag icon if the source is null if (null == m_stream.Source) { m_sourceDragIcon.Location = new Point( m_stream.SourceLocation.X, m_stream.SourceLocation.Y); } UpdateStreamLocation(); } else if (e.PropertyName.Equals("DestinationLocation")) { // Position the drag icon if the destination is null if (null == m_stream.Destination) { m_dstDragIcon.Location = new Point( m_stream.DestinationLocation.X, m_stream.DestinationLocation.Y); } UpdateStreamLocation(); } else if (e.PropertyName.Equals("Id")) { if (null != m_miniTable) { m_miniTable.NameTextBlock.Text = "S" + m_stream.Id.ToString(); } } // Reset the flag m_ignoreStreamPropertyChanges = false; }
public SetSubprocess(AbstractProcessUnit processUnit) { m_value = processUnit.Subprocess; m_pu = processUnit; }
/// <summary> /// Handles mouse-left-button-down event for placing a heat exchanger with utility /// </summary> public void MLBD_HEWU(object sender, MouseButtonEventArgs e) { // Start by getting the mouse position Point pos = e.GetPosition(m_canvas); // See if we have a DraggableStreamEndpoint where we clicked DraggableStreamEndpoint endpoint = m_canvas.GetChildAt(pos, m_placementIcon) as DraggableStreamEndpoint; // Remove the placement icon and then set it to null to indicate state completion m_canvas.RemoveChild(m_placementIcon); m_placementIcon = null; // If there's not an endpoint: // 1. Create and attach an incoming heat stream. Position the source endpoint just // below the process unit // 2. Create an undo that will remove both // 3. Switch to the appropriate state for moving the source endpoint if (null == endpoint) { // Create the actual process unit AbstractProcessUnit apu = (AbstractProcessUnit)Activator.CreateInstance( m_type, AbstractProcessUnit.GetNextUID()); apu.Location = new MathCore.Vector(pos.X, pos.Y); HeatStream s = new HeatStream(); apu.AttachIncomingStream(s); s.Destination = apu; s.PropertiesTable = new StreamPropertiesTable(s); // Position the source of the heat stream. It's above the process unit by default, unless // that would make it go off the screen if (apu.Location.Y < 150.0) { s.SourceLocation = new MathCore.Vector( apu.Location.X - 10.0, apu.Location.Y + 80.0); s.PropertiesTable.Location = new MathCore.Vector( apu.Location.X + 10.0, apu.Location.Y + 140.0); } else { s.SourceLocation = new MathCore.Vector( apu.Location.X - 10.0, apu.Location.Y - 80.0); s.PropertiesTable.Location = new MathCore.Vector( apu.Location.X + 10.0, apu.Location.Y - 100.0); } // Add the stream and the process unit to the workspace. Event handlers will update // the UI appropriately. m_workspace.AddProcessUnit(apu); m_workspace.AddStream(s); m_workspace.AddUndo(new UndoRedoCollection("Undo creation of heat exchanger with utility", new Logic.Undos.DetachIncomingStream(apu, s), new Logic.Undos.SetStreamDestination(s, null, apu, s.DestinationLocation), new Logic.Undos.RemoveStream(s), new Logic.Undos.RemoveProcessUnit(apu))); // Select nothing on the canvas m_canvas.SelectedElement = null; m_palette.SwitchToSelect(); return; } // Otherwise, if we HAVE clicked on an endpoint, just deny it by doing nothing }
public void MouseLeftButtonDown(object sender, MouseButtonEventArgs e) { // We don't process messages if the placement icon is null if (null == m_placementIcon) { return; } // Handle heat exchanger with utility as a special case if (m_type.Equals(typeof(HeatExchangerWithUtility))) { MLBD_HEWU(sender, e); return; } // Start by getting the mouse position Point pos = e.GetPosition(m_canvas); MathCore.Vector vPos = new MathCore.Vector(pos.X, pos.Y); // See if we have a DraggableStreamEndpoint where we clicked DraggableStreamEndpoint endpoint = m_canvas.GetChildAt(pos, m_placementIcon) as DraggableStreamEndpoint; // Remove the placement icon and then set it to null to indicate state completion m_canvas.RemoveChild(m_placementIcon); m_placementIcon = null; // Determine a unique identifier for the process unit int uid; do { uid = AbstractProcessUnit.GetNextUID(); }while (null != m_workspace.GetProcessUnit(uid)); // If there's not an endpoint, we create the process unit with no stream connections if (null == endpoint) { AbstractProcessUnit unit = (AbstractProcessUnit)Activator.CreateInstance( m_type, uid); // Set the location unit.Location = new MathCore.Vector(pos.X, pos.Y); // Add it to the workspace m_workspace.AddProcessUnit(unit); // Add an undo that will remove it m_workspace.AddUndo(new UndoRedoCollection("Undo process unit creation", new ChemProV.Logic.Undos.RemoveProcessUnit(unit))); m_canvas.SelectedElement = null; // Tell the control palette to switch back to select mode and then return m_palette.SwitchToSelect(); return; } // Otherwise, if we HAVE clicked on an endpoint... // Check to see if we can't connect this way AbstractProcessUnit temp = (AbstractProcessUnit) Activator.CreateInstance(m_type, -1); if (!endpoint.CanConnectTo(temp)) { // The usability here may be debatable. But for now we'll cancel placement and // give the user an error message m_palette.SwitchToSelect(); Core.App.MessageBox("The stream endpoint that you clicked cannot connect with " + "the process unit that you were placing."); return; } // Otherwise, if we CAN connect this way... // Create the process unit AbstractProcessUnit apu = (AbstractProcessUnit) Activator.CreateInstance(m_type, uid); // Make the undo and then the actual attachment if (DraggableStreamEndpoint.EndpointType.StreamDestination == endpoint.Type) { // Set the location apu.Location = endpoint.ParentStream.Stream.DestinationLocation; // Create an undo that sets the stream destination back to what it was and removes the // process unit m_workspace.AddUndo(new UndoRedoCollection("Undo process unit creation + attachment", new Logic.Undos.SetStreamDestination(endpoint.ParentStream.Stream, null, apu, vPos), new Logic.Undos.RemoveProcessUnit(apu))); apu.AttachIncomingStream(endpoint.ParentStream.Stream); endpoint.ParentStream.Stream.Destination = apu; } else { // Set the location apu.Location = endpoint.ParentStream.Stream.SourceLocation; // Create an undo that sets the stream source back to what it was and removes the // process unit from the canvas AbstractStream stream = endpoint.ParentStream.Stream; m_workspace.AddUndo(new UndoRedoCollection("Undo process unit creation + attachment", new Logic.Undos.SetStreamSource(stream, null, apu, stream.SourceLocation), new Logic.Undos.RemoveProcessUnit(apu))); apu.AttachOutgoingStream(endpoint.ParentStream.Stream); endpoint.ParentStream.Stream.Source = apu; } // Don't forget to add the process unit to the workspace. Event handlers will update the // UI appropriately. m_workspace.AddProcessUnit(apu); m_canvas.SelectedElement = null; // Go back to select mode m_palette.SwitchToSelect(); }
public SetProcessUnitLabel(AbstractProcessUnit unit, string labelToSetOnExecution) { m_lpu = unit; m_label = labelToSetOnExecution; }
public RemoveProcessUnit(AbstractProcessUnit unitToRemove) { m_remove = unitToRemove; }
public SetProcessUnitLocation(AbstractProcessUnit processUnit, MathCore.Vector location) { m_apu = processUnit; m_location = location; }
/// <summary> /// Merges comments from two Xml document streams into a new output Xml document stream. Comment /// merging is not commutative. One document must be considered to be the parent and another a /// child. ALL content from the parent will appear in the output. Comments from the child /// document will only be written to the output if they exist for shared entities. That is, if /// there is a comment in the child document that is tied to a process unit with Id=GPU_30, then /// it will only be written the output document if the parent also contained a process unit with /// the same Id. /// </summary> public static void Merge(Stream parent, string parentUserNameIfNotInXml, Stream child, string childUserNameIfNotInXml, Stream output) { // We need all streams to be non-null if (null == parent) { throw new ArgumentNullException( "Parent stream for comment merging cannot be null"); } if (null == child) { throw new ArgumentNullException( "Child stream for comment merging cannot be null"); } if (null == output) { throw new ArgumentNullException( "Output stream for comment merging cannot be null"); } // Load the workspaces from the streams Workspace wsParent = new Workspace(); wsParent.Load(parent); Workspace wsChild = new Workspace(); wsChild.Load(child); // What we will do in this method is alter wsParent to contain relevant content from the // child workspace and then save it to the output stream. // Start by setting user names for comments in both workspaces. We leave the user names // alone if they are not null or empty but otherwise we set them to the values specified // by the caller. SetUserNameIfAbsent(wsParent, parentUserNameIfNotInXml); SetUserNameIfAbsent(wsChild, childUserNameIfNotInXml); // Start with the free-floating sticky note comments. We want to take the ones from the // child and add them into the parent. But we want to avoid duplicates in the process. foreach (StickyNote sn in wsChild.StickyNotes) { // If they have the same text and location then we'll skip if (WorkspaceUtility.ContainsFFSNWithValues(wsParent, sn.Text, new MathCore.Vector(sn.LocationX, sn.LocationY))) { continue; } // Add it to the parent wsParent.StickyNotes.Add(sn); } // Next do process units in the child foreach (AbstractProcessUnit apuChild in wsChild.ProcessUnits) { AbstractProcessUnit apuParent = wsParent.GetProcessUnit(apuChild.Id); // If the parent workspace doesn't contain a process unit with the same ID then we // skip it if (null == apuParent) { continue; } foreach (StickyNote comment in apuChild.Comments) { if (WorkspaceUtility.CollectionContainsItemWithText(apuParent.Comments, comment.Text)) { // Skip it if there's already a comment with the same text continue; } // Add it to the parent process unit apuParent.Comments.Add(comment); } } // Now do streams in the child foreach (AbstractStream sChild in wsChild.Streams) { AbstractStream sParent = wsParent.GetStream(sChild.Id); // If the parent workspace doesn't contain a stream with the same ID then we // skip it if (null == sParent) { continue; } foreach (StickyNote comment in sChild.Comments) { if (WorkspaceUtility.CollectionContainsItemWithText(sParent.Comments, comment.Text)) { // Skip it if there's already a comment with the same text continue; } // Add the comment to the parent stream sParent.Comments.Add(comment); } } // Equation comments need to be merged as well foreach (EquationModel emChild in wsChild.Equations) { // Get the equation object in the parent with the same ID EquationModel emParent = wsParent.Equations.GetById(emChild.Id); // If we can't find it then move on to the next if (null == emParent) { continue; } // Now add each comment in the child that isn't already in the parent foreach (BasicComment bcChild in emChild.Comments) { if (!emParent.ContainsComment(bcChild.CommentText)) { emParent.Comments.Add(bcChild); } } } // Lastly we deal with the comments for the degrees of freedom analysis. We only // merge in comments from the child if the analysis text is the same in both. if (wsParent.DegreesOfFreedomAnalysis.Text == wsChild.DegreesOfFreedomAnalysis.Text) { foreach (BasicComment bcChild in wsChild.DegreesOfFreedomAnalysis.Comments) { if (!wsParent.DegreesOfFreedomAnalysis.ContainsComment(bcChild.CommentText)) { wsParent.DegreesOfFreedomAnalysis.Comments.Add(bcChild); } } } // Now that we have everything merged into the parent workspace, we just save it to the // output stream wsParent.Save(output); }
public void SetCommentObject(StickyNote comment, object parent) { if (null != m_sticky) { // Remove event handler before changing this value m_sticky.PropertyChanged -= this.StickyNote_PropertyChanged; } if (null != m_basic) { m_basic.OnTextChanged -= this.BasicComment_OnTextChanged; } // IMPORTANT: Unsubscribe from parent control property changes (if applicable) if (null != m_parentObject) { if (m_parentObject is AbstractProcessUnit) { (m_parentObject as AbstractProcessUnit).PropertyChanged -= this.ParentPU_PropertyChanged; } else if (m_parentObject is AbstractStream) { (m_parentObject as AbstractStream).PropertyChanged -= this.ParentStream_PropertyChanged; } } // Store references m_basic = null; m_sticky = comment; m_parentObject = parent; AbstractStream parentStream = parent as AbstractStream; AbstractProcessUnit parentAPU = parent as AbstractProcessUnit; // Update the UI elements if the comment is not null if (null != m_sticky) { CommentTextBox.Text = m_sticky.Text; UserNameLabel.Content = m_sticky.UserName; // Subsribe to property changes m_sticky.PropertyChanged += this.StickyNote_PropertyChanged; // Allow editing but not deletion CommentTextBox.IsReadOnly = false; XLabel.Visibility = System.Windows.Visibility.Collapsed; // Show or hide the icon based on the parent if (null != parentStream) { // Get the right icon for this type of stream string iconSource = PFD.Streams.StreamControl.GetIconSource(parent.GetType()); BitmapImage bmp = new BitmapImage(); bmp.UriSource = new Uri(iconSource, UriKind.Relative); IconImage.SetValue(Image.SourceProperty, bmp); // Make sure the icon is visible IconImage.Visibility = System.Windows.Visibility.Visible; TitleBarGrid.ColumnDefinitions[0].Width = new GridLength(20.0); // Give the icon a tooltip that tells what this is a comment for ToolTipService.SetToolTip(IconImage, "Comment for stream #" + parentStream.Id); // Subscribe to property changes for the stream parentStream.PropertyChanged += new PropertyChangedEventHandler(ParentStream_PropertyChanged); } else if (null != parentAPU) { // Get the right icon for this type of process unit string iconSource = ProcessUnitControl.GetIconSource(parent.GetType()); BitmapImage bmp = new BitmapImage(); bmp.UriSource = new Uri(iconSource, UriKind.Relative); IconImage.SetValue(Image.SourceProperty, bmp); // Make sure the icon is visible IconImage.Visibility = System.Windows.Visibility.Visible; TitleBarGrid.ColumnDefinitions[0].Width = new GridLength(20.0); // Give the icon a tooltip that tells what this is a comment for ToolTipService.SetToolTip(IconImage, "Comment for " + (m_parentObject as AbstractProcessUnit).Label); // Subscribe to property changes for the process unit parentAPU.PropertyChanged += new PropertyChangedEventHandler(ParentPU_PropertyChanged); } else { // Make sure the icon is hidden IconImage.Visibility = System.Windows.Visibility.Collapsed; TitleBarGrid.ColumnDefinitions[0].Width = new GridLength(0.0); } } }
/// <summary> /// Refreshes the control palette with appropriate controls based on the difficulty setting. This /// must be called each time the user changes the difficulty setting in the application. /// </summary> public void RefreshPalette(OptionDifficultySetting setting) { // Show or hide the heat stream button based on the setting if ((new HeatStream(-1)).IsAvailableWithDifficulty(setting)) { HeatStreamButton.Visibility = System.Windows.Visibility.Visible; } else { HeatStreamButton.Visibility = System.Windows.Visibility.Collapsed; } // Now we use reflection to create the process unit buttons // First clear the content in the process unit stack panel ProcessUnitsPanel.Children.Clear(); // We will create potentially multiple stack panels for rows of buttons StackPanel spPUs = null; // Keep track of how many buttons we create int puBtns = 0; // Use reflection to find appropriate process units and streams for the palette Assembly a = typeof(Logic.AbstractProcessUnit).Assembly; foreach (Type t in a.GetTypes()) { // Ignore abstract types if (t.IsAbstract) { continue; } // We only are interested in types that inherit from AbstractProcessUnit if (t.IsSubclassOf(typeof(AbstractProcessUnit)) && !t.IsAbstract) { // We've found a potential process unit, but we need to make sure that // it can be created under the specified difficulty setting AbstractProcessUnit unit = Activator.CreateInstance(t, (int)-1) as AbstractProcessUnit; if (unit.IsAvailableWithDifficulty(setting)) { if (0 == (puBtns % m_buttonsPerRow)) { // Create a new row spPUs = new StackPanel(); spPUs.Orientation = Orientation.Horizontal; // Add the first button to it spPUs.Children.Add(CreateButton( ProcessUnitControl.GetIconSource(t), unit.Description, t)); ProcessUnitsPanel.Children.Add(spPUs); } else { spPUs.Children.Add(CreateButton( ProcessUnitControl.GetIconSource(t), unit.Description, t)); } puBtns++; } } } }
public void TestCommentMerge() { // Build a workspace with 2 process units Workspace ws1 = new Workspace(); AbstractProcessUnit apu1 = new Separator(); AbstractProcessUnit apu2 = new Separator(); ws1.AddProcessUnit(apu1); ws1.AddProcessUnit(apu2); // Add 2 comments to the first and 3 to the second. These will be comments shared // between the two workspaces apu1.Comments.Add(new StickyNote() { Text = "Comment 1 on APU1" }); apu1.Comments.Add(new StickyNote() { Text = "Comment 2 on APU1" }); apu2.Comments.Add(new StickyNote() { Text = "Comment 1 on APU2" }); apu2.Comments.Add(new StickyNote() { Text = "Comment 2 on APU2" }); apu2.Comments.Add(new StickyNote() { Text = "Comment 3 on APU2" }); // Save the workspace to a memory stream MemoryStream ms1 = new MemoryStream(); ws1.Save(ms1); // Load to a new workspace. The two workspaces should have identical content after // the load. Workspace ws2 = new Workspace(); ws2.Load(ms1); // Get the process units from the second workspace AbstractProcessUnit ws2_apu1 = ws2.GetProcessUnit(apu1.Id); AbstractProcessUnit ws2_apu2 = ws2.GetProcessUnit(apu2.Id); // Make sure that they both exist if (null == ws2_apu1 || null == ws2_apu2) { Assert.Fail("After save, one or more process units was not found (TestCommentMerge)"); return; } // Now is where we add comments that are unique to the different workspaces apu1.Comments.Add(new StickyNote() { Text = "Comment on APU1 only in WS1" }); apu2.Comments.Add(new StickyNote() { Text = "Comment on APU2 only in WS1" }); ws2_apu1.Comments.Add(new StickyNote() { Text = "Comment on APU1 only in WS2" }); ws2_apu2.Comments.Add(new StickyNote() { Text = "Comment on APU2 only in WS2" }); ws2_apu2.Comments.Add(new StickyNote() { Text = "Another comment on APU2 only in WS2" }); // (Re-)create the memory streams and save both workspaces ms1 = new MemoryStream(); MemoryStream ms2 = new MemoryStream(); ws1.Save(ms1); ws2.Save(ms2); // Allocate a third memory stream for the merge MemoryStream msMerged = new MemoryStream(); // Merge Core.CommentMerger.Merge(ms1, "WS1_User", ms2, "WS2_User", msMerged); // Load back into a workspace and verify ws1.Load(msMerged); // ------ VERIFICATION ------ // There should be 2 process units apu1 = ws1.GetProcessUnit(apu1.Id); apu2 = ws1.GetProcessUnit(apu2.Id); if (null == ws2_apu1 || null == ws2_apu2) { Assert.Fail("After comment merge, one or more process units was not found (TestCommentMerge)"); return; } // The first one should have 4 comments. 2 from the original two that are in both documents, 1 // unique to the first workspace and 1 unique to the second Assert.IsTrue(4 == apu1.Comments.Count, "Process unit APU1 in document after merge should have 4 comments but has " + apu1.Comments.Count.ToString()); // The second one should have 6 comments. 3 from the original two that are in both documents, 1 // unique to the first workspace and 2 unique to the second Assert.IsTrue(6 == apu2.Comments.Count, "Process unit APU2 in document after merge should have 5 comments but has " + apu2.Comments.Count.ToString()); }
public DetachIncomingStream(AbstractProcessUnit processUnit, AbstractStream incomingStream) { m_pu = processUnit; m_stream = incomingStream; }
public void TestSaveLoad() { int i; Workspace ws1 = new Workspace(); Random rand = new Random(); // Add a random number of process units List <int> puIDs = new List <int>(); int numPU = rand.Next(25); for (i = 0; i < numPU; i++) { AbstractProcessUnit pu = new Mixer(); ws1.AddProcessUnit(pu); puIDs.Add(pu.Id); } // Add a random number of chemical streams int numStreams = rand.Next(10); for (i = 0; i < numStreams; i++) { AbstractStream stream = new ChemicalStream(AbstractStream.GetNextUID()); ws1.AddStream(stream); // Don't forget that the properties table needs to be created separately stream.PropertiesTable = new StreamPropertiesTable(stream); // 50% chance of connecting a destination (attempting a connect that is) if (0 == (rand.Next() % 2)) { AbstractProcessUnit pu = ws1.ProcessUnits[rand.Next(ws1.ProcessUnitCount)]; if (pu.AttachIncomingStream(stream)) { stream.Destination = pu; } } } // Save the workspace to a memory stream MemoryStream ms = new MemoryStream(); ws1.Save(ms, "TEST_VersionNA"); // Load to a new workspace Workspace ws2 = new Workspace(); ws2.Load(ms); // Make sure the number of process units and streams match Assert.IsTrue(numPU == ws2.ProcessUnitCount, "Number of process units between saved document (" + numPU.ToString() + ") and loaded document (" + ws2.ProcessUnitCount.ToString() + ") do not match"); Assert.IsTrue(numStreams == ws2.Streams.Count, "Number of streams between saved document (" + numStreams.ToString() + ") and loaded document (" + ws2.Streams.Count.ToString() + ") do not match"); // Test that the incoming/outgoing streams for process units match foreach (AbstractProcessUnit pu1 in ws1.ProcessUnits) { AbstractProcessUnit pu2 = ws2.GetProcessUnit(pu1.Id); Assert.IsNotNull(pu2, "Process unit with ID=" + pu1.Id.ToString() + " from workspace 1 (saved) was not " + "found in workspace 2 (loaded)."); // For now just compare outoging stream count Assert.IsTrue(pu1.OutgoingStreamCount == pu2.OutgoingStreamCount, "Mis-match outgoing stream count"); } }