/* Copyright (c) Citrix Systems Inc. * All rights reserved. * * Redistribution and use in source and binary forms, * with or without modification, are permitted provided * that the following conditions are met: * * * Redistributions of source code must retain the above * copyright notice, this list of conditions and the * following disclaimer. * * Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the * following disclaimer in the documentation and/or other * materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ using System; using System.Collections.Generic; using System.Text; using System.Drawing; using System.Windows.Forms; namespace XenAdmin.Controls.CustomGridView { public class GridHeaderItem : GridStringItem { public const int ResizeGutter = 3; // the space between the columns within which we resize the columns rather than dragging them private static readonly Image AscendingTriangle = Properties.Resources.ascending_triangle; private static readonly Image DescendingTriangle = Properties.Resources.descending_triangle; private static readonly Font SortFont = new Font(Program.DefaultFont.FontFamily, 7.0f); private static readonly Pen LinePen = Pens.LightSteelBlue; public readonly int MinimumWidth; private readonly SortOrder defaultSortOrder; public SortOrder Sort = SortOrder.None; public int SortPriority = -1; public bool IsDefaultSortColumn; public bool GreyOut; public bool Immovable; public bool UnSizable; private int width; private String columnName; public GridHeaderItem(HorizontalAlignment hAlign, VerticalAlignment vAlign, Brush foreBrush, Font font, String text, SortOrder defaultSortOrder, int width, int minwidth, Brush hotbrush) : base(text, hAlign, vAlign, false, false, foreBrush, font, hotbrush, font) { this.defaultSortOrder = defaultSortOrder; this.width = width; MinimumWidth = minwidth; } public String ColumnName { get { return columnName; } set { columnName = value; } } public int Width { get { return width; } set { width = value; } } public override void OnPaint(ItemPaintArgs itemPaintArgs) { if (!string.IsNullOrEmpty(sortdata.ToString())) { base.OnPaint(itemPaintArgs); DrawGlyphs(itemPaintArgs); } } public void DrawGlyphs(ItemPaintArgs itemPaintArgs) { Graphics g = itemPaintArgs.Graphics; if (SortPriority > -1 && itemPaintArgs.Rectangle.Width - (AscendingTriangle.Width + 16) > 0) { // Draw the number showing the precedence of sorting in this column versus sorting in other columns g.DrawString((SortPriority + 1).ToString(), SortFont, foreBrush, itemPaintArgs.Rectangle.Right - (AscendingTriangle.Width + 15), itemPaintArgs.Rectangle.Top + ((itemPaintArgs.Rectangle.Height / 2) - 7)); } if (Sort != SortOrder.None && itemPaintArgs.Rectangle.Width - (AscendingTriangle.Width + 5) > 0) { // Draw the triangle showing ascending/descending sort order DrawTriangle(g, Sort == SortOrder.Ascending ? AscendingTriangle : DescendingTriangle, itemPaintArgs); } DrawSideLine(g, itemPaintArgs, itemPaintArgs.Rectangle.Left - 1); DrawSideLine(g, itemPaintArgs, itemPaintArgs.Rectangle.Right - 1); } private void DrawSideLine(Graphics g, ItemPaintArgs itemPaintArgs, int x) { g.DrawLine(LinePen, x, itemPaintArgs.Rectangle.Top, x, itemPaintArgs.Rectangle.Bottom - 1); } private void DrawTriangle(Graphics g, Image triangle, ItemPaintArgs itemPaintArgs) { g.DrawImageUnscaled(triangle, itemPaintArgs.Rectangle.Right - triangle.Width - 5, itemPaintArgs.Rectangle.Top + ((itemPaintArgs.Rectangle.Height - triangle.Height) / 2), triangle.Width, triangle.Height); } public override void OnEnter(Point p) { if (!Immovable && !string.IsNullOrEmpty(sortdata.ToString())) { Hot = true; Row.GridView.Refresh(); } } public override void OnMouseMove(Point p) { if ((!UnSizable && (p.X >= CurrentRectangle.Width - ResizeGutter && p.X <= CurrentRectangle.Width)) || (!PreviousUnsizable() && (p.X < ResizeGutter && p.X >= 0))) Row.Cursor = Cursors.SizeWE; else Row.Cursor = Cursors.Hand; } private bool PreviousUnsizable() { GridHeaderRow hr = (GridHeaderRow)Row; int tindex = hr.Columns.IndexOf(ColumnName); if (tindex <= 0) return true; string tother = hr.Columns[tindex - 1]; GridItemBase prevItem; if (!hr.Items.TryGetValue(tother, out prevItem)) return true; GridHeaderItem prevHeader = prevItem as GridHeaderItem; if (prevHeader == null) return true; return prevHeader.UnSizable; } public override void OnLeave() { if (!string.IsNullOrEmpty(sortdata.ToString())) { Row.Cursor = Cursors.Default; Hot = false; Row.GridView.Refresh(); } } public override void OnClick(Point p) { if (!string.IsNullOrEmpty(sortdata.ToString())) { NextSort(); Row.GridView.Sort(); Row.GridView.Refresh(); } } /// /// Changes the sort order of this column to the next value /// private void NextSort() { switch (Sort) { case SortOrder.None: SetSort(defaultSortOrder); break; case SortOrder.Ascending: SetSort(defaultSortOrder == SortOrder.Ascending ? SortOrder.Descending : SortOrder.None); break; case SortOrder.Descending: SetSort(defaultSortOrder == SortOrder.Ascending ? SortOrder.None : SortOrder.Ascending); break; } } private void SetSort(SortOrder sortOrder) { GridHeaderRow ghr = (GridHeaderRow)Row; int oldPriority = SortPriority; SortOrder oldSort = Sort; Sort = sortOrder; if (Sort == SortOrder.None) // removing sorting from this column { SortPriority = -1; foreach (GridHeaderItem other in ghr.Items.Values) { if (other != this && other.SortPriority > oldPriority) other.SortPriority--; } } else if (oldSort == SortOrder.None) // starting to apply sorting to this column { SortPriority = 0; foreach (GridHeaderItem other in ghr.Items.Values) { if (other != this && other.SortPriority > -1) other.SortPriority++; } } ghr.UpdateCompareOrder(); } // When using this function, it is the caller's responsibility to // make sure all the columns have a consistent set of priorities internal void SetSort(int priority, SortOrder sortOrder) { SortPriority = priority; Sort = sortOrder; } // When using this function, it is the caller's responsibility to // make sure all the columns have a consistent set of priorities internal void UnsetSort() { SortPriority = -1; Sort = SortOrder.None; } } }