Xamarin Public Jenkins (auto-signing) 536cd135cc Imported Upstream version 5.4.0.167
Former-commit-id: 5624ac747d633e885131e8349322922b6a59baaa
2017-08-21 15:34:15 +00:00

845 lines
26 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

//-------------------------------------------------------------
// <copyright company=Microsoft Corporation>
// Copyright © Microsoft Corporation. All Rights Reserved.
// </copyright>
//-------------------------------------------------------------
// @owner=alexgor, deliant
//=================================================================
// File: AnnotationCollection.cs
//
// Namespace: System.Web.UI.WebControls[Windows.Forms].Charting
//
// Classes: AnnotationCollection, AnnotationCollectionEditor
//
// Purpose: Collection of annotation objects.
//
// Reviewed:
//
//===================================================================
#region Used namespace
using System;
using System.Collections;
using System.Collections.Specialized;
using System.ComponentModel;
using System.ComponentModel.Design;
using System.Data;
using System.Drawing;
using System.Drawing.Design;
using System.Drawing.Text;
using System.Drawing.Drawing2D;
using System.Globalization;
using System.Diagnostics.CodeAnalysis;
#if Microsoft_CONTROL
using System.Windows.Forms;
using System.Windows.Forms.DataVisualization.Charting;
using System.Windows.Forms.DataVisualization.Charting.Data;
using System.Windows.Forms.DataVisualization.Charting.ChartTypes;
using System.Windows.Forms.DataVisualization.Charting.Utilities;
using System.Windows.Forms.DataVisualization.Charting.Borders3D;
#else
using System.Web;
using System.Web.UI;
using System.Web.UI.DataVisualization.Charting;
using System.Web.UI.DataVisualization.Charting.Data;
using System.Web.UI.DataVisualization.Charting.Utilities;
#endif
#endregion
#if Microsoft_CONTROL
namespace System.Windows.Forms.DataVisualization.Charting
#else
namespace System.Web.UI.DataVisualization.Charting
#endif
{
/// <summary>
/// <b>AnnotationCollection</b> is a collection that stores chart annotation objects.
/// <seealso cref="Charting.Chart.Annotations"/>
/// </summary>
/// <remarks>
/// All chart annotations are stored in this collection. It is exposed as
/// a <see cref="Charting.Chart.Annotations"/> property of the chart. It is also used to
/// store annotations inside the <see cref="AnnotationGroup"/> class.
/// <para>
/// This class includes methods for adding, inserting, iterating and removing annotations.
/// </para>
/// </remarks>
[
SRDescription("DescriptionAttributeAnnotations3"),
]
#if ASPPERM_35
[AspNetHostingPermission(System.Security.Permissions.SecurityAction.InheritanceDemand, Level = AspNetHostingPermissionLevel.Minimal)]
[AspNetHostingPermission(System.Security.Permissions.SecurityAction.LinkDemand, Level = AspNetHostingPermissionLevel.Minimal)]
#endif
public class AnnotationCollection : ChartNamedElementCollection<Annotation>
{
#region Fields
/// <summary>
/// Group this collection belongs too
/// </summary>
internal AnnotationGroup AnnotationGroup { get; set; }
#if Microsoft_CONTROL
// Annotation object that was last clicked on
internal Annotation lastClickedAnnotation = null;
// Start point of annotation moving or resizing
private PointF _movingResizingStartPoint = PointF.Empty;
// Current resizing mode
private ResizingMode _resizingMode = ResizingMode.None;
// Annotation object which is currently placed on the chart
internal Annotation placingAnnotation = null;
#endif
#endregion
#region Construction and Initialization
/// <summary>
/// Initializes a new instance of the <see cref="AnnotationCollection"/> class.
/// </summary>
/// <param name="parent">The parent chart element.</param>
internal AnnotationCollection(IChartElement parent) : base(parent)
{
}
#endregion
#region Items Inserting and Removing Notification methods
/// <summary>
/// Initializes the specified item.
/// </summary>
/// <param name="item">The item.</param>
internal override void Initialize(Annotation item)
{
if (item != null)
{
TextAnnotation textAnnotation = item as TextAnnotation;
if (textAnnotation != null && string.IsNullOrEmpty(textAnnotation.Text) && Chart != null && Chart.IsDesignMode())
{
textAnnotation.Text = item.Name;
}
//If the collection belongs to annotation group we need to pass a ref to this group to all the child annotations
if (this.AnnotationGroup != null)
{
item.annotationGroup = this.AnnotationGroup;
}
item.ResetCurrentRelativePosition();
}
base.Initialize(item);
}
/// <summary>
/// Deinitializes the specified item.
/// </summary>
/// <param name="item">The item.</param>
internal override void Deinitialize(Annotation item)
{
if (item != null)
{
item.annotationGroup = null;
item.ResetCurrentRelativePosition();
}
base.Deinitialize(item);
}
/// <summary>
/// Finds an annotation in the collection by name.
/// </summary>
/// <param name="name">
/// Name of the annotation to find.
/// </param>
/// <returns>
/// <see cref="Annotation"/> object, or null (or nothing) if it does not exist.
/// </returns>
public override Annotation FindByName(string name)
{
foreach(Annotation annotation in this)
{
// Compare annotation name
if(annotation.Name == name)
{
return annotation;
}
// Check if annotation is a group
AnnotationGroup annotationGroup = annotation as AnnotationGroup;
if(annotationGroup != null)
{
Annotation result = annotationGroup.Annotations.FindByName(name);
if(result != null)
{
return result;
}
}
}
return null;
}
#endregion
#region Painting
/// <summary>
/// Paints all annotation objects in the collection.
/// </summary>
/// <param name="chartGraph">Chart graphics used for painting.</param>
/// <param name="drawAnnotationOnly">Indicates that only annotation objects are redrawn.</param>
[SuppressMessage("Microsoft.Usage", "CA1801:ReviewUnusedParameters", Justification="This parameter is used when compiling for the Microsoft version of Chart")]
internal void Paint(ChartGraphics chartGraph, bool drawAnnotationOnly)
{
#if Microsoft_CONTROL
ChartPicture chartPicture = this.Chart.chartPicture;
// Restore previous background using double buffered bitmap
if(!chartPicture.isSelectionMode &&
this.Count > 0 /*&&
!this.Chart.chartPicture.isPrinting*/)
{
chartPicture.backgroundRestored = true;
Rectangle chartPosition = new Rectangle(0, 0, chartPicture.Width, chartPicture.Height);
if(chartPicture.nonTopLevelChartBuffer == null || !drawAnnotationOnly)
{
// Dispose previous bitmap
if(chartPicture.nonTopLevelChartBuffer != null)
{
chartPicture.nonTopLevelChartBuffer.Dispose();
chartPicture.nonTopLevelChartBuffer = null;
}
// Copy chart area plotting rectangle from the chart's dubble buffer image into area dubble buffer image
if (this.Chart.paintBufferBitmap != null &&
this.Chart.paintBufferBitmap.Size.Width >= chartPosition.Size.Width &&
this.Chart.paintBufferBitmap.Size.Height >= chartPosition.Size.Height)
{
chartPicture.nonTopLevelChartBuffer = this.Chart.paintBufferBitmap.Clone(
chartPosition, this.Chart.paintBufferBitmap.PixelFormat);
}
}
else if(drawAnnotationOnly && chartPicture.nonTopLevelChartBuffer != null)
{
// Restore previous background
this.Chart.paintBufferBitmapGraphics.DrawImageUnscaled(
chartPicture.nonTopLevelChartBuffer,
chartPosition);
}
}
#endif // Microsoft_CONTROL
// Draw all annotation objects
foreach(Annotation annotation in this)
{
// Reset calculated relative position
annotation.ResetCurrentRelativePosition();
if(annotation.IsVisible())
{
bool resetClip = false;
// Check if anchor point ----osiated with plot area is inside the scaleView
if(annotation.IsAnchorVisible())
{
// Set annotation object clipping
if(annotation.ClipToChartArea.Length > 0 &&
annotation.ClipToChartArea != Constants.NotSetValue &&
Chart != null)
{
int areaIndex = Chart.ChartAreas.IndexOf(annotation.ClipToChartArea);
if( areaIndex >= 0 )
{
// Get chart area object
ChartArea chartArea = Chart.ChartAreas[areaIndex];
chartGraph.SetClip(chartArea.PlotAreaPosition.ToRectangleF());
resetClip = true;
}
}
// Start Svg Selection mode
string url = String.Empty;
#if !Microsoft_CONTROL
url = annotation.Url;
#endif // !Microsoft_CONTROL
chartGraph.StartHotRegion(
annotation.ReplaceKeywords(url),
annotation.ReplaceKeywords(annotation.ToolTip) );
// Draw annotation object
annotation.Paint(Chart, chartGraph);
// End Svg Selection mode
chartGraph.EndHotRegion( );
// Reset clipping region
if(resetClip)
{
chartGraph.ResetClip();
}
}
}
}
}
#endregion
#region Mouse Events Handlers
#if Microsoft_CONTROL
/// <summary>
/// Mouse was double clicked.
/// </summary>
internal void OnDoubleClick()
{
if(lastClickedAnnotation != null &&
lastClickedAnnotation.AllowTextEditing)
{
TextAnnotation textAnnotation = lastClickedAnnotation as TextAnnotation;
if(textAnnotation == null)
{
AnnotationGroup group = lastClickedAnnotation as AnnotationGroup;
if (group != null)
{
// Try to edit text annotation in the group
foreach (Annotation annot in group.Annotations)
{
TextAnnotation groupAnnot = annot as TextAnnotation;
if (groupAnnot != null &&
groupAnnot.AllowTextEditing)
{
// Get annotation position in relative coordinates
PointF firstPoint = PointF.Empty;
PointF anchorPoint = PointF.Empty;
SizeF size = SizeF.Empty;
groupAnnot.GetRelativePosition(out firstPoint, out size, out anchorPoint);
RectangleF textPosition = new RectangleF(firstPoint, size);
// Check if last clicked coordinate is inside this text annotation
if (groupAnnot.GetGraphics() != null &&
textPosition.Contains(groupAnnot.GetGraphics().GetRelativePoint(this._movingResizingStartPoint)))
{
textAnnotation = groupAnnot;
lastClickedAnnotation = textAnnotation;
break;
}
}
}
}
}
if(textAnnotation != null)
{
// Start annotation text editing
textAnnotation.BeginTextEditing();
}
}
}
/// <summary>
/// Checks if specified point is contained by any of the selection handles.
/// </summary>
/// <param name="point">Point which is tested in pixel coordinates.</param>
/// <param name="resizingMode">Handle containing the point or None.</param>
/// <returns>Annotation that contains the point or Null.</returns>
internal Annotation HitTestSelectionHandles(PointF point, ref ResizingMode resizingMode)
{
Annotation annotation = null;
if( Common != null &&
Common.graph != null)
{
PointF pointRel = Common.graph.GetRelativePoint(point);
foreach(Annotation annot in this)
{
// Reset selcted path point
annot.currentPathPointIndex = -1;
// Check if annotation is selected
if(annot.IsSelected)
{
if(annot.selectionRects != null)
{
for(int index = 0; index < annot.selectionRects.Length; index++)
{
if(!annot.selectionRects[index].IsEmpty &&
annot.selectionRects[index].Contains(pointRel))
{
annotation = annot;
if(index > (int)ResizingMode.AnchorHandle)
{
resizingMode = ResizingMode.MovingPathPoints;
annot.currentPathPointIndex = index - 9;
}
else
{
resizingMode = (ResizingMode)index;
}
}
}
}
}
}
}
return annotation;
}
/// <summary>
/// Mouse button pressed in the control.
/// </summary>
/// <param name="e">Event arguments.</param>
/// <param name="isHandled">Returns true if event is handled and no further processing required.</param>
internal void OnMouseDown(MouseEventArgs e, ref bool isHandled)
{
// Reset last clicked annotation object and stop text editing
if(lastClickedAnnotation != null)
{
TextAnnotation textAnnotation = lastClickedAnnotation as TextAnnotation;
if(textAnnotation != null)
{
// Stop annotation text editing
textAnnotation.StopTextEditing();
}
lastClickedAnnotation = null;
}
// Check if in annotation placement mode
if( this.placingAnnotation != null)
{
// Process mouse down
this.placingAnnotation.PlacementMouseDown(new PointF(e.X, e.Y), e.Button);
// Set handled flag
isHandled = true;
return;
}
// Process only left mouse buttons
if(e.Button == MouseButtons.Left)
{
bool updateRequired = false;
this._resizingMode = ResizingMode.None;
// Check if mouse buton was pressed in any selection handles areas
Annotation annotation =
HitTestSelectionHandles(new PointF(e.X, e.Y), ref this._resizingMode);
// Check if mouse button was pressed over one of the annotation objects
if(annotation == null && this.Count > 0)
{
HitTestResult result = this.Chart.HitTest(e.X, e.Y, ChartElementType.Annotation);
if(result != null && result.ChartElementType == ChartElementType.Annotation)
{
annotation = (Annotation)result.Object;
}
}
// Unselect all annotations if mouse clicked outside any annotations
if(annotation == null || !annotation.IsSelected)
{
if((Control.ModifierKeys & Keys.Control) != Keys.Control &&
(Control.ModifierKeys & Keys.Shift) != Keys.Shift)
{
foreach (Annotation annot in this.Chart.Annotations)
{
if(annot != annotation && annot.IsSelected)
{
annot.IsSelected = false;
updateRequired = true;
// Call selection changed notification
if (this.Chart != null)
{
this.Chart.OnAnnotationSelectionChanged(annot);
}
}
}
}
}
// Process mouse action in the annotation object
if(annotation != null)
{
// Mouse down event handled
isHandled = true;
// Select/Unselect annotation
Annotation selectableAnnotation = annotation;
if(annotation.AnnotationGroup != null)
{
// Select annotation group when click on any child annotations
selectableAnnotation = annotation.AnnotationGroup;
}
if(!selectableAnnotation.IsSelected && selectableAnnotation.AllowSelecting)
{
selectableAnnotation.IsSelected = true;
updateRequired = true;
// Call selection changed notification
if (this.Chart != null)
{
this.Chart.OnAnnotationSelectionChanged(selectableAnnotation);
}
}
else if((Control.ModifierKeys & Keys.Control) == Keys.Control ||
(Control.ModifierKeys & Keys.Shift) == Keys.Shift)
{
selectableAnnotation.IsSelected = false;
updateRequired = true;
// Call selection changed notification
if (this.Chart != null)
{
this.Chart.OnAnnotationSelectionChanged(selectableAnnotation);
}
}
// Remember last clicked and selected annotation
lastClickedAnnotation = annotation;
// Rember mouse position
this._movingResizingStartPoint = new PointF(e.X, e.Y);
// Start moving, repositioning or resizing of annotation
if(annotation.IsSelected)
{
// Check if one of selection handles was clicked on
this._resizingMode = annotation.GetSelectionHandle(this._movingResizingStartPoint);
if(!annotation.AllowResizing &&
this._resizingMode >= ResizingMode.TopLeftHandle &&
this._resizingMode <= ResizingMode.LeftHandle)
{
this._resizingMode = ResizingMode.None;
}
if(!annotation.AllowAnchorMoving &&
this._resizingMode == ResizingMode.AnchorHandle)
{
this._resizingMode = ResizingMode.None;
}
if(this._resizingMode == ResizingMode.None && annotation.AllowMoving)
{
// Annotation moving mode
this._resizingMode = ResizingMode.Moving;
}
}
else
{
if(this._resizingMode == ResizingMode.None && annotation.AllowMoving)
{
// Do not allow moving child annotations inside the group.
// Only the whole group can be selected, resized or repositioned.
if (annotation.AnnotationGroup != null)
{
// Move the group instead
lastClickedAnnotation = annotation.AnnotationGroup;
}
// Annotation moving mode
this._resizingMode = ResizingMode.Moving;
}
}
}
// Update chart
if(updateRequired)
{
// Invalidate and update the chart
this.Chart.Invalidate(true);
this.Chart.UpdateAnnotations();
}
}
}
/// <summary>
/// Mouse button released in the control.
/// </summary>
/// <param name="e">Event arguments.</param>
internal void OnMouseUp(MouseEventArgs e)
{
// Check if in annotation placement mode
if( this.placingAnnotation != null)
{
if(!this.placingAnnotation.PlacementMouseUp(new PointF(e.X, e.Y), e.Button))
{
return;
}
}
if(e.Button == MouseButtons.Left)
{
// Reset moving sizing start point
this._movingResizingStartPoint = PointF.Empty;
this._resizingMode = ResizingMode.None;
}
// Loop through all annotation objects
for(int index = 0; index < this.Count; index++)
{
Annotation annotation = this[index];
// NOTE: Automatic deleting feature was disabled. -AG.
/*
// Delete all annotation objects moved outside clipping region
if( annotation.outsideClipRegion )
{
this.List.RemoveAt(index);
--index;
}
*/
// Reset start position/location fields
annotation.startMovePositionRel = RectangleF.Empty;
annotation.startMoveAnchorLocationRel = PointF.Empty;
if(annotation.startMovePathRel != null)
{
annotation.startMovePathRel.Dispose();
annotation.startMovePathRel = null;
}
// Fire position changed event
if( annotation.positionChanged )
{
annotation.positionChanged = false;
if (this.Chart != null)
{
this.Chart.OnAnnotationPositionChanged(annotation);
}
}
}
}
/// <summary>
/// Mouse moved in the control.
/// </summary>
/// <param name="e">Event arguments.</param>
internal void OnMouseMove(MouseEventArgs e)
{
// Check if in annotation placement mode
if(this.placingAnnotation != null)
{
System.Windows.Forms.Cursor newCursor = this.Chart.Cursor;
if(this.placingAnnotation.IsValidPlacementPosition(e.X, e.Y))
{
newCursor = Cursors.Cross;
}
else
{
newCursor = this.Chart.defaultCursor;
}
// Set current chart cursor
if (newCursor != this.Chart.Cursor)
{
System.Windows.Forms.Cursor tmpCursor = this.Chart.defaultCursor;
this.Chart.Cursor = newCursor;
this.Chart.defaultCursor = tmpCursor;
}
this.placingAnnotation.PlacementMouseMove(new PointF(e.X, e.Y));
return;
}
// Check if currently resizing/moving annotation
if(!this._movingResizingStartPoint.IsEmpty &&
this._resizingMode != ResizingMode.None)
{
// Calculate how far the mouse was moved
SizeF moveDistance = new SizeF(
this._movingResizingStartPoint.X - e.X,
this._movingResizingStartPoint.Y - e.Y );
// Update location of all selected annotation objects
foreach(Annotation annot in this)
{
if(annot.IsSelected &&
( (this._resizingMode == ResizingMode.MovingPathPoints && annot.AllowPathEditing) ||
(this._resizingMode == ResizingMode.Moving && annot.AllowMoving) ||
(this._resizingMode == ResizingMode.AnchorHandle && annot.AllowAnchorMoving) ||
(this._resizingMode >= ResizingMode.TopLeftHandle && this._resizingMode <= ResizingMode.LeftHandle && annot.AllowResizing) ) )
{
annot.AdjustLocationSize(moveDistance, this._resizingMode, true, true);
}
}
// Move last clicked non-selected annotation
if(lastClickedAnnotation != null &&
!lastClickedAnnotation.IsSelected)
{
if(this._resizingMode == ResizingMode.Moving &&
lastClickedAnnotation.AllowMoving)
{
lastClickedAnnotation.AdjustLocationSize(moveDistance, this._resizingMode, true, true);
}
}
// Invalidate and update the chart
this.Chart.Invalidate(true);
this.Chart.UpdateAnnotations();
}
else if(this.Count > 0)
{
// Check if currently placing annotation from the UserInterface
bool process = true;
if(process)
{
// Check if mouse pointer is over the annotation selection handle
ResizingMode currentResizingMode = ResizingMode.None;
Annotation annotation =
HitTestSelectionHandles(new PointF(e.X, e.Y), ref currentResizingMode);
// Check if mouse pointer over the annotation object movable area
if(annotation == null)
{
HitTestResult result = this.Chart.HitTest(e.X, e.Y, ChartElementType.Annotation);
if(result != null && result.ChartElementType == ChartElementType.Annotation)
{
annotation = (Annotation)result.Object;
if(annotation != null)
{
// Check if annotation is in the collection
if(this.Contains(annotation))
{
currentResizingMode = ResizingMode.Moving;
if(annotation.AllowMoving == false)
{
// Movement is not allowed
annotation = null;
currentResizingMode = ResizingMode.None;
}
}
}
}
}
// Set mouse cursor
SetResizingCursor(annotation, currentResizingMode);
}
}
}
/// <summary>
/// Sets mouse cursor shape.
/// </summary>
/// <param name="annotation">Annotation object.</param>
/// <param name="currentResizingMode">Resizing mode.</param>
private void SetResizingCursor(Annotation annotation, ResizingMode currentResizingMode)
{
// Change current cursor
if(this.Chart != null)
{
System.Windows.Forms.Cursor newCursor = this.Chart.Cursor;
if(annotation != null)
{
if(currentResizingMode == ResizingMode.MovingPathPoints &&
annotation.AllowPathEditing)
{
newCursor = Cursors.Cross;
}
if(currentResizingMode == ResizingMode.Moving &&
annotation.AllowMoving)
{
newCursor = Cursors.SizeAll;
}
if(currentResizingMode == ResizingMode.AnchorHandle &&
annotation.AllowAnchorMoving)
{
newCursor = Cursors.Cross;
}
if(currentResizingMode != ResizingMode.Moving &&
annotation.AllowResizing)
{
if(annotation.SelectionPointsStyle == SelectionPointsStyle.TwoPoints)
{
if(currentResizingMode == ResizingMode.TopLeftHandle ||
currentResizingMode == ResizingMode.BottomRightHandle)
{
newCursor = Cursors.Cross;
}
}
else
{
if(currentResizingMode == ResizingMode.TopLeftHandle ||
currentResizingMode == ResizingMode.BottomRightHandle)
{
newCursor = Cursors.SizeNWSE;
}
else if(currentResizingMode == ResizingMode.TopRightHandle ||
currentResizingMode == ResizingMode.BottomLeftHandle)
{
newCursor = Cursors.SizeNESW;
}
else if(currentResizingMode == ResizingMode.TopHandle ||
currentResizingMode == ResizingMode.BottomHandle)
{
newCursor = Cursors.SizeNS;
}
else if(currentResizingMode == ResizingMode.LeftHandle ||
currentResizingMode == ResizingMode.RightHandle)
{
newCursor = Cursors.SizeWE;
}
}
}
}
else
{
newCursor = this.Chart.defaultCursor;
}
// Set current chart cursor
if (newCursor != this.Chart.Cursor)
{
System.Windows.Forms.Cursor tmpCursor = this.Chart.defaultCursor;
this.Chart.Cursor = newCursor;
this.Chart.defaultCursor = tmpCursor;
}
}
}
#endif // Microsoft_CONTROL
#endregion
#region Event handlers
internal void ChartAreaNameReferenceChanged(object sender, NameReferenceChangedEventArgs e)
{
// If all the chart areas are removed and then a new one is inserted - Annotations don't get bound to it by default
if (e.OldElement == null)
return;
foreach (Annotation annotation in this)
{
if (annotation.ClipToChartArea == e.OldName)
annotation.ClipToChartArea = e.NewName;
AnnotationGroup group = annotation as AnnotationGroup;
if (group != null)
{
group.Annotations.ChartAreaNameReferenceChanged(sender, e);
}
}
}
#endregion
}
}