|
//------------------------------------------------------------------------------
// <copyright file="DataGridParentRows.cs" company="Microsoft">
// Copyright (c) Microsoft Corporation. All rights reserved.
// </copyright>
//------------------------------------------------------------------------------
namespace System.Windows.Forms {
using System.Text;
using System.Runtime.Remoting;
using System;
using System.Collections;
using System.Windows.Forms;
using System.Security.Permissions;
using System.ComponentModel;
using System.Drawing;
using System.Drawing.Imaging;
using Microsoft.Win32;
using System.Runtime.InteropServices;
using System.Diagnostics;
using System.Runtime.Versioning;
internal class DataGridParentRows {
// siting
//
private DataGrid dataGrid;
// ui
//
// private Color backColor = DataGrid.defaultParentRowsBackColor;
// private Color foreColor = DataGrid.defaultParentRowsForeColor;
private SolidBrush backBrush = DataGrid.DefaultParentRowsBackBrush;
private SolidBrush foreBrush = DataGrid.DefaultParentRowsForeBrush;
private int borderWidth = 1;
// private Color borderColor = SystemColors.WindowFrame;
private Brush borderBrush = new SolidBrush(SystemColors.WindowFrame);
private static Bitmap rightArrow = null;
private static Bitmap leftArrow = null;
private ColorMap[] colorMap = new ColorMap[] {new ColorMap()};
// private bool gridLineDots = false;
// private Color gridLineColor = SystemColors.Control;
// private Brush gridLineBrush = SystemBrushes.Control;
private Pen gridLinePen = SystemPens.Control;
private int totalHeight = 0;
private int textRegionHeight = 0;
// now that we have left and right arrows, we also have layout
private Layout layout = new Layout();
// mouse info
//
// private bool overLeftArrow = false;
// private bool overRightArrow = false;
private bool downLeftArrow = false;
private bool downRightArrow = false;
// a horizOffset of 0 means that the layout for the parent
// rows is left aligned.
// a horizOffset of 1 means that the leftmost unit of information ( let it be a
// table name, a column name or a column value ) is not visible.
// a horizOffset of 2 means that the leftmost 2 units of information are not visible, and so on
//
private int horizOffset = 0;
// storage for parent row states
//
private ArrayList parents = new ArrayList();
private int parentsCount = 0;
private ArrayList rowHeights = new ArrayList();
AccessibleObject accessibleObject;
internal DataGridParentRows(DataGrid dataGrid) {
this.colorMap[0].OldColor = Color.Black;
this.dataGrid = dataGrid;
// UpdateGridLinePen();
}
// =------------------------------------------------------------------
// = Properties
// =------------------------------------------------------------------
public AccessibleObject AccessibleObject {
get {
if (accessibleObject == null) {
accessibleObject = new DataGridParentRowsAccessibleObject(this);
}
return accessibleObject;
}
}
internal Color BackColor {
get {
return backBrush.Color;
}
set {
if (value.IsEmpty)
throw new ArgumentException(SR.GetString(SR.DataGridEmptyColor, "Parent Rows BackColor"));
if (value != backBrush.Color) {
backBrush = new SolidBrush(value);
Invalidate();
}
}
}
internal SolidBrush BackBrush {
get {
return backBrush;
}
set {
if (value != backBrush) {
CheckNull(value, "BackBrush");
backBrush = value;
Invalidate();
}
}
}
internal SolidBrush ForeBrush {
get {
return foreBrush;
}
set {
if (value != foreBrush) {
CheckNull(value, "BackBrush");
foreBrush = value;
Invalidate();
}
}
}
// since the layout of the parentRows is computed on every paint message,
// we can actually return true ClientRectangle coordinates
internal Rectangle GetBoundsForDataGridStateAccesibility(DataGridState dgs) {
Rectangle ret = Rectangle.Empty;
int rectY = 0;
for (int i = 0; i < parentsCount; i++) {
int height = (int) rowHeights[i];
if (parents[i] == dgs) {
ret.X = layout.leftArrow.IsEmpty ? layout.data.X : layout.leftArrow.Right;
ret.Height = height;
ret.Y = rectY;
ret.Width = layout.data.Width;
return ret;
}
rectY += height;
}
return ret;
}
/*
internal Color BorderColor {
get {
return borderColor;
}
set {
if (value != borderColor) {
borderColor = value;
Invalidate();
}
}
}
*/
internal Brush BorderBrush {
get {
return borderBrush;
}
set {
if (value != borderBrush) {
borderBrush = value;
Invalidate();
}
}
}
/*
internal Brush GridLineBrush {
get {
return gridLineBrush;
}
set {
if (value != gridLineBrush) {
gridLineBrush = value;
UpdateGridLinePen();
Invalidate();
}
}
}
internal bool GridLineDots {
get {
return gridLineDots;
}
set {
if (gridLineDots != value) {
gridLineDots = value;
UpdateGridLinePen();
Invalidate();
}
}
}
*/
internal int Height {
get {
return totalHeight;
}
}
internal Color ForeColor {
get {
return foreBrush.Color;
}
set {
if (value.IsEmpty)
throw new ArgumentException(SR.GetString(SR.DataGridEmptyColor, "Parent Rows ForeColor"));
if (value != foreBrush.Color) {
foreBrush = new SolidBrush(value);
Invalidate();
}
}
}
internal bool Visible {
get {
return dataGrid.ParentRowsVisible;
}
set {
dataGrid.ParentRowsVisible = value;
}
}
// =------------------------------------------------------------------
// = Methods
// =------------------------------------------------------------------
/// <include file='doc\DataGridParentRows.uex' path='docs/doc[@for="DataGridParentRows.AddParent"]/*' />
/// <devdoc>
/// Adds a DataGridState object to the top of the list of parents.
/// </devdoc>
internal void AddParent(DataGridState dgs) {
CurrencyManager childDataSource = (CurrencyManager) dataGrid.BindingContext[dgs.DataSource, dgs.DataMember];
parents.Add(dgs);
SetParentCount(parentsCount + 1);
Debug.Assert(GetTopParent() != null, "we should have a parent at least");
}
internal void Clear() {
for (int i = 0; i < parents.Count; i++) {
DataGridState dgs = parents[i] as DataGridState;
dgs.RemoveChangeNotification();
}
parents.Clear();
rowHeights.Clear();
totalHeight = 0;
SetParentCount(0);
}
internal void SetParentCount(int count) {
parentsCount = count;
dataGrid.Caption.BackButtonVisible = (parentsCount > 0) && (dataGrid.AllowNavigation);
}
internal void CheckNull(object value, string propName) {
if (value == null)
throw new ArgumentNullException("propName");
}
internal void Dispose() {
gridLinePen.Dispose();
}
/// <include file='doc\DataGridParentRows.uex' path='docs/doc[@for="DataGridParentRows.GetTopParent"]/*' />
/// <devdoc>
/// Retrieves the top most parent in the list of parents.
/// </devdoc>
internal DataGridState GetTopParent() {
if (parentsCount < 1) {
return null;
}
return(DataGridState)(((ICloneable)(parents[parentsCount-1])).Clone());
}
/// <include file='doc\DataGridParentRows.uex' path='docs/doc[@for="DataGridParentRows.IsEmpty"]/*' />
/// <devdoc>
/// Determines if there are any parent rows contained in this object.
/// </devdoc>
internal bool IsEmpty() {
return parentsCount == 0;
}
/// <include file='doc\DataGridParentRows.uex' path='docs/doc[@for="DataGridParentRows.PopTop"]/*' />
/// <devdoc>
/// Similar to GetTopParent() but also removes it.
/// </devdoc>
internal DataGridState PopTop() {
if (parentsCount < 1) {
return null;
}
SetParentCount(parentsCount - 1);
DataGridState ret = (DataGridState)parents[parentsCount];
ret.RemoveChangeNotification();
parents.RemoveAt(parentsCount);
return ret;
}
internal void Invalidate() {
if (dataGrid != null)
dataGrid.InvalidateParentRows();
}
internal void InvalidateRect(Rectangle rect)
{
if (dataGrid != null)
{
Rectangle r = new Rectangle(rect.X, rect.Y, rect.Width + borderWidth, rect.Height + borderWidth);
dataGrid.InvalidateParentRowsRect(r);
}
}
// called from DataGrid::OnLayout
internal void OnLayout() {
if (parentsCount == rowHeights.Count)
return;
int height = 0;
if (totalHeight == 0) {
totalHeight += 2 * borderWidth;
}
// figure out how tall each row's text will be
//
textRegionHeight = (int)dataGrid.Font.Height + 2;
// make the height of the Column.Font count for the height
// of the parentRows;
//
// if the user wants to programatically
// navigate to a relation in the constructor of the form
// ( ie, when the form does not process PerformLayout )
// the grid will receive an OnLayout message when there is more
// than one parent in the grid
if (parentsCount > rowHeights.Count) {
Debug.Assert(parentsCount == rowHeights.Count + 1 || rowHeights.Count == 0, "see bug 82808 for more info, or the comment above");
int rowHeightsCount = this.rowHeights.Count;
for (int i = rowHeightsCount; i < parentsCount; i++) {
DataGridState dgs = (DataGridState) parents[i];
GridColumnStylesCollection cols = dgs.GridColumnStyles;
int colsHeight = 0;
for (int j=0; j<cols.Count; j++) {
colsHeight = Math.Max(colsHeight, cols[j].GetMinimumHeight());
}
height = Math.Max(colsHeight, textRegionHeight);
// the height of the bottom border
height ++;
rowHeights.Add(height);
totalHeight += height;
}
} else {
Debug.Assert(parentsCount == rowHeights.Count - 1, "we do layout only for push/popTop");
if (parentsCount == 0)
totalHeight = 0;
else
totalHeight -= (int) rowHeights[rowHeights.Count-1];
rowHeights.RemoveAt(rowHeights.Count - 1);
}
}
private int CellCount() {
int cellCount = 0;
cellCount = ColsCount();
if (dataGrid.ParentRowsLabelStyle == DataGridParentRowsLabelStyle.TableName ||
dataGrid.ParentRowsLabelStyle == DataGridParentRowsLabelStyle.Both) {
cellCount ++;
}
return cellCount;
}
private void ResetMouseInfo()
{
// overLeftArrow = false;
// overRightArrow = false;
downLeftArrow = false;
downRightArrow = false;
}
private void LeftArrowClick(int cellCount) {
if (horizOffset > 0) {
ResetMouseInfo();
horizOffset -= 1;
Invalidate();
}
else
{
ResetMouseInfo();
InvalidateRect(layout.leftArrow);
}
}
private void RightArrowClick(int cellCount) {
if (horizOffset < cellCount - 1) {
ResetMouseInfo();
horizOffset += 1;
Invalidate();
}
else
{
ResetMouseInfo();
InvalidateRect(layout.rightArrow);
}
}
// the only mouse clicks that are handled are
// the mouse clicks on the LeftArrow and RightArrow
//
internal void OnMouseDown(int x, int y, bool alignToRight) {
if (layout.rightArrow.IsEmpty) {
Debug.Assert(layout.leftArrow.IsEmpty, "we can't have the leftArrow w/o the rightArrow");
return;
}
int cellCount = CellCount();
if (layout.rightArrow.Contains(x,y)) {
// draw a nice sunken border around the right arrow area
// we want to keep a cell on the screen
downRightArrow = true;
if (alignToRight)
LeftArrowClick(cellCount);
else
RightArrowClick(cellCount);
}
else if (layout.leftArrow.Contains(x,y)) {
downLeftArrow = true;
if (alignToRight)
RightArrowClick(cellCount);
else
LeftArrowClick(cellCount);
}
else
{
if (downLeftArrow)
{
downLeftArrow = false;
InvalidateRect(layout.leftArrow);
}
if (downRightArrow)
{
downRightArrow = false;
InvalidateRect(layout.rightArrow);
}
}
}
internal void OnMouseLeave() {
if (downLeftArrow)
{
downLeftArrow = false;
InvalidateRect(layout.leftArrow);
}
if (downRightArrow)
{
downRightArrow = false;
InvalidateRect(layout.rightArrow);
}
}
internal void OnMouseMove(int x, int y) {
/*
if (!layout.leftArrow.IsEmpty && layout.leftArrow.Contains(x,y))
{
ResetMouseInfo();
overLeftArrow = true;
InvalidateRect(layout.leftArrow);
return;
}
if (!layout.rightArrow.IsEmpty && layout.rightArrow.Contains(x,y))
{
ResetMouseInfo();
overRightArrow = true;
InvalidateRect(layout.rightArrow);
return;
}
*/
if (downLeftArrow)
{
downLeftArrow = false;
InvalidateRect(layout.leftArrow);
}
if (downRightArrow)
{
downRightArrow = false;
InvalidateRect(layout.rightArrow);
}
}
internal void OnMouseUp(int x, int y) {
ResetMouseInfo();
if (!layout.rightArrow.IsEmpty && layout.rightArrow.Contains(x,y))
{
InvalidateRect(layout.rightArrow);
return;
}
if (!layout.leftArrow.IsEmpty && layout.leftArrow.Contains(x,y))
{
InvalidateRect(layout.leftArrow);
return;
}
}
internal void OnResize(Rectangle oldBounds) {
Invalidate();
}
/// <include file='doc\DataGridParentRows.uex' path='docs/doc[@for="DataGridParentRows.Paint"]/*' />
/// <devdoc>
/// Paints the parent rows
/// </devdoc>
internal void Paint(Graphics g, Rectangle visualbounds, bool alignRight) {
Rectangle bounds = visualbounds;
// Paint the border around our bounds
if (borderWidth > 0) {
PaintBorder(g, bounds);
bounds.Inflate(-borderWidth, -borderWidth);
}
PaintParentRows(g, bounds, alignRight);
}
private void PaintBorder(Graphics g, Rectangle bounds) {
Rectangle border = bounds;
// top
border.Height = borderWidth;
g.FillRectangle(borderBrush, border);
// bottom
border.Y = bounds.Bottom - borderWidth;
g.FillRectangle(borderBrush, border);
// left
border = new Rectangle(bounds.X, bounds.Y + borderWidth,
borderWidth, bounds.Height - 2*borderWidth);
g.FillRectangle(borderBrush, border);
// right
border.X = bounds.Right - borderWidth;
g.FillRectangle(borderBrush, border);
}
// will return the width of the text box that will fit all the
// tables names
private int GetTableBoxWidth(Graphics g, Font font) {
// try to make the font BOLD
Font textFont = font;
try {
textFont = new Font(font, FontStyle.Bold);
}
catch {
}
int width = 0;
for (int row = 0; row < parentsCount; row ++) {
DataGridState dgs = (DataGridState) parents[row];
// Graphics.MeasureString(...) returns different results for ": " than for " :"
//
string displayTableName = dgs.ListManager.GetListName() + " :";
int size = (int) g.MeasureString(displayTableName, textFont).Width;
width = Math.Max(size, width);
}
return width;
}
// will return the width of the text box that will
// fit all the column names
private int GetColBoxWidth(Graphics g, Font font, int colNum) {
int width = 0;
for (int row = 0; row < parentsCount; row ++) {
DataGridState dgs = (DataGridState) parents[row];
GridColumnStylesCollection columns = dgs.GridColumnStyles;
if (colNum < columns.Count) {
// Graphics.MeasureString(...) returns different results for ": " than for " :"
//
string colName = columns[colNum].HeaderText + " :";
int size = (int) g.MeasureString(colName, font).Width;
width = Math.Max(size, width);
}
}
return width;
}
// will return the width of the best fit for the column
//
private int GetColDataBoxWidth(Graphics g, int colNum) {
int width = 0;
for (int row = 0; row < parentsCount; row ++) {
DataGridState dgs = (DataGridState) parents[row];
GridColumnStylesCollection columns = dgs.GridColumnStyles;
if (colNum < columns.Count) {
object value = columns[colNum].GetColumnValueAtRow((CurrencyManager) dataGrid.BindingContext[dgs.DataSource, dgs.DataMember],
dgs.LinkingRow.RowNumber);
int size = columns[colNum].GetPreferredSize(g, value).Width;
width = Math.Max(size, width);
}
}
return width;
}
// will return the count of the table with the largest number of columns
private int ColsCount() {
int colNum = 0;
for (int row = 0; row < parentsCount; row ++) {
DataGridState dgs = (DataGridState) parents[row];
colNum = Math.Max(colNum, dgs.GridColumnStyles.Count);
}
return colNum;
}
// will return the total width required to paint the parentRows
private int TotalWidth(int tableNameBoxWidth, int[] colsNameWidths, int[] colsDataWidths) {
int totalWidth = 0;
totalWidth += tableNameBoxWidth;
Debug.Assert(colsNameWidths.Length == colsDataWidths.Length, "both arrays are as long as the largest column count in dgs");
for (int i = 0; i < colsNameWidths.Length; i ++) {
totalWidth += colsNameWidths[i];
totalWidth += colsDataWidths[i];
}
// let 3 pixels in between datacolumns
// see DonnaWa
totalWidth += 3 * (colsNameWidths.Length - 1);
return totalWidth;
}
// computes the layout for the parent rows
//
private void ComputeLayout(Rectangle bounds, int tableNameBoxWidth, int[] colsNameWidths, int[] colsDataWidths) {
int totalWidth = TotalWidth(tableNameBoxWidth, colsNameWidths, colsDataWidths);
if (totalWidth > bounds.Width) {
layout.leftArrow = new Rectangle(bounds.X, bounds.Y, 15, bounds.Height);
layout.data = new Rectangle(layout.leftArrow.Right, bounds.Y, bounds.Width - 30, bounds.Height);
layout.rightArrow = new Rectangle(layout.data.Right, bounds.Y, 15, bounds.Height);
}
else {
layout.data = bounds;
layout.leftArrow = Rectangle.Empty;
layout.rightArrow = Rectangle.Empty;
}
}
private void PaintParentRows(Graphics g, Rectangle bounds, bool alignToRight) {
// variables needed for aligning the table and column names
int tableNameBoxWidth = 0;
int numCols = ColsCount();
int[] colsNameWidths = new int[numCols];
int[] colsDataWidths = new int[numCols];
// compute the size of the box that will contain the tableName
//
if (dataGrid.ParentRowsLabelStyle == DataGridParentRowsLabelStyle.TableName ||
dataGrid.ParentRowsLabelStyle == DataGridParentRowsLabelStyle.Both) {
tableNameBoxWidth = GetTableBoxWidth(g, dataGrid.Font);
}
// initialiaze the arrays that contain the column names and the column size
//
for (int i = 0; i < numCols; i++) {
if (dataGrid.ParentRowsLabelStyle == DataGridParentRowsLabelStyle.ColumnName ||
dataGrid.ParentRowsLabelStyle == DataGridParentRowsLabelStyle.Both) {
colsNameWidths[i] = GetColBoxWidth(g, dataGrid.Font, i);
}
else {
colsNameWidths[i] = 0;
}
colsDataWidths[i] = GetColDataBoxWidth(g, i);
}
// compute the layout
//
ComputeLayout(bounds, tableNameBoxWidth, colsNameWidths, colsDataWidths);
// paint the navigation arrows, if necessary
//
if (!layout.leftArrow.IsEmpty)
{
g.FillRectangle(BackBrush, layout.leftArrow);
PaintLeftArrow(g, layout.leftArrow, alignToRight);
}
// paint the parent rows:
//
Rectangle rowBounds = layout.data;
for (int row = 0; row < parentsCount; ++row) {
rowBounds.Height = (int) rowHeights[row];
if (rowBounds.Y > bounds.Bottom)
break;
int paintedWidth = PaintRow(g, rowBounds, row, dataGrid.Font, alignToRight, tableNameBoxWidth, colsNameWidths, colsDataWidths);
if (row == parentsCount-1)
break;
// draw the grid line below
g.DrawLine(gridLinePen, rowBounds.X, rowBounds.Bottom,
rowBounds.X + paintedWidth,
rowBounds.Bottom);
rowBounds.Y += rowBounds.Height;
}
if (!layout.rightArrow.IsEmpty)
{
g.FillRectangle(BackBrush, layout.rightArrow);
PaintRightArrow(g, layout.rightArrow, alignToRight);
}
}
[ResourceExposure(ResourceScope.Machine)]
[ResourceConsumption(ResourceScope.Machine, ResourceScope.Machine)]
private Bitmap GetBitmap(string bitmapName, Color transparentColor) {
Bitmap b = null;
try {
b = new Bitmap(typeof(DataGridParentRows), bitmapName);
b.MakeTransparent(transparentColor);
}
catch (Exception e) {
Debug.Fail("Failed to load bitmap: " + bitmapName, e.ToString());
}
return b;
}
[ResourceExposure(ResourceScope.Machine)]
[ResourceConsumption(ResourceScope.Machine)]
private Bitmap GetRightArrowBitmap()
{
if (rightArrow == null)
rightArrow = GetBitmap("DataGridParentRows.RightArrow.bmp", Color.White);
return rightArrow;
}
[ResourceExposure(ResourceScope.Machine)]
[ResourceConsumption(ResourceScope.Machine)]
private Bitmap GetLeftArrowBitmap()
{
if (leftArrow == null)
leftArrow = GetBitmap("DataGridParentRows.LeftArrow.bmp", Color.White);
return leftArrow;
}
private void PaintBitmap(Graphics g, Bitmap b, Rectangle bounds)
{
// center the bitmap in the bounds:
int bmpX = bounds.X + (bounds.Width - b.Width) / 2;
int bmpY = bounds.Y + (bounds.Height - b.Height) / 2;
Rectangle bmpRect = new Rectangle(bmpX, bmpY, b.Width, b.Height);
g.FillRectangle(BackBrush, bmpRect);
// now draw the bitmap
ImageAttributes attr = new ImageAttributes();
this.colorMap[0].NewColor = this.ForeColor;
attr.SetRemapTable(colorMap, ColorAdjustType.Bitmap);
g.DrawImage(b, bmpRect, 0, 0, bmpRect.Width, bmpRect.Height,GraphicsUnit.Pixel, attr);
attr.Dispose();
}
/*
private void PaintOverButton(Graphics g, Rectangle bounds)
{
}
*/
private void PaintDownButton(Graphics g, Rectangle bounds)
{
g.DrawLine(Pens.Black, bounds.X, bounds.Y, bounds.X + bounds.Width, bounds.Y); // the top
g.DrawLine(Pens.White, bounds.X + bounds.Width, bounds.Y, bounds.X + bounds.Width, bounds.Y + bounds.Height); // the right side
g.DrawLine(Pens.White, bounds.X + bounds.Width, bounds.Y + bounds.Height, bounds.X, bounds.Y + bounds.Height); // the right side
g.DrawLine(Pens.Black, bounds.X, bounds.Y + bounds.Height, bounds.X, bounds.Y); // the left side
}
private void PaintLeftArrow(Graphics g, Rectangle bounds, bool alignToRight)
{
Bitmap bmp = GetLeftArrowBitmap();
// paint the border around this bitmap if this is the case
//
/*
if (overLeftArrow)
{
Debug.Assert(!downLeftArrow, "can both of those happen?");
PaintOverButton(g, bounds);
layout.leftArrow.Inflate(-1,-1);
}
*/
if (downLeftArrow)
{
PaintDownButton(g, bounds);
layout.leftArrow.Inflate(-1,-1);
lock (bmp) {
PaintBitmap(g, bmp, bounds);
}
layout.leftArrow.Inflate(1,1);
}
else {
lock (bmp) {
PaintBitmap(g, bmp, bounds);
}
}
}
private void PaintRightArrow(Graphics g, Rectangle bounds, bool alignToRight)
{
Bitmap bmp = GetRightArrowBitmap();
// paint the border around this bitmap if this is the case
//
/*
if (overRightArrow)
{
Debug.Assert(!downRightArrow, "can both of those happen?");
PaintOverButton(g, bounds);
layout.rightArrow.Inflate(-1,-1);
}
*/
if (downRightArrow)
{
PaintDownButton(g, bounds);
layout.rightArrow.Inflate(-1,-1);
lock (bmp) {
PaintBitmap(g, bmp, bounds);
}
layout.rightArrow.Inflate(1,1);
}
else {
lock (bmp) {
PaintBitmap(g, bmp, bounds);
}
}
}
private int PaintRow(Graphics g, Rectangle bounds, int row, Font font, bool alignToRight,
int tableNameBoxWidth, int[] colsNameWidths, int[] colsDataWidths) {
DataGridState dgs = (DataGridState) parents[row];
Rectangle paintBounds = bounds;
Rectangle rowBounds = bounds;
paintBounds.Height = (int) rowHeights[row];
rowBounds.Height = (int) rowHeights[row];
int paintedWidth = 0;
// used for scrolling: when paiting, we will skip horizOffset cells in the dataGrid ParentRows
int skippedCells = 0;
// paint the table name
if ( dataGrid.ParentRowsLabelStyle == DataGridParentRowsLabelStyle.TableName ||
dataGrid.ParentRowsLabelStyle == DataGridParentRowsLabelStyle.Both) {
if (skippedCells < horizOffset) {
// skip this
skippedCells ++;
}
else {
paintBounds.Width = Math.Min(paintBounds.Width, tableNameBoxWidth);
paintBounds.X = MirrorRect(bounds, paintBounds, alignToRight);
string displayTableName = dgs.ListManager.GetListName() + ": ";
PaintText(g, paintBounds, displayTableName, font, true, alignToRight); // true is for painting bold
paintedWidth += paintBounds.Width;
}
}
if (paintedWidth >= bounds.Width)
return bounds.Width; // we painted everything
rowBounds.Width -= paintedWidth;
rowBounds.X += alignToRight ? 0 : paintedWidth;
paintedWidth += PaintColumns(g, rowBounds, dgs, font, alignToRight, colsNameWidths, colsDataWidths, skippedCells);
// paint the possible space left after columns
if (paintedWidth < bounds.Width) {
paintBounds.X = bounds.X + paintedWidth;
paintBounds.Width = bounds.Width - paintedWidth;
paintBounds.X = MirrorRect(bounds, paintBounds, alignToRight);
g.FillRectangle(BackBrush, paintBounds);
}
return paintedWidth;
}
private int PaintColumns(Graphics g, Rectangle bounds, DataGridState dgs, Font font, bool alignToRight,
int[] colsNameWidths, int[] colsDataWidths, int skippedCells) {
Rectangle paintBounds = bounds;
Rectangle rowBounds = bounds;
GridColumnStylesCollection cols = dgs.GridColumnStyles;
int cx = 0;
for (int i = 0; i < cols.Count; i ++) {
if (cx >= bounds.Width)
break;
// paint the column name, if we have to
if (dataGrid.ParentRowsLabelStyle == DataGridParentRowsLabelStyle.ColumnName ||
dataGrid.ParentRowsLabelStyle == DataGridParentRowsLabelStyle.Both) {
if (skippedCells < horizOffset) {
// skip this column
}
else {
paintBounds.X = bounds.X + cx;
paintBounds.Width = Math.Min(bounds.Width - cx, colsNameWidths[i]);
paintBounds.X = MirrorRect(bounds, paintBounds, alignToRight);
string colName = cols[i].HeaderText + ": ";
PaintText(g, paintBounds, colName, font, false, alignToRight); // false is for not painting bold
cx += paintBounds.Width;
}
}
if (cx >= bounds.Width)
break;
if (skippedCells < horizOffset) {
// skip this cell
skippedCells ++;
} else {
// paint the cell contents
paintBounds.X = bounds.X + cx;
paintBounds.Width = Math.Min(bounds.Width - cx, colsDataWidths[i]);
paintBounds.X = MirrorRect(bounds, paintBounds, alignToRight);
// when we paint the data grid parent rows, we want to paint the data at the position
// stored in the currency manager.
cols[i].Paint(g, paintBounds, (CurrencyManager) dataGrid.BindingContext[dgs.DataSource, dgs.DataMember],
dataGrid.BindingContext[dgs.DataSource, dgs.DataMember].Position, BackBrush, ForeBrush, alignToRight);
cx += paintBounds.Width;
// draw the line to the right (or left, according to alignRight)
//
g.DrawLine(new Pen(SystemColors.ControlDark),
alignToRight ? paintBounds.X : paintBounds.Right,
paintBounds.Y,
alignToRight ? paintBounds.X : paintBounds.Right,
paintBounds.Bottom);
// this is how wide the line is....
cx++;
// put 3 pixels in between columns
// see DonnaWa
//
if ( i < cols.Count - 1)
{
paintBounds.X = bounds.X + cx;
paintBounds.Width = Math.Min(bounds.Width - cx, 3);
paintBounds.X = MirrorRect(bounds, paintBounds, alignToRight);
g.FillRectangle(BackBrush, paintBounds);
cx += 3;
}
}
}
return cx;
}
/// <include file='doc\DataGridParentRows.uex' path='docs/doc[@for="DataGridParentRows.PaintText"]/*' />
/// <devdoc>
/// Draws on the screen the text. It is used only to paint the Table Name and the column Names
/// Returns the width of bounding rectangle that was passed in
/// </devdoc>
private int PaintText(Graphics g, Rectangle textBounds, string text, Font font, bool bold, bool alignToRight) {
Font textFont = font;
if (bold)
try {
textFont = new Font(font, FontStyle.Bold);
} catch {}
else
textFont = font;
// right now, we paint the entire box, cause it will be used anyway
g.FillRectangle(BackBrush, textBounds);
StringFormat format = new StringFormat();
if (alignToRight) {
format.FormatFlags |= StringFormatFlags.DirectionRightToLeft;
format.Alignment = StringAlignment.Far;
}
format.FormatFlags |= StringFormatFlags.NoWrap;
// part 1, section 3: put the table and the column name in the
// parent rows at the same height as the dataGridTextBoxColumn draws the string
//
textBounds.Offset(0, 2);
textBounds.Height -= 2;
g.DrawString(text, textFont, ForeBrush, textBounds, format);
format.Dispose();
return textBounds.Width;
}
// will return the X coordinate of the containedRect mirrored within the surroundingRect
// according to the value of alignToRight
private int MirrorRect(Rectangle surroundingRect, Rectangle containedRect, bool alignToRight) {
Debug.Assert(containedRect.X >= surroundingRect.X && containedRect.Right <= surroundingRect.Right, "containedRect is not contained in surroundingRect");
if (alignToRight)
return surroundingRect.Right - containedRect.Right + surroundingRect.X;
else
return containedRect.X;
}
private class Layout {
public Rectangle data;
public Rectangle leftArrow;
public Rectangle rightArrow;
public Layout() {
data = Rectangle.Empty;
leftArrow = Rectangle.Empty;
rightArrow = Rectangle.Empty;
}
public override string ToString() {
StringBuilder sb = new StringBuilder(200);
sb.Append("ParentRows Layout: \n");
sb.Append("data = ");
sb.Append(data.ToString());
sb.Append("\n leftArrow = ");
sb.Append(leftArrow.ToString());
sb.Append("\n rightArrow = ");
sb.Append(rightArrow.ToString());
sb.Append("\n");
return sb.ToString();
}
}
[ComVisible(true)]
protected internal class DataGridParentRowsAccessibleObject : AccessibleObject {
DataGridParentRows owner = null;
public DataGridParentRowsAccessibleObject(DataGridParentRows owner) : base() {
Debug.Assert(owner != null, "DataGridParentRowsAccessibleObject must have a valid owner");
this.owner = owner;
}
internal DataGridParentRows Owner {
get {
return owner;
}
}
public override Rectangle Bounds {
get {
return owner.dataGrid.RectangleToScreen(owner.dataGrid.ParentRowsBounds);
}
}
public override string DefaultAction {
get {
return SR.GetString(SR.AccDGNavigateBack);
}
}
public override string Name {
get {
return SR.GetString(SR.AccDGParentRows);
}
}
public override AccessibleObject Parent {
[SecurityPermission(SecurityAction.Demand, Flags = SecurityPermissionFlag.UnmanagedCode)]
get {
return owner.dataGrid.AccessibilityObject;
}
}
public override AccessibleRole Role {
get {
return AccessibleRole.List;
}
}
public override AccessibleStates State {
get {
AccessibleStates state = AccessibleStates.ReadOnly;
if (owner.parentsCount == 0) {
state |= AccessibleStates.Invisible;
}
if (owner.dataGrid.ParentRowsVisible) {
state |= AccessibleStates.Expanded;
}
else {
state |= AccessibleStates.Collapsed;
}
return state;
}
}
public override string Value {
[SecurityPermission(SecurityAction.Demand, Flags = SecurityPermissionFlag.UnmanagedCode)]
get {
return null;
}
}
[SecurityPermission(SecurityAction.Demand, Flags = SecurityPermissionFlag.UnmanagedCode)]
public override void DoDefaultAction() {
owner.dataGrid.NavigateBack();
}
public override AccessibleObject GetChild(int index) {
return ((DataGridState)owner.parents[index]).ParentRowAccessibleObject;
}
public override int GetChildCount() {
return owner.parentsCount;
}
/// <include file='doc\DataGridParentRows.uex' path='docs/doc[@for="DataGridParentRows.DataGridParentRowsAccessibleObject.GetFocused"]/*' />
/// <devdoc>
/// Returns the currently focused child, if any.
/// Returns this if the object itself is focused.
/// </devdoc>
public override AccessibleObject GetFocused() {
return null;
}
internal AccessibleObject GetNext(AccessibleObject child) {
int children = GetChildCount();
bool hit = false;
for (int i=0; i<children; i++) {
if (hit) {
return GetChild(i);
}
if (GetChild(i) == child) {
hit = true;
}
}
return null;
}
internal AccessibleObject GetPrev(AccessibleObject child) {
int children = GetChildCount();
bool hit = false;
for (int i=children-1; i>=0; i--) {
if (hit) {
return GetChild(i);
}
if (GetChild(i) == child) {
hit = true;
}
}
return null;
}
/// <include file='doc\DataGridParentRows.uex' path='docs/doc[@for="DataGridParentRows.DataGridParentRowsAccessibleObject.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:
return Parent.GetChild(1);
case AccessibleNavigation.Up:
case AccessibleNavigation.Left:
case AccessibleNavigation.Previous:
return Parent.GetChild(GetChildCount() - 1);
case AccessibleNavigation.FirstChild:
if (GetChildCount() > 0) {
return GetChild(0);
}
break;
case AccessibleNavigation.LastChild:
if (GetChildCount() > 0) {
return GetChild(GetChildCount() - 1);
}
break;
}
return null;
}
[SecurityPermission(SecurityAction.Demand, Flags = SecurityPermissionFlag.UnmanagedCode)]
public override void Select(AccessibleSelection flags) {
}
}
}
}
|