using System;
using System.ComponentModel;
using System.Windows.Forms;
using System.Drawing;
using System.Drawing.Drawing2D;
using FastReport.Table;
using FastReport.Data;
using FastReport.Utils;
using FastReport.Forms;
namespace FastReport.Matrix
{
internal enum MatrixElement
{
None,
Column,
Row,
Cell
}
partial class MatrixObject
{
#region Fields
internal TableCell selectedCell;
private bool dragSelectedCell;
internal DragInfo dragInfo;
#endregion
#region Properties
///
/// This property is not relevant to this class.
///
[Browsable(false)]
public override int ColumnCount
{
get { return base.ColumnCount; }
set { base.ColumnCount = value; }
}
///
/// This property is not relevant to this class.
///
[Browsable(false)]
public override int RowCount
{
get { return base.RowCount; }
set { base.RowCount = value; }
}
///
/// This property is not relevant to this class.
///
[Browsable(false)]
public new int FixedRows
{
get { return base.FixedRows; }
set { base.FixedRows = value; }
}
///
/// This property is not relevant to this class.
///
[Browsable(false)]
public new int FixedColumns
{
get { return base.FixedColumns; }
set { base.FixedColumns = value; }
}
///
/// This property is not relevant to this class.
///
[Browsable(false)]
public new bool CanBreak
{
get { return base.CanBreak; }
set { base.CanBreak = value; }
}
///
/// This property is not relevant to this class.
///
[Browsable(false)]
public new bool GrowToBottom
{
get { return base.GrowToBottom; }
set { base.GrowToBottom = value; }
}
private bool DragCellMode
{
get { return selectedCell != null && dragSelectedCell; }
}
#endregion
#region Private Methods
internal void RefreshTemplate(bool reset)
{
Helper.UpdateDescriptors();
for (int x = 0; x < Helper.BodyWidth; x++)
{
for (int y = 0; y < Helper.BodyHeight; y++)
{
TableCell cell = this[x + FixedColumns, y + FixedRows];
if (reset)
cell.Text = "";
else
cell.SetFlags(Flags.CanEdit, false);
}
}
MatrixElement element;
MatrixDescriptor descriptor;
bool isTotal;
for (int x = 0; x < ColumnCount; x++)
{
for (int y = 0; y < RowCount; y++)
{
TableCell cell = this[x, y];
GetMatrixElement(cell, out element, out descriptor, out isTotal);
bool enableSmartTag = descriptor != null && !isTotal;
cell.SetFlags(Flags.HasSmartTag, enableSmartTag);
}
}
}
internal void DrawSelectedCellFrame(FRPaintEventArgs e, TableCell cell)
{
Pen p = e.Cache.GetPen(Color.Black, 3, System.Drawing.Drawing2D.DashStyle.Solid);
e.Graphics.DrawRectangle(p, cell.AbsLeft * e.ScaleX, cell.AbsTop * e.ScaleY,
cell.Width * e.ScaleX, cell.Height * e.ScaleY);
}
internal void DrawDragIndicator(FRPaintEventArgs e)
{
dragInfo.targetCell.DrawDragAcceptFrame(e, Color.Red);
if (dragInfo.indicator.Width > 0 || dragInfo.indicator.Height > 0)
{
IGraphics g = e.Graphics;
int left = (int)Math.Round((dragInfo.indicator.Left + AbsLeft) * e.ScaleX);
int top = (int)Math.Round((dragInfo.indicator.Top + AbsTop) * e.ScaleY);
int right = (int)Math.Round(dragInfo.indicator.Width * e.ScaleX) + left;
int bottom = (int)Math.Round(dragInfo.indicator.Height * e.ScaleY) + top;
Pen p = e.Cache.GetPen(Color.Red, 1, DashStyle.Solid);
g.DrawLine(p, left, top, right, bottom);
p = Pens.Red;
Brush b = Brushes.Red;
if (dragInfo.indicator.Width == 0)
{
Point[] poly = new Point[] {
new Point(left, top),
new Point(left - 4, top - 4),
new Point(left + 4, top - 4),
new Point(left, top) };
g.FillPolygon(b, poly);
g.DrawPolygon(p, poly);
poly = new Point[] {
new Point(left, bottom),
new Point(left - 4, bottom + 4),
new Point(left + 4, bottom + 4),
new Point(left, bottom) };
g.FillPolygon(b, poly);
g.DrawPolygon(p, poly);
}
else
{
Point[] poly = new Point[] {
new Point(left, top),
new Point(left - 4, top - 4),
new Point(left - 4, top + 4),
new Point(left, top) };
g.FillPolygon(b, poly);
g.DrawPolygon(p, poly);
poly = new Point[] {
new Point(right, top),
new Point(right + 4, top - 4),
new Point(right + 4, top + 4),
new Point(right, top) };
g.FillPolygon(b, poly);
g.DrawPolygon(p, poly);
}
}
}
private void GetMatrixElement(TableCell cell, out MatrixElement element, out MatrixDescriptor descriptor,
out bool isTotal)
{
element = MatrixElement.None;
descriptor = null;
isTotal = false;
bool noColumns = Data.Columns.Count == 0;
bool noRows = Data.Rows.Count == 0;
bool noCells = Data.Cells.Count == 0;
// create temporary descriptors
if (noColumns)
Data.Columns.Add(new MatrixHeaderDescriptor("", false));
if (noRows)
Data.Rows.Add(new MatrixHeaderDescriptor("", false));
if (noCells)
Data.Cells.Add(new MatrixCellDescriptor());
Helper.UpdateDescriptors();
foreach (MatrixHeaderDescriptor descr in Data.Columns)
{
if (descr.TemplateCell == cell || descr.TemplateTotalCell == cell)
{
element = MatrixElement.Column;
if (!noColumns)
descriptor = descr;
isTotal = descr.TemplateTotalCell == cell;
}
}
foreach (MatrixHeaderDescriptor descr in Data.Rows)
{
if (descr.TemplateCell == cell || descr.TemplateTotalCell == cell)
{
element = MatrixElement.Row;
if (!noRows)
descriptor = descr;
isTotal = descr.TemplateTotalCell == cell;
}
}
foreach (MatrixCellDescriptor descr in Data.Cells)
{
if (descr.TemplateCell == cell)
{
element = MatrixElement.Cell;
if (!noCells)
descriptor = descr;
}
}
if (cell.Address.X >= FixedColumns && cell.Address.Y >= FixedRows)
element = MatrixElement.Cell;
if (noColumns)
Data.Columns.Clear();
if (noRows)
Data.Rows.Clear();
if (noCells)
Data.Cells.Clear();
}
#endregion
#region Protected Methods
///
protected override SelectionPoint[] GetSelectionPoints()
{
if (AutoSize)
return new SelectionPoint[] { new SelectionPoint(AbsLeft, AbsTop, SizingPoint.LeftTop) };
return base.GetSelectionPoints();
}
#endregion
#region Public Methods
///
public override void Draw(FRPaintEventArgs e)
{
if (IsDesigning && AutoSize)
{
AutoSize = true;
CalcHeight();
}
base.Draw(e);
if (selectedCell != null)
DrawSelectedCellFrame(e, selectedCell);
if (dragInfo.target != MatrixElement.None)
DrawDragIndicator(e);
if (!IsResultMatrix)
RefreshTemplate(false);
}
///
public override void SelectionChanged()
{
base.SelectionChanged();
this.selectedCell = null;
dragInfo.source = MatrixElement.None;
dragInfo.sourceDescriptor = null;
if (!IsSelected || Report.Designer.SelectedObjects.Count != 1)
return;
TableCell selectedCell = Report.Designer.SelectedObjects[0] as TableCell;
if (selectedCell == null)
return;
bool isTotal;
GetMatrixElement(selectedCell, out dragInfo.source, out dragInfo.sourceDescriptor, out isTotal);
if (dragInfo.sourceDescriptor == null || isTotal)
{
dragInfo.source = MatrixElement.None;
dragInfo.sourceDescriptor = null;
}
else
this.selectedCell = selectedCell;
}
///
public override void HandleMouseDown(FRMouseEventArgs e)
{
if (DragCellMode)
{
e.handled = true;
e.mode = WorkspaceMode2.Custom;
e.activeObject = this;
}
else
base.HandleMouseDown(e);
}
///
public override void HandleMouseMove(FRMouseEventArgs e)
{
if (DragCellMode && e.button == MouseButtons.Left)
{
e.DragSource = selectedCell;
HandleDragOver(e);
}
else
{
base.HandleMouseMove(e);
if (AutoSize && (MouseMode == MouseMode.ResizeColumn || MouseMode == MouseMode.ResizeRow))
{
MouseMode = MouseMode.None;
e.handled = false;
e.mode = WorkspaceMode2.None;
e.cursor = Cursors.Default;
}
if (selectedCell != null && e.button == MouseButtons.None)
{
PointF point = new PointF(e.x, e.y);
RectangleF innerRect = selectedCell.AbsBounds;
RectangleF outerRect = innerRect;
innerRect.Inflate(-3, -3);
outerRect.Inflate(3, 3);
dragSelectedCell = outerRect.Contains(point) && !innerRect.Contains(point);
if (dragSelectedCell)
{
e.handled = true;
e.cursor = Cursors.SizeAll;
}
}
}
}
///
public override void HandleMouseUp(FRMouseEventArgs e)
{
if (DragCellMode)
{
HandleDragDrop(e);
Report.Designer.SetModified(this, "Change");
selectedCell = null;
dragSelectedCell = false;
}
else
base.HandleMouseUp(e);
}
///
public override void HandleDragOver(FRMouseEventArgs e)
{
// matrix that is defined in the base report cannot be configured such way.
if (IsAncestor)
return;
dragInfo.target = MatrixElement.None;
dragInfo.indicator = Rectangle.Empty;
if (!(e.DragSource is TextObject))
return;
bool noColumns = Data.Columns.Count == 0;
bool noRows = Data.Rows.Count == 0;
bool noCells = Data.Cells.Count == 0;
// create temporary descriptors
if (noColumns)
Data.Columns.Add(new MatrixHeaderDescriptor("", false));
if (noRows)
Data.Rows.Add(new MatrixHeaderDescriptor("", false));
if (noCells)
Data.Cells.Add(new MatrixCellDescriptor());
Helper.UpdateDescriptors();
PointF point = new PointF(e.x, e.y);
// determine the location where to insert a new item: column, row or cell
foreach (MatrixHeaderDescriptor descr in Data.Columns)
{
TableCell cell = descr.TemplateCell;
if (cell != e.DragSource && cell.PointInObject(point))
{
dragInfo.target = MatrixElement.Column;
dragInfo.targetIndex = Data.Columns.IndexOf(descr) + 1;
dragInfo.targetCell = cell;
float top = cell.Bottom;
float width = cell.Width;
if (noColumns || point.Y < cell.AbsTop + cell.Height / 2)
{
if (descr.TemplateTotalCell != null)
width += descr.TemplateTotalCell.Width;
top = cell.Top;
dragInfo.targetIndex--;
}
dragInfo.indicator = new RectangleF(cell.Left, top, noColumns ? 0 : width, 0);
e.dragMessage = Res.Get("ComponentsMisc,Matrix,NewColumn");
}
}
foreach (MatrixHeaderDescriptor descr in Data.Rows)
{
TableCell cell = descr.TemplateCell;
if (cell != e.DragSource && cell.PointInObject(point))
{
dragInfo.target = MatrixElement.Row;
dragInfo.targetIndex = Data.Rows.IndexOf(descr) + 1;
dragInfo.targetCell = cell;
float left = cell.Right;
float height = cell.Height;
if (noRows || point.X < cell.AbsLeft + cell.Width / 2)
{
if (descr.TemplateTotalCell != null)
height += descr.TemplateTotalCell.Height;
left = cell.Left;
dragInfo.targetIndex--;
}
dragInfo.indicator = new RectangleF(left, cell.Top, 0, noRows ? 0 : height);
e.dragMessage = Res.Get("ComponentsMisc,Matrix,NewRow");
}
}
foreach (MatrixCellDescriptor descr in Data.Cells)
{
TableCell cell = descr.TemplateCell;
if (cell != e.DragSource && cell.PointInObject(point))
{
dragInfo.target = MatrixElement.Cell;
dragInfo.targetCell = cell;
bool preferLeftRight = Math.Min(point.X - cell.AbsLeft, cell.AbsRight - point.X) < 10;
if (Data.Cells.Count < 2 || CellsSideBySide)
{
dragInfo.targetIndex = Data.Cells.IndexOf(descr) + 1;
dragInfo.cellsSideBySide = true;
float left = cell.Right;
if (point.X < cell.AbsLeft + cell.Width / 2)
{
left = cell.Left;
dragInfo.targetIndex--;
}
dragInfo.indicator = new RectangleF(left, cell.Top, 0, cell.Height);
}
if ((Data.Cells.Count < 2 && !preferLeftRight) || (Data.Cells.Count >= 2 && !CellsSideBySide))
{
dragInfo.targetIndex = Data.Cells.IndexOf(descr) + 1;
dragInfo.cellsSideBySide = false;
float top = cell.Bottom;
if (point.Y < cell.AbsTop + cell.Height / 2)
{
top = cell.Top;
dragInfo.targetIndex--;
}
dragInfo.indicator = new RectangleF(cell.Left, top, cell.Width, 0);
}
if (noCells)
{
dragInfo.targetIndex = 0;
dragInfo.indicator = RectangleF.Empty;
}
e.dragMessage = Res.Get("ComponentsMisc,Matrix,NewCell");
}
}
if (noColumns)
Data.Columns.Clear();
if (noRows)
Data.Rows.Clear();
if (noCells)
Data.Cells.Clear();
e.handled = PointInObject(point);
}
///
public override void HandleDragDrop(FRMouseEventArgs e)
{
if (dragInfo.target != MatrixElement.None)
{
string draggedText = (e.DragSource as TextObject).Text;
MatrixDescriptor sourceDescr = dragInfo.sourceDescriptor;
MatrixDescriptor targetDescr = null;
// insert new item.
switch (dragInfo.target)
{
case MatrixElement.Column:
targetDescr = new MatrixHeaderDescriptor(draggedText);
if (sourceDescr != null)
targetDescr.Assign(sourceDescr);
if (dragInfo.source == MatrixElement.Cell)
targetDescr.TemplateCell = null;
Data.Columns.Insert(dragInfo.targetIndex, targetDescr as MatrixHeaderDescriptor);
break;
case MatrixElement.Row:
targetDescr = new MatrixHeaderDescriptor(draggedText);
if (sourceDescr != null)
targetDescr.Assign(sourceDescr);
if (dragInfo.source == MatrixElement.Cell)
targetDescr.TemplateCell = null;
Data.Rows.Insert(dragInfo.targetIndex, targetDescr as MatrixHeaderDescriptor);
break;
case MatrixElement.Cell:
targetDescr = new MatrixCellDescriptor(draggedText);
if (sourceDescr != null)
targetDescr.Assign(sourceDescr);
if (dragInfo.source != MatrixElement.Cell)
targetDescr.TemplateCell = null;
CellsSideBySide = dragInfo.cellsSideBySide;
Data.Cells.Insert(dragInfo.targetIndex, targetDescr as MatrixCellDescriptor);
break;
}
// remove source item
switch (dragInfo.source)
{
case MatrixElement.Column:
Data.Columns.Remove(sourceDescr as MatrixHeaderDescriptor);
break;
case MatrixElement.Row:
Data.Rows.Remove(sourceDescr as MatrixHeaderDescriptor);
break;
case MatrixElement.Cell:
Data.Cells.Remove(sourceDescr as MatrixCellDescriptor);
break;
}
if (DataSource == null)
{
if (draggedText.StartsWith("[") && draggedText.EndsWith("]"))
draggedText = draggedText.Substring(1, draggedText.Length - 2);
DataSource = DataHelper.GetDataSource(Report.Dictionary, draggedText);
}
Helper.BuildTemplate();
if (targetDescr != null)
{
Report.Designer.SelectedObjects.Clear();
Report.Designer.SelectedObjects.Add(targetDescr.TemplateCell);
}
}
dragInfo.target = MatrixElement.None;
dragInfo.source = MatrixElement.None;
}
///
public override void OnBeforeInsert(int flags)
{
BuildTemplate();
}
///
public override ContextMenuBase GetContextMenu()
{
return new MatrixObjectMenu(Report.Designer);
}
internal override ContextMenuBase GetCellContextMenu(TableCell cell)
{
if (Report.Designer.SelectedObjects.Count == 1)
{
MatrixElement element;
MatrixDescriptor descriptor;
bool isTotal;
GetMatrixElement(cell, out element, out descriptor, out isTotal);
switch (element)
{
case MatrixElement.Column:
case MatrixElement.Row:
if (isTotal)
return new MatrixTotalMenu(this, element, descriptor);
else if (descriptor != null)
return new MatrixHeaderMenu(this, element, descriptor);
break;
case MatrixElement.Cell:
if (descriptor != null)
return new MatrixCellMenu(this, element, descriptor);
break;
}
}
return new MatrixCellMenuBase(this, MatrixElement.None, null);
}
internal override SmartTagBase GetCellSmartTag(TableCell cell)
{
MatrixElement element;
MatrixDescriptor descriptor;
bool isTotal;
GetMatrixElement(cell, out element, out descriptor, out isTotal);
if (descriptor != null && !isTotal)
return new MatrixCellSmartTag(this, descriptor);
return null;
}
internal override void HandleCellDoubleClick(TableCell cell)
{
MatrixElement element;
MatrixDescriptor descriptor;
bool isTotal;
GetMatrixElement(cell, out element, out descriptor, out isTotal);
if (descriptor != null && !isTotal)
{
using (ExpressionEditorForm form = new ExpressionEditorForm(Report))
{
form.ExpressionText = descriptor.Expression;
if (form.ShowDialog() == DialogResult.OK)
{
descriptor.Expression = form.ExpressionText;
BuildTemplate();
Report.Designer.SetModified(cell, "Change");
}
}
}
else
{
if (cell.HasFlag(Flags.CanEdit) && !cell.HasRestriction(Restrictions.DontEdit) && cell.InvokeEditor())
Report.Designer.SetModified(cell, "Change");
}
}
///
public override void HandleKeyDown(Control sender, KeyEventArgs e)
{
bool myKey = false;
SelectedObjectCollection selection = Report.Designer.SelectedObjects;
if (!IsSelected || !(selection[0] is TableCell))
return;
TableCell cell = selection[0] as TableCell;
MatrixElement element;
MatrixDescriptor descriptor;
bool isTotal;
GetMatrixElement(cell, out element, out descriptor, out isTotal);
switch (e.KeyCode)
{
case Keys.Delete:
if (element != MatrixElement.None)
{
if (descriptor != null && !IsAncestor)
{
if (isTotal)
(descriptor as MatrixHeaderDescriptor).Totals = false;
else
{
switch (element)
{
case MatrixElement.Column:
Data.Columns.Remove(descriptor as MatrixHeaderDescriptor);
break;
case MatrixElement.Row:
Data.Rows.Remove(descriptor as MatrixHeaderDescriptor);
break;
case MatrixElement.Cell:
Data.Cells.Remove(descriptor as MatrixCellDescriptor);
break;
}
}
}
myKey = true;
}
break;
case Keys.Enter:
if (descriptor != null && !isTotal)
{
HandleCellDoubleClick(cell);
myKey = true;
}
break;
}
if (myKey)
{
e.Handled = true;
BuildTemplate();
Report.Designer.SetModified(this, "Change");
}
else
base.HandleKeyDown(sender, e);
}
#endregion
private void InitDesign()
{
dragInfo = new DragInfo();
}
internal class DragInfo
{
public MatrixElement source;
public MatrixElement target;
public MatrixDescriptor sourceDescriptor;
public int targetIndex;
public RectangleF indicator;
public bool cellsSideBySide;
public TableCell targetCell;
}
}
}