|
//------------------------------------------------------------------------------
// <copyright file="DataGridRelationshipRow.cs" company="Microsoft">
// Copyright (c) Microsoft Corporation. All rights reserved.
// </copyright>
//------------------------------------------------------------------------------
namespace System.Windows.Forms {
using System.Runtime.Remoting;
using System;
using System.Runtime.InteropServices;
using System.Security.Permissions;
using System.Windows.Forms;
using System.ComponentModel;
using System.Drawing;
using Microsoft.Win32;
using System.Diagnostics;
using System.Collections;
using System.Globalization;
/// <include file='doc\DataGridRelationshipRow.uex' path='docs/doc[@for="DataGridRelationshipRow"]/*' />
/// <devdoc>
/// This class fully encapsulates the painting logic for a row
/// appearing in a DataGrid.
/// </devdoc>
internal class DataGridRelationshipRow : DataGridRow {
private const bool defaultOpen = false;
private const int expandoBoxWidth = 14;
private const int indentWidth = 20;
// private const int relationshipSpacing = 1;
private const int triangleSize = 5;
private bool expanded = defaultOpen;
// private bool hasRelationships = false;
// private Font linkFont = null;
// private new DataGrid dataGrid; // Currently used only to obtain a Graphics object for measuring text
// private Rectangle relationshipRect = Rectangle.Empty;
// private int relationshipHeight = 0;
// relationships
// we should get this directly from the dgTable.
// private ArrayList relationships;
// private int focusedRelation = -1;
// private int focusedTextWidth;
public DataGridRelationshipRow(DataGrid dataGrid, DataGridTableStyle dgTable, int rowNumber)
: base(dataGrid, dgTable, rowNumber) {
// this.dataGrid = dataGrid;
// linkFont = dataGrid.LinkFont;
// relationshipHeight = dataGrid.LinkFontHeight + this.dgTable.relationshipSpacing;
// if (DataGrid.AllowNavigation) {
// hasRelationships = dgTable.RelationsList.Count > 0;
// }
}
internal protected override int MinimumRowHeight(GridColumnStylesCollection cols) {
/*
if (DataGrid != null && DataGrid.LinkFontHeight + this.dgTable.relationshipSpacing != relationshipHeight) {
relationshipRect = Rectangle.Empty;
relationshipHeight = DataGrid.LinkFontHeight + this.dgTable.relationshipSpacing;
}
*/
return base.MinimumRowHeight(cols) + (this.expanded ? GetRelationshipRect().Height : 0);
}
internal protected override int MinimumRowHeight(DataGridTableStyle dgTable) {
/*
if (DataGrid != null && DataGrid.LinkFontHeight + this.dgTable.relationshipSpacing != relationshipHeight) {
relationshipRect = Rectangle.Empty;
relationshipHeight = DataGrid.LinkFontHeight + this.dgTable.relationshipSpacing;
}
*/
return base.MinimumRowHeight(dgTable) + (this.expanded ? GetRelationshipRect().Height : 0);
}
// =------------------------------------------------------------------
// = Properties
// =------------------------------------------------------------------
public virtual bool Expanded {
get {
return expanded;
}
set {
if (expanded == value)
return;
if (expanded)
Collapse();
else
Expand();
}
}
/*
private Color BorderColor {
get {
if (DataGrid == null)
return Color.Empty;
return DataGrid.GridLineColor;
}
}
*/
#if FALSE
private int BorderWidth {
get {
DataGrid dataGrid = this.DataGrid;
if (dataGrid == null)
return 0;
// if the user set the GridLineStyle property on the dataGrid.
// then use the value of that property
DataGridLineStyle gridStyle;
int gridLineWidth;
if (this.dgTable.IsDefault) {
gridStyle = this.DataGrid.GridLineStyle;
gridLineWidth = this.DataGrid.GridLineWidth;
} else {
gridStyle = this.dgTable.GridLineStyle;
gridLineWidth = this.dgTable.GridLineWidth;
}
if (gridStyle == DataGridLineStyle.None)
return 0;
return gridLineWidth;
}
}
#endif //FALSE
private int FocusedRelation {
get {
return this.dgTable.FocusedRelation;
}
set {
dgTable.FocusedRelation = value;
}
}
// =------------------------------------------------------------------
// = Methods
// =------------------------------------------------------------------
private void Collapse() {
Debug.Assert(this.dgTable.DataGrid.AllowNavigation, "how can the user collapse the relations if the grid does not allow navigation?");
if (expanded) {
expanded = false;
// relationshipRect = Rectangle.Empty;
FocusedRelation = -1;
DataGrid.OnRowHeightChanged(this);
}
}
protected override AccessibleObject CreateAccessibleObject() {
return new DataGridRelationshipRowAccessibleObject(this);
}
private void Expand() {
Debug.Assert(this.dgTable.DataGrid.AllowNavigation, "how can the user expand the relations if the grid does not allow navigation?");
if (expanded == false
&& DataGrid != null
&& this.dgTable != null
&& this.dgTable.RelationsList.Count > 0) {
expanded = true;
FocusedRelation = -1;
// relationshipRect = Rectangle.Empty;
DataGrid.OnRowHeightChanged(this);
}
}
public override int Height {
get {
int height = base.Height;
if (expanded)
return height + GetRelationshipRect().Height;
else
return height;
}
set {
// we should use the RelationshipRect only when the row is expanded
if (expanded)
base.Height = value - GetRelationshipRect().Height;
else
base.Height = value;
}
}
// so the edit box will not paint under the
// grid line of the row
public override Rectangle GetCellBounds(int col) {
Rectangle cellBounds = base.GetCellBounds(col);
// decrement base.Height by 1, so the edit box will not
// paint over the bottom line.
cellBounds.Height = base.Height - 1;
return cellBounds;
}
/// <include file='doc\DataGridRelationshipRow.uex' path='docs/doc[@for="DataGridRelationshipRow.GetOutlineRect"]/*' />
/// <devdoc>
/// Given an origin, this procedure returns
/// a rectangle that describes the location of an outline box.
/// </devdoc>
/// <internalonly/>
private Rectangle GetOutlineRect(int xOrigin, int yOrigin) {
Rectangle outline = new Rectangle(xOrigin + 2,
yOrigin + 2,
9,
9);
return outline;
}
public override Rectangle GetNonScrollableArea() {
if (expanded) {
return GetRelationshipRect();
}
else
return Rectangle.Empty;
}
private Rectangle GetRelationshipRect() {
Debug.Assert(this.expanded, "we should need this rectangle only when the row is expanded");
Rectangle ret = this.dgTable.RelationshipRect;
ret.Y = base.Height - this.dgTable.BorderWidth;
return ret;
}
#if FALSE
private Rectangle GetRelationshipRect() {
if (relationshipRect.IsEmpty) {
Debug.WriteLineIf(CompModSwitches.DGRelationShpRowLayout.TraceVerbose, "GetRelationshipRect grinding away");
if (!expanded) {
return(relationshipRect = new Rectangle(0,0,0,0));
}
Graphics g = DataGrid.CreateGraphicsInternal();
relationshipRect = new Rectangle();
relationshipRect.X = 0; //indentWidth;
relationshipRect.Y = base.Height - this.dgTable.BorderWidth;
// Determine the width of the widest relationship name
int longestRelationship = 0;
for (int r = 0; r < this.dgTable.RelationsList.Count; ++r) {
int rwidth = (int) Math.Ceiling(g.MeasureString(((string) this.dgTable.RelationsList[r]), this.DataGrid.LinkFont).Width);
if (rwidth > longestRelationship)
longestRelationship = rwidth;
}
g.Dispose();
relationshipRect.Width = longestRelationship + 5;
relationshipRect.Width += 2; // relationshipRect border;
relationshipRect.Height = this.dgTable.BorderWidth + relationshipHeight * this.dgTable.RelationsList.Count;
relationshipRect.Height += 2; // relationship border
if (this.dgTable.RelationsList.Count > 0)
relationshipRect.Height += 2 * System.Windows.Forms.DataGridTableStyle.relationshipSpacing;
}
return relationshipRect;
}
#endif// FALSE
private Rectangle GetRelationshipRectWithMirroring() {
Rectangle relRect = GetRelationshipRect();
bool rowHeadersVisible = this.dgTable.IsDefault ? this.DataGrid.RowHeadersVisible : this.dgTable.RowHeadersVisible;
if (rowHeadersVisible) {
int rowHeaderWidth = this.dgTable.IsDefault ? this.DataGrid.RowHeaderWidth : this.dgTable.RowHeaderWidth;
relRect.X += DataGrid.GetRowHeaderRect().X + rowHeaderWidth;
}
relRect.X = MirrorRelationshipRectangle(relRect, DataGrid.GetRowHeaderRect(), DataGrid.RightToLeft == RightToLeft.Yes);
return relRect;
}
/// <include file='doc\DataGridRelationshipRow.uex' path='docs/doc[@for="DataGridRelationshipRow.OnMouseDown"]/*' />
/// <devdoc>
/// Called by the DataGrid when a click occurs in the row's client
/// area. The coordinates are normalized to the rectangle's top
/// left point.
/// </devdoc>
private bool PointOverPlusMinusGlyph(int x, int y, Rectangle rowHeaders, bool alignToRight) {
if (dgTable == null || dgTable.DataGrid == null || !dgTable.DataGrid.AllowNavigation)
return false;
Rectangle insideRowHeaders = rowHeaders;
if (!this.DataGrid.FlatMode) {
insideRowHeaders.Inflate(-1,-1);
}
Rectangle outline = GetOutlineRect(insideRowHeaders.Right - expandoBoxWidth, 0);
outline.X = MirrorRectangle(outline.X, outline.Width, insideRowHeaders, alignToRight);
return outline.Contains(x,y);
}
public override bool OnMouseDown(int x, int y, Rectangle rowHeaders, bool alignToRight) {
bool rowHeadersVisible = this.dgTable.IsDefault ? this.DataGrid.RowHeadersVisible : this.dgTable.RowHeadersVisible;
if (rowHeadersVisible) {
if (PointOverPlusMinusGlyph(x,y,rowHeaders, alignToRight)) {
if (this.dgTable.RelationsList.Count == 0) {
return false;
}
else if (expanded) {
Collapse();
}
else {
Expand();
}
DataGrid.OnNodeClick(EventArgs.Empty);
return true;
}
}
if (!expanded)
return base.OnMouseDown(x, y, rowHeaders, alignToRight);
// hit test for relationships
Rectangle relRect = GetRelationshipRectWithMirroring();
if (relRect.Contains(x, y)) {
int r = RelationFromY(y);
if (r != -1) {
// first, reset the FocusedRelation
FocusedRelation = -1;
DataGrid.NavigateTo(((string)this.dgTable.RelationsList[r]), this, true);
}
// DataGrid.OnLinkClick(EventArgs.Empty);
return true;
}
return base.OnMouseDown(x, y, rowHeaders, alignToRight);
}
public override bool OnMouseMove(int x, int y, Rectangle rowHeaders, bool alignToRight) {
if (!expanded)
return false;
Rectangle relRect = GetRelationshipRectWithMirroring();
if (relRect.Contains(x, y)) {
this.DataGrid.Cursor = Cursors.Hand;
return true;
}
this.DataGrid.Cursor = Cursors.Default;
return base.OnMouseMove(x, y, rowHeaders, alignToRight);
}
// this function will not invalidate all of the
// row
public override void OnMouseLeft(Rectangle rowHeaders, bool alignToRight) {
if (!expanded)
return;
Rectangle relRect = GetRelationshipRect();
relRect.X += rowHeaders.X + this.dgTable.RowHeaderWidth;
relRect.X = MirrorRelationshipRectangle(relRect, rowHeaders, alignToRight);
if (FocusedRelation != -1) {
InvalidateRowRect(relRect);
FocusedRelation = -1;
}
}
public override void OnMouseLeft() {
if (!expanded)
return;
if (FocusedRelation != -1) {
InvalidateRow();
FocusedRelation = -1;
}
base.OnMouseLeft();
}
/// <include file='doc\DataGridRelationshipRow.uex' path='docs/doc[@for="DataGridRelationshipRow.OnKeyPress"]/*' />
/// <devdoc>
/// Called by the DataGrid when a keypress occurs on a row with "focus."
/// </devdoc>
public override bool OnKeyPress(Keys keyData) {
// ignore the shift key if it is not paired w/ the TAB key
if ((keyData & Keys.Modifiers) == Keys.Shift && (keyData & Keys.KeyCode) != Keys.Tab)
return false;
switch (keyData & Keys.KeyCode) {
case Keys.F5:
if (dgTable == null || dgTable.DataGrid == null || !dgTable.DataGrid.AllowNavigation)
return false;
if (expanded)
Collapse();
else
Expand();
FocusedRelation = -1;
return true;
// to make the gridTest run w/ the numLock key on
//
case Keys.NumLock:
if (FocusedRelation != -1)
return false;
else
return base.OnKeyPress(keyData);
case Keys.Enter:
if (FocusedRelation != -1) {
// somebody set the relation number up already
// navigate to the relation
DataGrid.NavigateTo(((string)this.dgTable.RelationsList[FocusedRelation]), this, true);
// now reset the FocusedRelation
FocusedRelation = -1;
return true;
}
else
return false;
case Keys.Tab:
return false;
default:
FocusedRelation = -1;
return base.OnKeyPress(keyData);
}
}
// will reset the FocusedRelation and will invalidate the
// rectangle so that the linkFont is no longer shown
internal override void LoseChildFocus(Rectangle rowHeaders, bool alignToRight) {
// we only invalidate stuff if the row is expanded.
if (FocusedRelation == -1 || !expanded)
return;
FocusedRelation = -1;
Rectangle relRect = GetRelationshipRect();
relRect.X += rowHeaders.X + this.dgTable.RowHeaderWidth;
relRect.X = MirrorRelationshipRectangle(relRect, rowHeaders, alignToRight);
InvalidateRowRect(relRect);
}
// here is the logic for FOCUSED:
//
// first the dataGrid gets the KeyPress.
// the dataGrid passes it to the currentRow. if it is anything other
// than Enter or TAB, the currentRow resets the FocusedRelation variable.
//
// Then the dataGrid takes another look at the TAB key and if it is the case
// it passes it to the row. If the dataRelationshipRow can become focused,
// then it eats the TAB key, otherwise it will give it back to the dataGrid.
//
internal override bool ProcessTabKey(Keys keyData, Rectangle rowHeaders, bool alignToRight) {
Debug.Assert((keyData & Keys.Control) != Keys.Control, "the DataGridRelationshipRow only handles TAB and TAB-SHIFT");
Debug.Assert((keyData & Keys.Alt) != Keys.Alt, "the DataGridRelationshipRow only handles TAB and TAB-SHIFT");
// if there are no relationships, this row can't do anything with the
// key
if (this.dgTable.RelationsList.Count == 0 || dgTable.DataGrid == null || !dgTable.DataGrid.AllowNavigation)
return false;
// expand the relationship box
if (!expanded)
Expand();
if ((keyData & Keys.Shift) == Keys.Shift) {
if (FocusedRelation == 0) {
// if user hits TAB-SHIFT and the focus was on the first relationship then
// reset FocusedRelation and let the dataGrid use the key
//
// consider: Microsoft: if the relationships box is expanded, should we collapse it on leave?
FocusedRelation = -1;
return false;
}
// we need to invalidate the relationshipRectangle, and cause the linkFont to move
// to the next relation
Rectangle relRect = GetRelationshipRect();
relRect.X += rowHeaders.X + this.dgTable.RowHeaderWidth;
relRect.X = MirrorRelationshipRectangle(relRect, rowHeaders, alignToRight);
InvalidateRowRect(relRect);
if (FocusedRelation == -1)
// is the first time that the user focuses on this
// set of relationships
FocusedRelation = this.dgTable.RelationsList.Count - 1;
else
FocusedRelation --;
return true;
}
else {
if (FocusedRelation == this.dgTable.RelationsList.Count - 1) {
// if the user hits TAB and the focus was on the last relationship then
// reset FocusedRelation and let the dataGrid use the key
//
// consider: Microsoft: if the relationships box is expanded, should we collapse it on leave?
FocusedRelation = -1;
return false;
}
// we need to invalidate the relationshipRectangle, and cause the linkFont to move
// to the next relation
Rectangle relRect = GetRelationshipRect();
relRect.X += rowHeaders.X + this.dgTable.RowHeaderWidth;
relRect.X = MirrorRelationshipRectangle(relRect, rowHeaders, alignToRight);
InvalidateRowRect(relRect);
FocusedRelation ++;
return true;
}
}
/// <include file='doc\DataGridRelationshipRow.uex' path='docs/doc[@for="DataGridRelationshipRow.Paint"]/*' />
/// <devdoc>
/// Paints the row.
/// </devdoc>
public override int Paint(Graphics g, Rectangle bounds, Rectangle trueRowBounds, int firstVisibleColumn, int numVisibleColumns) {
return Paint(g, bounds, trueRowBounds, firstVisibleColumn, numVisibleColumns, false);
}
public override int Paint(Graphics g,
Rectangle bounds, // negative offsetted row bounds
Rectangle trueRowBounds, // real row bounds.
int firstVisibleColumn,
int numVisibleColumns,
bool alignToRight) {
if (CompModSwitches.DGRelationShpRowPaint.TraceVerbose) Debug.WriteLine("Painting row " + RowNumber.ToString(CultureInfo.InvariantCulture) + " with bounds " + bounds.ToString());
int bWidth = this.dgTable.BorderWidth;
// paint the data cells
Rectangle dataBounds = bounds;
dataBounds.Height = base.Height - bWidth;
int dataWidth = PaintData(g, dataBounds, firstVisibleColumn, numVisibleColumns, alignToRight);
int dataWidthOffsetted = dataWidth + bounds.X - trueRowBounds.X;
dataBounds.Offset(0, bWidth); // use bWidth, not 1
if (bWidth > 0)
PaintBottomBorder(g, dataBounds, dataWidth, bWidth, alignToRight);
if (expanded && this.dgTable.RelationsList.Count > 0) {
// paint the relationships
Rectangle relationBounds = new Rectangle(trueRowBounds.X,
dataBounds.Bottom,
trueRowBounds.Width,
trueRowBounds.Height - dataBounds.Height - 2 * bWidth);
PaintRelations(g, relationBounds, trueRowBounds, dataWidthOffsetted,
firstVisibleColumn, numVisibleColumns, alignToRight);
relationBounds.Height += 1;
if (bWidth > 0)
PaintBottomBorder(g, relationBounds, dataWidthOffsetted, bWidth, alignToRight);
}
return dataWidth;
}
protected override void PaintCellContents(Graphics g, Rectangle cellBounds, DataGridColumnStyle column,
Brush backBr, Brush foreBrush, bool alignToRight) {
CurrencyManager listManager = DataGrid.ListManager;
// painting the error..
//
string errString = String.Empty;
Rectangle bounds = cellBounds;
object errInfo = DataGrid.ListManager[this.number];
if (errInfo is IDataErrorInfo)
errString = ((IDataErrorInfo) errInfo)[column.PropertyDescriptor.Name];
if (!String.IsNullOrEmpty(errString)) {
Bitmap bmp = GetErrorBitmap();
Rectangle errRect;
lock (bmp) {
errRect = PaintIcon(g, bounds, true, alignToRight, bmp, backBr);
}
// paint the errors correctly when RTL = true
if (alignToRight)
bounds.Width -= errRect.Width + xOffset;
else
bounds.X += errRect.Width + xOffset;
DataGrid.ToolTipProvider.AddToolTip(errString, (IntPtr)(DataGrid.ToolTipId ++), errRect);
}
column.Paint(g, bounds, listManager, this.RowNumber, backBr, foreBrush, alignToRight);
}
public override void PaintHeader(Graphics g, Rectangle bounds, bool alignToRight, bool isDirty) {
DataGrid grid = this.DataGrid;
Rectangle insideBounds = bounds;
if (!grid.FlatMode) {
ControlPaint.DrawBorder3D(g, insideBounds, Border3DStyle.RaisedInner);
insideBounds.Inflate(-1,-1);
}
if (this.dgTable.IsDefault)
PaintHeaderInside(g, insideBounds, this.DataGrid.HeaderBackBrush, alignToRight, isDirty);
else
PaintHeaderInside(g, insideBounds, this.dgTable.HeaderBackBrush, alignToRight, isDirty);
}
public void PaintHeaderInside(Graphics g, Rectangle bounds, Brush backBr, bool alignToRight, bool isDirty) {
// paint the row header
bool paintPlusMinus = dgTable.RelationsList.Count > 0 && dgTable.DataGrid.AllowNavigation;
int rowHeaderBoundsX = MirrorRectangle(bounds.X,
bounds.Width - (paintPlusMinus ? expandoBoxWidth : 0),
bounds, alignToRight);
if (!alignToRight) Debug.Assert(bounds.X == rowHeaderBoundsX, "what's up doc?");
Rectangle rowHeaderBounds = new Rectangle(rowHeaderBoundsX,
bounds.Y,
bounds.Width - (paintPlusMinus ? expandoBoxWidth : 0),
bounds.Height);
base.PaintHeader(g, rowHeaderBounds, alignToRight, isDirty);
// Paint the expando on the right
int expandoBoxX = MirrorRectangle(bounds.X + rowHeaderBounds.Width, expandoBoxWidth, bounds, alignToRight);
if (!alignToRight) Debug.Assert(rowHeaderBounds.Right == expandoBoxX, "what's up doc?");
Rectangle expandoBox = new Rectangle(expandoBoxX,
bounds.Y,
expandoBoxWidth,
bounds.Height);
if (paintPlusMinus) {
PaintPlusMinusGlyph(g, expandoBox, backBr, alignToRight);
}
}
/// <include file='doc\DataGridRelationshipRow.uex' path='docs/doc[@for="DataGridRelationshipRow.PaintRelations"]/*' />
/// <devdoc>
/// Paints the relationships below the data area.
/// </devdoc>
private void PaintRelations(Graphics g, Rectangle bounds, Rectangle trueRowBounds,
int dataWidth, int firstCol, int nCols, bool alignToRight) {
// Calculate the relationship rect.
// relationshipRect = Rectangle.Empty;
Rectangle relRect = GetRelationshipRect();
//relRect.Offset(trueRowBounds.X, trueRowBounds.Y);
relRect.X = alignToRight ? bounds.Right - relRect.Width : bounds.X;
relRect.Y = bounds.Y;
int paintedWidth = Math.Max(dataWidth, relRect.Width);
// Paint the stuff to the right , or left (Bi-Di) of the relationship rect.
Region r = g.Clip;
g.ExcludeClip(relRect);
g.FillRectangle(GetBackBrush(),
alignToRight ? bounds.Right - dataWidth : bounds.X,
bounds.Y,
dataWidth,
bounds.Height);
// Paint the relations' text
g.SetClip(bounds);
relRect.Height -= this.dgTable.BorderWidth; // use bWidth not 1
g.DrawRectangle(SystemPens.ControlText, relRect.X, relRect.Y, relRect.Width - 1, relRect.Height - 1);
relRect.Inflate(-1, -1);
int cy = PaintRelationText(g, relRect, alignToRight);
if (cy < relRect.Height) {
g.FillRectangle(GetBackBrush(), relRect.X, relRect.Y + cy, relRect.Width, relRect.Height - cy);
}
g.Clip = r;
// paint any exposed area to the right or to the left (BI-DI)
if (paintedWidth < bounds.Width) {
int bWidth;
if (this.dgTable.IsDefault)
bWidth = this.DataGrid.GridLineWidth;
else
bWidth = this.dgTable.GridLineWidth;
g.FillRectangle(DataGrid.BackgroundBrush,
alignToRight ? bounds.X : bounds.X + paintedWidth,
bounds.Y,
bounds.Width - paintedWidth - bWidth + 1, // + 1 cause the relationship rectangle was deflated
bounds.Height);
// Paint the border to the right of each cell
if (bWidth > 0) {
Brush br;
// if the user changed the gridLineColor on the dataGrid
// from the defaultValue, then use that value;
if (this.dgTable.IsDefault)
br = this.DataGrid.GridLineBrush;
else
br = this.dgTable.GridLineBrush;
g.FillRectangle(br,
alignToRight ? bounds.Right - bWidth - paintedWidth : bounds.X + paintedWidth - bWidth,
bounds.Y,
bWidth,
bounds.Height);
}
}
}
private int PaintRelationText(Graphics g, Rectangle bounds, bool alignToRight) {
g.FillRectangle(GetBackBrush(), bounds.X, bounds.Y, bounds.Width, System.Windows.Forms.DataGridTableStyle.relationshipSpacing);
int relationshipHeight = this.dgTable.RelationshipHeight;
Rectangle textBounds = new Rectangle(bounds.X, bounds.Y + System.Windows.Forms.DataGridTableStyle.relationshipSpacing,
bounds.Width,
relationshipHeight);
int cy = System.Windows.Forms.DataGridTableStyle.relationshipSpacing;
for (int r = 0; r < this.dgTable.RelationsList.Count; ++r) {
if (cy > bounds.Height)
break;
Brush textBrush = this.dgTable.IsDefault ? this.DataGrid.LinkBrush : this.dgTable.LinkBrush;
Font textFont = this.DataGrid.Font;
textBrush = this.dgTable.IsDefault ? this.DataGrid.LinkBrush : this.dgTable.LinkBrush;
textFont = this.DataGrid.LinkFont;
g.FillRectangle(GetBackBrush(), textBounds);
StringFormat format = new StringFormat();
if (alignToRight) {
format.FormatFlags |= StringFormatFlags.DirectionRightToLeft;
format.Alignment = StringAlignment.Far;
}
g.DrawString(((string)this.dgTable.RelationsList[r]), textFont, textBrush, textBounds,
format);
if (r == FocusedRelation && this.number == this.DataGrid.CurrentCell.RowNumber) {
textBounds.Width = this.dgTable.FocusedTextWidth;
ControlPaint.DrawFocusRectangle(g, textBounds, ((SolidBrush)textBrush).Color, ((SolidBrush)GetBackBrush()).Color);
textBounds.Width = bounds.Width;
}
format.Dispose();
textBounds.Y += relationshipHeight;
cy += textBounds.Height;
}
return cy;
}
/// <include file='doc\DataGridRelationshipRow.uex' path='docs/doc[@for="DataGridRelationshipRow.PaintPlusMinusGlyph"]/*' />
/// <internalonly/>
private void PaintPlusMinusGlyph(Graphics g, Rectangle bounds, Brush backBr, bool alignToRight) {
if (CompModSwitches.DGRelationShpRowPaint.TraceVerbose) Debug.WriteLine("PlusMinusGlyph painting in bounds -> " + bounds.ToString());
Rectangle outline = GetOutlineRect(bounds.X, bounds.Y);
outline = Rectangle.Intersect(bounds, outline);
if (outline.IsEmpty)
return;
g.FillRectangle(backBr, bounds);
if (CompModSwitches.DGRelationShpRowPaint.TraceVerbose) Debug.WriteLine("Painting PlusMinusGlyph with outline -> " + outline.ToString());
// draw the +/- box
Pen drawPen = this.dgTable.IsDefault ? this.DataGrid.HeaderForePen : this.dgTable.HeaderForePen;
g.DrawRectangle(drawPen, outline.X, outline.Y, outline.Width - 1, outline.Height - 1);
int indent = 2;
// draw the -
g.DrawLine(drawPen,
outline.X + indent, outline.Y + outline.Width / 2,
outline.Right - indent - 1, outline.Y + outline.Width/2); // -1 on the y coordinate
if (!expanded) {
// draw the vertical line to make +
g.DrawLine(drawPen,
outline.X + outline.Height/2, outline.Y + indent,
outline.X + outline.Height/2, outline.Bottom - indent - 1); // -1... hinting
}
else {
Point[] points = new Point[3];
points[0] = new Point(outline.X + outline.Height/2, outline.Bottom);
points[1] = new Point(points[0].X, bounds.Y + 2*indent + base.Height);
points[2] = new Point(alignToRight ? bounds.X : bounds.Right,
points[1].Y);
g.DrawLines(drawPen, points);
}
}
private int RelationFromY(int y) {
int relation = -1;
int relationshipHeight = this.dgTable.RelationshipHeight;
Rectangle relRect = GetRelationshipRect();
int cy = base.Height - this.dgTable.BorderWidth + System.Windows.Forms.DataGridTableStyle.relationshipSpacing;
while (cy < relRect.Bottom) {
if (cy > y)
break;
cy += relationshipHeight;
relation++;
}
if (relation >= this.dgTable.RelationsList.Count)
return -1;
return relation;
}
// given the relRect and the rowHeader, this function will return the
// X coordinate of the relationship rectangle as it should appear on the screen
private int MirrorRelationshipRectangle(Rectangle relRect, Rectangle rowHeader, bool alignToRight) {
if (alignToRight)
return rowHeader.X - relRect.Width;
else
return relRect.X;
}
// given the X and Width of a rectangle R1 contained in rect,
// this will return the X coordinate of the rectangle that corresponds to R1 in Bi-Di transformation
private int MirrorRectangle(int x, int width, Rectangle rect, bool alignToRight) {
if (alignToRight)
return rect.Right + rect.X - width - x;
else
return x;
}
[ComVisible(true)]
protected class DataGridRelationshipRowAccessibleObject : DataGridRowAccessibleObject {
public DataGridRelationshipRowAccessibleObject(DataGridRow owner) : base(owner) {
}
protected override void AddChildAccessibleObjects(IList children) {
base.AddChildAccessibleObjects(children);
DataGridRelationshipRow row = (DataGridRelationshipRow)Owner;
if (row.dgTable.RelationsList!= null) {
for (int i=0; i<row.dgTable.RelationsList.Count; i++) {
children.Add(new DataGridRelationshipAccessibleObject(row, i));
}
}
}
private DataGridRelationshipRow RelationshipRow {
get {
return (DataGridRelationshipRow)Owner;
}
}
public override string DefaultAction {
get {
if (RelationshipRow.dgTable.RelationsList.Count > 0) {
if (RelationshipRow.Expanded) {
return SR.GetString(SR.AccDGCollapse);
}
else {
return SR.GetString(SR.AccDGExpand);
}
}
return null;
}
}
public override AccessibleStates State {
get {
AccessibleStates state = base.State;
if (RelationshipRow.dgTable.RelationsList.Count > 0) {
if (((DataGridRelationshipRow)Owner).Expanded) {
state |= AccessibleStates.Expanded;
}
else {
state |= AccessibleStates.Collapsed;
}
}
return state;
}
}
[SecurityPermission(SecurityAction.Demand, Flags = SecurityPermissionFlag.UnmanagedCode)]
public override void DoDefaultAction() {
if (RelationshipRow.dgTable.RelationsList.Count > 0) {
((DataGridRelationshipRow)Owner).Expanded = !((DataGridRelationshipRow)Owner).Expanded;
}
}
public override AccessibleObject GetFocused() {
DataGridRelationshipRow row = (DataGridRelationshipRow)Owner;
int focusRel = row.dgTable.FocusedRelation;
if (focusRel == -1) {
return base.GetFocused();
}
else {
return GetChild(GetChildCount() - row.dgTable.RelationsList.Count + focusRel);
}
}
}
[ComVisible(true)]
protected class DataGridRelationshipAccessibleObject : AccessibleObject {
DataGridRelationshipRow owner = null;
int relationship;
public DataGridRelationshipAccessibleObject(DataGridRelationshipRow owner, int relationship) : base() {
Debug.Assert(owner != null, "DataGridRelationshipAccessibleObject must have a valid owner DataGridRow");
this.owner = owner;
this.relationship = relationship;
}
public override Rectangle Bounds {
get {
Rectangle rowBounds = DataGrid.GetRowBounds(owner);
Rectangle bounds = owner.Expanded ? owner.GetRelationshipRectWithMirroring() : Rectangle.Empty;
bounds.Y += owner.dgTable.RelationshipHeight * relationship;
bounds.Height = owner.Expanded ? owner.dgTable.RelationshipHeight : 0; // when the row is collapsed the height of the relationship object should be 0
// GetRelationshipRectWithMirroring will use the row headers width
if (!owner.Expanded)
bounds.X += rowBounds.X;
bounds.Y += rowBounds.Y;
return owner.DataGrid.RectangleToScreen(bounds);
}
}
public override string Name {
get {
return (string)owner.dgTable.RelationsList[relationship];
}
}
protected DataGridRelationshipRow Owner {
get {
return owner;
}
}
public override AccessibleObject Parent {
[SecurityPermission(SecurityAction.Demand, Flags = SecurityPermissionFlag.UnmanagedCode)]
get {
return owner.AccessibleObject;
}
}
protected DataGrid DataGrid {
get {
return owner.DataGrid;
}
}
public override AccessibleRole Role {
get {
return AccessibleRole.Link;
}
}
public override AccessibleStates State {
get {
DataGridRow[] dgRows = this.DataGrid.DataGridRows;
if (Array.IndexOf(dgRows, this.owner) == -1) {
return AccessibleStates.Unavailable;
}
AccessibleStates state = AccessibleStates.Selectable
| AccessibleStates.Focusable
| AccessibleStates.Linked;
if (!owner.Expanded) {
state |= AccessibleStates.Invisible;
}
if (DataGrid.Focused && Owner.dgTable.FocusedRelation == relationship) {
state |= AccessibleStates.Focused;
}
return state;
}
}
public override string Value {
get {
DataGridRow[] dgRows = this.DataGrid.DataGridRows;
if (Array.IndexOf(dgRows, this.owner) == -1) {
return null;
} else {
return (string)owner.dgTable.RelationsList[relationship];
}
}
set {
// not supported
}
}
public override string DefaultAction {
get {
return SR.GetString(SR.AccDGNavigate);
}
}
[SecurityPermission(SecurityAction.Demand, Flags = SecurityPermissionFlag.UnmanagedCode)]
public override void DoDefaultAction() {
((DataGridRelationshipRow)Owner).Expanded = true;
owner.FocusedRelation = -1;
DataGrid.NavigateTo((string)owner.dgTable.RelationsList[relationship], owner, true);
DataGrid.BeginInvoke(new MethodInvoker(this.ResetAccessibilityLayer));
}
private void ResetAccessibilityLayer() {
((DataGrid.DataGridAccessibleObject) DataGrid.AccessibilityObject).NotifyClients(AccessibleEvents.Reorder, 0);
((DataGrid.DataGridAccessibleObject) DataGrid.AccessibilityObject).NotifyClients(AccessibleEvents.Focus, DataGrid.CurrentCellAccIndex);
((DataGrid.DataGridAccessibleObject) DataGrid.AccessibilityObject).NotifyClients(AccessibleEvents.Selection, DataGrid.CurrentCellAccIndex);
}
/// <include file='doc\DataGridRelationshipRow.uex' path='docs/doc[@for="DataGridRelationshipRow.DataGridRelationshipAccessibleObject.Navigate"]/*' />
/// <devdoc>
/// Navigate to the next or previous grid entry.
/// </devdoc>
[SecurityPermission(SecurityAction.Demand, Flags = SecurityPermissionFlag.UnmanagedCode)]
public override AccessibleObject Navigate(AccessibleNavigation navdir) {
switch (navdir) {
case AccessibleNavigation.Right:
case AccessibleNavigation.Next:
case AccessibleNavigation.Down:
if (relationship + 1 < owner.dgTable.RelationsList.Count) {
return Parent.GetChild(Parent.GetChildCount() - owner.dgTable.RelationsList.Count + relationship + 1);
}
break;
case AccessibleNavigation.Up:
case AccessibleNavigation.Left:
case AccessibleNavigation.Previous:
if (relationship > 0) {
return Parent.GetChild(Parent.GetChildCount() - owner.dgTable.RelationsList.Count + relationship - 1);
}
break;
}
return null;
}
[SecurityPermission(SecurityAction.Demand, Flags = SecurityPermissionFlag.UnmanagedCode)]
public override void Select(AccessibleSelection flags) {
// Focus the PropertyGridView window
//
if ( (flags & AccessibleSelection.TakeFocus) == AccessibleSelection.TakeFocus) {
DataGrid.Focus();
}
if ( (flags & AccessibleSelection.TakeSelection) == AccessibleSelection.TakeSelection) {
Owner.FocusedRelation = relationship;
}
}
}
}
}
|