Index: Core/Common/src/Core.Common.Controls.Swf/Core.Common.Controls.Swf.csproj =================================================================== diff -u -r8cae5d69ac2d4cf678486ac2b457c0dfe97089d5 -r46f5191a65faec434930a191e65f4c23d9ff8cfe --- Core/Common/src/Core.Common.Controls.Swf/Core.Common.Controls.Swf.csproj (.../Core.Common.Controls.Swf.csproj) (revision 8cae5d69ac2d4cf678486ac2b457c0dfe97089d5) +++ Core/Common/src/Core.Common.Controls.Swf/Core.Common.Controls.Swf.csproj (.../Core.Common.Controls.Swf.csproj) (revision 46f5191a65faec434930a191e65f4c23d9ff8cfe) @@ -65,26 +65,6 @@ AllRules.ruleset - - False - ..\..\..\..\lib\DevExpress.Data.v9.3.dll - - - False - ..\..\..\..\lib\DevExpress.Utils.v9.3.dll - - - False - ..\..\..\..\lib\DevExpress.XtraEditors.v9.3.dll - - - False - ..\..\..\..\lib\DevExpress.XtraGrid.v9.3.dll - - - False - ..\..\..\..\lib\DevExpress.XtraWizard.v9.3.dll - ..\..\..\..\packages\log4net.2.0.4\lib\net40-full\log4net.dll True @@ -103,10 +83,6 @@ - - False - ..\..\..\..\lib\TeeChart.dll - @@ -116,61 +92,21 @@ Component - - UserControl - - - - UserControl - UserControl FindAndReplaceControl.cs - - UserControl - - - ComboBoxTypeEditor.cs - Component - True True Resources.resx - - - - - - - - - UserControl - - - TableView.cs - - - - - - - - - - Form - - - WizardDialog.cs - @@ -185,14 +121,6 @@ Resources.Designer.cs Designer - - TableView.cs - Designer - - - WizardDialog.cs - Designer - @@ -230,18 +158,6 @@ - - - - - - - - - - - - False .NET Framework 3.5 SP1 Client Profile @@ -259,59 +175,11 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + + ..\Resources\PasteHS.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Resources\information.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Resources\folder.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Resources\edit_replace_all.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Resources\binocular.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Resources\drive.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Resources\computer.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Resources\table_edit.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Resources\page_white.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Resources\csv-export.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Resources\DeleteHS1.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + Transparantie moet tussen 0 en 100 liggen. + + + ..\Resources\csv-import.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Resources\edit-replace.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Resources\pin.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Resources\CopyHS.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Resources\cross.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Resources\tick.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Resources\funnel-small.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Resources\funnel--minus.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + Argument kan niet de waarde 'null' hebben. + + + Bestandsnaam moet een extensie hebben. + + + Argument bevat geen bestandsnaam. + + + Nieuwe tabel + + + Kopiëren + + + Plakken + + + Verwijderen + + + Gearceerde stijl wordt niet ondersteund voor exporteren en zal genegeerd worden. + + + Extensie ({0}) wordt niet ondersteund. + + + Invoerformaat wordt niet ondersteund. Y moet numeriek zijn maar is van type: {0}. + + + Ongeldig argument voor databron van gegevensreeks. Biedt u een IEnumerable aan? IList en IListSource worden ondersteund. + + + Dit programma accepteert alleen {0} als gegevensreeks. + + + Geen cursor toegewezen aan {0}. + + + Verschil: +horizontaal: {0} +verticaal: {1} + + + seconden + + + Actie {0} wordt niet ondersteund door de TableView. + + + Ongebonden kolommen van type {0} worden niet ondersteund. + + + Ongeldig rijnummer {0}. + + + Weet u zeker dat u het volgende element wilt verwijderen: {0} + + + Kan INodePresenter voor {0} niet vinden. Zorg ervoor dat u de ontbrekende INodePresenter aan de NodePresenters eigenschap van een TreeView heeft toegevoegd. + + + Kan diagram niet tekenen. + + + Aantal X-waarden moet gelijk zijn aan het aantal Y-waarden. + + + Zou geen indices lager dan -1 moeten teruggeven! + + + Geselecteerde index is buiten bereik van de gevensreeks. + + + 'LastSelectedSeries' moet gezet zijn voordat 'SelectedPointIndex' wordt gezet. + + + Onbekende TeeChart gegevensreeks: houdt geen verband met een bekende ChartSeries. + + + Verwijderen is niet geïmplementeerd voor dit type databron. + + + X-waarde wordt vastgelegd (linker limiet) {0} => {1}. + + + X-waarde wordt vastgelegd (rechter limiet) {0} => {1}. + + + Niet te klonen subelementen in menu-element. + + + De eigenschap 'DockStyle' van de inklapbare splitser kan geen waarde 'Filled' of 'None' hebben. + + + Er is een kritieke fout opgetreden. Ringtoets moet herstart worden. + + + {0} tot {1} + + + Er is een fout opgetreden. Verifieer de invoer alstublieft. - The primary goals of this format is to allow a simple XML format - that is mostly human readable. The generation and parsing of the - various data types are done through the TypeConverter classes - associated with the data types. +Fout: +{0} + + + Fout opgetreden + + + OnNodeRenamed moet zijn geïmplementeerd in de afgeleide klasse. + + + Structuurweergave mag niet leeg zijn. + + + Fout tijdens slepen/neerzetten: {0}. + + + Het geselecteerde element kan niet worden verwijderd. + + + De methode of operatie is niet geïmplementeerd. + + + Datumtijd notatie niet zoals verwacht. + + + Validatie van cel is mislukt: {0}. + + + Validatie van rij is mislukt: {0}. + + + Ongeldige rij: {0}. + + + Plakken waarden mislukt: {0}. + + + Ongeldig geplakte rij {0} wordt overgeslagen. + + + Kan de waarde in cel [{0}, {1}] niet plakken. Rij {0} wordt overgeslagen. + + + Kan niet plakken in een gefilterde tableview. + + + Kan niet plakken in gesorteerde kolom. + + + Er zijn geen waardes om te plakken (kopteksten worden overgeslagen). + + + Kan alleen in rechthoekige selectie plakken. + + + Klembord bevat geen tekst. Hierdoor kan het niet in de tabel worden geplakt. + + + Wilt u de waarde corrigeren? - Example: - - ... ado.net/XML headers & schema ... - text/microsoft-resx - 1.3 - System.Resources.ResXResourceReader, System.Windows.Forms, ... - System.Resources.ResXResourceWriter, System.Windows.Forms, ... - this is my long string - Blue - - [base64 mime encoded serialized .NET Framework object] - - - [base64 mime encoded string representing a byte array form of the .NET Framework object] - - - There are any number of "resheader" rows that contain simple - name/value pairs. - - Each data row contains a name, and value. The row also contains a - type or mimetype. Type corresponds to a .NET class that support - text/value conversion through the TypeConverter architecture. - Classes that don't support this are serialized and stored with the - mimetype set. - - The mimetype is used for serialized objects, and tells the - ResXResourceReader how to depersist the object. This is currently not - extensible. For a given mimetype the value must be set accordingly: - - Note - application/x-microsoft.net.object.binary.base64 is the format - that the ResXResourceWriter will generate, however the reader can - read any of the formats listed below. - - mimetype: application/x-microsoft.net.object.binary.base64 - value : The object must be serialized with - : System.Serialization.Formatters.Binary.BinaryFormatter - : and then encoded with base64 encoding. - - mimetype: application/x-microsoft.net.object.soap.base64 - value : The object must be serialized with - : System.Runtime.Serialization.Formatters.Soap.SoapFormatter - : and then encoded with base64 encoding. - - mimetype: application/x-microsoft.net.object.bytearray.base64 - value : The object must be serialized into a byte array - : using a System.ComponentModel.TypeConverter - : and then encoded with base64 encoding. - --> - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - text/microsoft-resx - - - 1.3 - - - System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.3500.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.3500.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - +Kies Ja om de waarde zelf te corrigeren. Kies Nee als u de oorspronkelijke waarde wilt terugkrijgen. + + + <aangepast> + + + Het is niet toegestaan om rijen aan deze tabel toe te voegen. + + + Niet in staat om cellen te selecteren wanneer tableView RowSelect ingeschakeld is. Gebruik in plaats daarvan SelectRow. + + + Kan tekenreeks {0} niet omzetten naar {1} om te plakken. + + + Kan waarde in cel [{0}, {1}] niet instellen. Reden: {2}. + + + Kan waarde voor rij {0} niet instellen. Reden: {1}. + + + Kopiëer alle kopteksten + + + Maak kolom los + + + Pin kolom vast + + + SelectionChanged event afgevuurd. + + + {0} exemplaren van {1} zijn met {2} vervangen. + + + Er is geen tekst om te zoeken. + + + Einde van document is bereikt. + + + Mijn Computer + + + Een optionele randstijl om te tekenen. Zet de waarde op 'Flat' om geen rand te tekenen. + + + Geen conversie van het type 'string' mogelijk. + + + Niet in staat om een presentatieobject te vinden voor niet geïnitialiseerd object. + + + Knoop moet opgegeven zijn om diens toestand op te kunnen nemen. + + + Knoop data moet aanwezig zijn om de toestand van diens knoop op te kunnen nemen. + + + Knoop heeft niet dezelfde data als de opgenomen knoop. + + + tot + \ No newline at end of file Index: Core/Common/src/Core.Common.Controls.Table/Resources/CopyHS.png =================================================================== diff -u Binary files differ Index: Core/Common/src/Core.Common.Controls.Table/Resources/DeleteHS1.png =================================================================== diff -u Binary files differ Index: Core/Common/src/Core.Common.Controls.Table/Resources/PasteHS.png =================================================================== diff -u Binary files differ Index: Core/Common/src/Core.Common.Controls.Table/Resources/binocular.png =================================================================== diff -u Binary files differ Index: Core/Common/src/Core.Common.Controls.Table/Resources/computer.png =================================================================== diff -u Binary files differ Index: Core/Common/src/Core.Common.Controls.Table/Resources/cross.png =================================================================== diff -u Binary files differ Index: Core/Common/src/Core.Common.Controls.Table/Resources/csv-export.png =================================================================== diff -u Binary files differ Index: Core/Common/src/Core.Common.Controls.Table/Resources/csv-import.png =================================================================== diff -u Binary files differ Index: Core/Common/src/Core.Common.Controls.Table/Resources/down.bmp =================================================================== diff -u Binary files differ Index: Core/Common/src/Core.Common.Controls.Table/Resources/down1.bmp =================================================================== diff -u Binary files differ Index: Core/Common/src/Core.Common.Controls.Table/Resources/drive.png =================================================================== diff -u Binary files differ Index: Core/Common/src/Core.Common.Controls.Table/Resources/edit-replace.png =================================================================== diff -u Binary files differ Index: Core/Common/src/Core.Common.Controls.Table/Resources/edit_replace_all.png =================================================================== diff -u Binary files differ Index: Core/Common/src/Core.Common.Controls.Table/Resources/folder.png =================================================================== diff -u Binary files differ Index: Core/Common/src/Core.Common.Controls.Table/Resources/funnel--minus.png =================================================================== diff -u Binary files differ Index: Core/Common/src/Core.Common.Controls.Table/Resources/funnel-small.png =================================================================== diff -u Binary files differ Index: Core/Common/src/Core.Common.Controls.Table/Resources/information.png =================================================================== diff -u Binary files differ Index: Core/Common/src/Core.Common.Controls.Table/Resources/page_white.png =================================================================== diff -u Binary files differ Index: Core/Common/src/Core.Common.Controls.Table/Resources/pin.png =================================================================== diff -u Binary files differ Index: Core/Common/src/Core.Common.Controls.Table/Resources/table_edit.png =================================================================== diff -u Binary files differ Index: Core/Common/src/Core.Common.Controls.Table/Resources/tick.png =================================================================== diff -u Binary files differ Index: Core/Common/src/Core.Common.Controls.Table/Resources/up.bmp =================================================================== diff -u Binary files differ Index: Core/Common/src/Core.Common.Controls.Table/TableSelectionChangedEventArgs.cs =================================================================== diff -u --- Core/Common/src/Core.Common.Controls.Table/TableSelectionChangedEventArgs.cs (revision 0) +++ Core/Common/src/Core.Common.Controls.Table/TableSelectionChangedEventArgs.cs (revision 46f5191a65faec434930a191e65f4c23d9ff8cfe) @@ -0,0 +1,18 @@ +using System; +using System.Collections.Generic; + +namespace Core.Common.Controls.Table +{ + public class TableSelectionChangedEventArgs : EventArgs + { + /// + /// Selection Changed EventArgs + /// + public TableSelectionChangedEventArgs(IList cells) + { + Cells = cells; + } + + public IList Cells { get; private set; } + } +} \ No newline at end of file Index: Core/Common/src/Core.Common.Controls.Table/TableView.Designer.cs =================================================================== diff -u --- Core/Common/src/Core.Common.Controls.Table/TableView.Designer.cs (revision 0) +++ Core/Common/src/Core.Common.Controls.Table/TableView.Designer.cs (revision 46f5191a65faec434930a191e65f4c23d9ff8cfe) @@ -0,0 +1,93 @@ +namespace Core.Common.Controls.Table +{ + partial class TableView + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + #region Component Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.dxGridControl = new DevExpress.XtraGrid.GridControl(); + this.dxGridView = new DevExpress.XtraGrid.Views.Grid.GridView(); + this.repositoryItemTimeEdit1 = new DevExpress.XtraEditors.Repository.RepositoryItemTimeEdit(); + ((System.ComponentModel.ISupportInitialize)(this.dxGridControl)).BeginInit(); + ((System.ComponentModel.ISupportInitialize)(this.dxGridView)).BeginInit(); + ((System.ComponentModel.ISupportInitialize)(this.repositoryItemTimeEdit1)).BeginInit(); + this.SuspendLayout(); + // + // dxGridControl + // + this.dxGridControl.AllowRestoreSelectionAndFocusedRow = DevExpress.Utils.DefaultBoolean.True; + this.dxGridControl.Dock = System.Windows.Forms.DockStyle.Fill; + this.dxGridControl.Location = new System.Drawing.Point(0, 0); + this.dxGridControl.LookAndFeel.SkinName = "Blue"; + this.dxGridControl.LookAndFeel.Style = DevExpress.LookAndFeel.LookAndFeelStyle.Office2003; + this.dxGridControl.LookAndFeel.UseDefaultLookAndFeel = false; + this.dxGridControl.MainView = this.dxGridView; + this.dxGridControl.Name = "dxGridControl"; + this.dxGridControl.RepositoryItems.AddRange(new DevExpress.XtraEditors.Repository.RepositoryItem[] { + this.repositoryItemTimeEdit1}); + this.dxGridControl.Size = new System.Drawing.Size(564, 408); + this.dxGridControl.TabIndex = 3; + this.dxGridControl.UseEmbeddedNavigator = true; + this.dxGridControl.ViewCollection.AddRange(new DevExpress.XtraGrid.Views.Base.BaseView[] { + this.dxGridView}); + // + // dxGridView + // + this.dxGridView.GridControl = this.dxGridControl; + this.dxGridView.Name = "dxGridView"; + this.dxGridView.OptionsCustomization.AllowColumnMoving = false; + this.dxGridView.OptionsCustomization.AllowGroup = false; + this.dxGridView.OptionsDetail.EnableDetailToolTip = true; + this.dxGridView.OptionsSelection.MultiSelect = true; + this.dxGridView.OptionsSelection.MultiSelectMode = DevExpress.XtraGrid.Views.Grid.GridMultiSelectMode.CellSelect; + this.dxGridView.OptionsView.ColumnAutoWidth = false; + this.dxGridView.OptionsView.NewItemRowPosition = DevExpress.XtraGrid.Views.Grid.NewItemRowPosition.Bottom; + this.dxGridView.OptionsView.ShowFooter = true; + this.dxGridView.OptionsView.ShowGroupPanel = false; + this.dxGridView.PaintStyleName = "Flat"; + // + // repositoryItemTimeEdit1 + // + this.repositoryItemTimeEdit1.AutoHeight = false; + this.repositoryItemTimeEdit1.Buttons.AddRange(new DevExpress.XtraEditors.Controls.EditorButton[] { + new DevExpress.XtraEditors.Controls.EditorButton()}); + this.repositoryItemTimeEdit1.DisplayFormat.FormatString = "yyyy-MM-dd HH:mm:ss"; + this.repositoryItemTimeEdit1.DisplayFormat.FormatType = DevExpress.Utils.FormatType.Custom; + this.repositoryItemTimeEdit1.EditFormat.FormatString = "yyyy-MM-dd HH:mm:ss"; + this.repositoryItemTimeEdit1.EditFormat.FormatType = DevExpress.Utils.FormatType.Custom; + this.repositoryItemTimeEdit1.EditValueChangedFiringMode = DevExpress.XtraEditors.Controls.EditValueChangedFiringMode.Default; + this.repositoryItemTimeEdit1.Mask.EditMask = "yyyy-MM-dd HH:mm:ss"; + this.repositoryItemTimeEdit1.Name = "repositoryItemTimeEdit1"; + this.repositoryItemTimeEdit1.ValidateOnEnterKey = true; + // + // TableView + // + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.Controls.Add(this.dxGridControl); + this.Name = "TableView"; + this.Size = new System.Drawing.Size(564, 408); + ((System.ComponentModel.ISupportInitialize)(this.dxGridControl)).EndInit(); + ((System.ComponentModel.ISupportInitialize)(this.dxGridView)).EndInit(); + ((System.ComponentModel.ISupportInitialize)(this.repositoryItemTimeEdit1)).EndInit(); + this.ResumeLayout(false); + + } + + #endregion + + private DevExpress.XtraEditors.Repository.RepositoryItemTimeEdit repositoryItemTimeEdit1; + private DevExpress.XtraGrid.GridControl dxGridControl; + private DevExpress.XtraGrid.Views.Grid.GridView dxGridView; + } +} \ No newline at end of file Index: Core/Common/src/Core.Common.Controls.Table/TableView.cs =================================================================== diff -u --- Core/Common/src/Core.Common.Controls.Table/TableView.cs (revision 0) +++ Core/Common/src/Core.Common.Controls.Table/TableView.cs (revision 46f5191a65faec434930a191e65f4c23d9ff8cfe) @@ -0,0 +1,2521 @@ +using System; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.ComponentModel; +using System.Data; +using System.Drawing; +using System.Globalization; +using System.IO; +using System.Linq; +using System.Text; +using System.Windows.Forms; +using Core.Common.Controls.Table.Properties; +using Core.Common.Controls.Table.Editors; +using Core.Common.Controls.Table.Validation; +using Core.Common.Controls.Views; +using Core.Common.Utils.Events; +using Core.Common.Utils.Extensions; +using Core.Common.Utils.Reflection; +using DevExpress.Data; +using DevExpress.Utils; +using DevExpress.Utils.Drawing; +using DevExpress.Utils.Menu; +using DevExpress.XtraEditors; +using DevExpress.XtraEditors.Repository; +using DevExpress.XtraEditors.ViewInfo; +using DevExpress.XtraGrid; +using DevExpress.XtraGrid.Columns; +using DevExpress.XtraGrid.Localization; +using DevExpress.XtraGrid.Views.Base; +using DevExpress.XtraGrid.Views.Grid; +using DevExpress.XtraGrid.Views.Grid.ViewInfo; +using log4net; +using TypeConverter = Core.Common.Utils.TypeConverter; + +namespace Core.Common.Controls.Table +{ + /// + /// Graphical representation of tabular data. + /// + public partial class TableView : UserControl, IView, ISupportInitialize + { + public enum ValidationExceptionMode + { + Ignore, + NoAction, + DisplayError, + ThrowException + } + + private static readonly ILog Log = LogManager.GetLogger(typeof(TableView)); + private readonly ICollection selectedCells; + private readonly TableViewValidator tableViewValidator; + private readonly List columns; + private bool isPasting; + private bool isSelectionChanging; + private bool updatingSelection; + private bool showRowNumbers; + private bool autoGenerateColumns; + private bool refreshRequired; + private bool allowColumnSorting = true; + private bool f2Pressed; + private Timer refreshTimer; + private BindingSource bindingSource; + private GridCell[] cellsToFill; + + public TableView() + { + InitializeComponent(); + + columns = new List(); + ColumnMenuItems = new List(); + selectedCells = new HashSet(); + tableViewValidator = new TableViewValidator(this); + PasteController = new TableViewPasteController(this) + { + PasteBehaviour = TableViewPasteBehaviourOptions.SkipCellWhenValueIsInvalid + }; + + AllowColumnPinning = true; + AllowDeleteRow = true; + AutoGenerateColumns = true; + MultipleCellEdit = true; + dxGridView.OptionsView.ShowFooter = false; + dxGridView.OptionsBehavior.CopyToClipboardWithColumnHeaders = false; //mimic behavior of 8.2 + GridLocalizer.Active = new TableViewExceptionMessageController(); + + Text = Resources.TableView_TableView_new_Table; + + ReadOnlyCellForeColor = Color.Black; //just use black as a default to increase readability + ReadOnlyCellBackColor = Color.FromArgb(255, 244, 244, 244); + InvalidCellBackgroundColor = Color.Tomato; + ExceptionMode = ValidationExceptionMode.DisplayError; + ConfigureContextMenu(); + SubscribeEvents(); + CreateRefreshTimer(); + } + + public void ExportAsCsv(string fileName, string delimiter = ", ") + { + // the build-in export to file method depends on a devexpress dll we haven't included so far + using (var writer = new StreamWriter(fileName)) + { + var visibleColumns = columns.Where(c => c.Visible).OrderBy(c => c.DisplayIndex); + var lastColumn = visibleColumns.Last(); + + foreach (var visibleColumn in visibleColumns) + { + writer.Write(visibleColumn.Caption); + if (visibleColumn != lastColumn) + { + writer.Write(delimiter); + } + } + + writer.WriteLine(); + + var shownColumns = visibleColumns.Select(c => c.AbsoluteIndex).ToArray(); + + //writing the data + for (int x = 0; x < RowCount; x++) + { + for (int y = 0; y < shownColumns.Length; y++) + { + writer.Write(GetCellDisplayText(x, shownColumns[y])); + if (y != columns.Count - 1) + { + writer.Write(delimiter); + } + } + writer.WriteLine(); + } + writer.Close(); + } + } + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + UnSubscribeFromDataSource(); + + if (refreshTimer != null) + { + refreshTimer.Stop(); + refreshTimer.Tick -= OnRefreshTimerOnTick; + refreshTimer.Dispose(); + refreshTimer = null; + } + + if (disposing) + { + //only dispose if disposing managed resource (otherwise called from other thread) + // prevents memory leaks + foreach (var view in dxGridControl.Views.Cast().ToList()) + { + view.Dispose(); + } + dxGridControl.Dispose(); + } + + if (columns != null) + { + foreach (var column in columns) + { + column.Dispose(); + } + } + + if (disposing && (components != null)) + { + components.Dispose(); + } + + try + { + /* + Localize bug in XtraEditors: + + System.InvalidOperationException : Value Dispose() cannot be called while doing CreateHandle(). + at System.Windows.Forms.Control.Dispose(Boolean disposing) + at DevExpress.XtraEditors.ScrollBarBase.Dispose(Boolean disposing) + at System.ComponentModel.Component.Dispose() + at DevExpress.XtraGrid.Scrolling.ScrollInfo.Dispose() + at DevExpress.XtraGrid.Views.Grid.GridView.Dispose(Boolean disposing) + at System.ComponentModel.Component.Dispose() + at DevExpress.XtraGrid.GridControl.RemoveView(BaseView gv, Boolean disposeView) + at DevExpress.XtraGrid.GridControl.RemoveView(BaseView gv) + at DevExpress.XtraGrid.GridControl.Dispose(Boolean disposing) + at System.ComponentModel.Component.Dispose() + at System.Windows.Forms.Control.Dispose(Boolean disposing) + at System.Windows.Forms.ContainerControl.Dispose(Boolean disposing) + at Core.Common.Controls.Swf.Table.TableView.Dispose(Boolean disposing) in TableView.Designer.cs: line 22 + */ + base.Dispose(disposing); + } + catch (InvalidOperationException e) + { + Log.Debug("Strange bug in XtraGrid control, from time to time crashes", e); + } + } + + /// + /// Converts value pasted from clipboard, currently always a string, to a value of the type + /// required by the underlying datasource. + /// In addition to default conversion for e.g string to int by + /// TypeConverter.ConvertValueToTargetType + /// There is added support for the RepositoryItemImageComboBox where the description (will default be + /// copied to clipboard) will be converted to value. + /// - NB the base class RepositoryItemComboBox does not have items with value and description + /// + /// + /// + /// + internal object ConvertStringValueToDataValue(int columnIndex, string cellValue) + { + object value = null; + RepositoryItem editor = dxGridView.Columns[columnIndex].ColumnEdit; + Type columnType = dxGridView.Columns[columnIndex].ColumnType; + if (null != editor) + { + var imageComboBoxEditor = editor as RepositoryItemImageComboBox; + if (imageComboBoxEditor != null) + { + var repositoryItemImageComboBox = imageComboBoxEditor; + var map = new Dictionary(); + for (int j = 0; j < repositoryItemImageComboBox.Items.Count; j++) + { + map[repositoryItemImageComboBox.Items[j].Description] = + repositoryItemImageComboBox.Items[j].Value; + } + if (map.ContainsKey(cellValue)) + { + value = map[cellValue]; + } + } + else if (editor is RepositoryItemComboBox || editor is RepositoryItemLookUpEdit) + { + var valueLookUp = new Dictionary(); + + var comboBoxEditor = editor as RepositoryItemComboBox; + if (comboBoxEditor != null) + { + var repositoryItemComboBox = comboBoxEditor; + valueLookUp = repositoryItemComboBox.Items.OfType().ToDictionary(i => i.DisplayText, i => i.Value); + } + else + { + var lookUpEdit = (RepositoryItemLookUpEdit) editor; + var comboBoxItems = lookUpEdit.DataSource as IEnumerable; + if (comboBoxItems != null) + { + valueLookUp = comboBoxItems.ToDictionary(i => i.DisplayText, i => i.Value); + } + } + + if (valueLookUp.Any() && valueLookUp.ContainsKey(cellValue)) + { + value = valueLookUp[cellValue]; + } + else if (comboBoxEditor != null) // items are not mandatory + { + value = cellValue; + } + } + else + { + value = ConvertToColumnValue(cellValue, columnType); + } + } + else if (dxGridView.Columns[columnIndex].RealColumnEdit is RepositoryItemCheckEdit) + { + return cellValue == "Checked"; + } + else + { + value = ConvertToColumnValue(cellValue, columnType); + } + return value; + } + + private TableViewColumn GetColumnByDxColumn(GridColumn dxGridColumn) + { + return columns.FirstOrDefault(c => c.AbsoluteIndex == dxGridColumn.AbsoluteIndex); + } + + private void BestFitColumnsWithOnlyFirstWordOfHeader() + { + var oldHeaders = columns.ToDictionary(c => c, c => c.Caption); + + dxGridView.BeginUpdate(); + try + { + foreach (var column in columns) + { + string caption = column.Caption; + + //Say the caption is 'Discharge on Lateral (m3/s)'. We're trying to do + //something a bit smarter than just ignore the header entirely: we try + //to get the first word (eg: "Discharge"), add room for the ellipsis + //and keep that into view + + if (!String.IsNullOrEmpty(caption)) + { + var indexOfWhitespace = caption.IndexOfAny(new[] + { + ' ', + '\t' + }); + if (indexOfWhitespace >= 0) + { + //add space for ellipsis + column.Caption = caption.Substring(0, indexOfWhitespace) + "..."; + } + } + } + + dxGridView.BestFitColumns(); + + //restore the original columns + foreach (var column in columns) + { + column.Caption = oldHeaders[column]; + } + } + finally + { + dxGridView.EndUpdate(); + } + } + + private bool DeselectSelectCells(int top, int left, int bottom, int right) + { + var cellsDeselected = false; + // dxGridControl.SuspendLayout(); + dxGridView.BeginSelection(); + for (int y = top; y <= bottom; y++) + { + for (int x = left; x <= right; x++) + { + var selectedCell = selectedCells.FirstOrDefault(c => c.Column == GetColumnByDisplayIndex(x) && c.RowIndex == y); + if (selectedCell != null) + { + DeselectCell(selectedCell); + cellsDeselected = true; + } + } + } + dxGridView.EndSelection(); + //dxGridControl.ResumeLayout(); + + return cellsDeselected; + } + + private void AddEnumCellEditors() + { + foreach (var column in columns.Where(c => c.ColumnType.IsEnum && c.Editor == null)) + { + column.Editor = new ComboBoxTypeEditor + { + Items = Enum.GetValues(column.ColumnType), + ItemsMandatory = false, + CustomFormatter = new EnumFormatter(column.ColumnType) + }; + } + } + + private static void CopyPasteControllerPasteFailed(object sender, EventArgs e) + { + MessageBox.Show(e.Value); + } + + private void BindingListListChanged(object sender, ListChangedEventArgs e) + { + if (!AutoGenerateColumns || e.ListChangedType != ListChangedType.PropertyDescriptorChanged || e.PropertyDescriptor == null) + { + return; + } + + // has column name changed + var column = dxGridView.Columns.ColumnByName(e.PropertyDescriptor.DisplayName); + if (column != null) + { + return; + } + + column = dxGridView.Columns[e.NewIndex]; + + column.FieldName = e.PropertyDescriptor.Name; + column.Caption = e.PropertyDescriptor.DisplayName; + } + + private void DataSourceDataTableColumnsCollectionChanged(object sender, CollectionChangeEventArgs e) + { + if (e.Action == CollectionChangeAction.Add || e.Action == CollectionChangeAction.Remove) + { + if (AutoGenerateColumns) + { + dxGridView.PopulateColumns(); + BuildColumnWrappers(); + BestFitColumns(); + } + } + } + + private void DataSourcePropertyChanged(object sender, PropertyChangedEventArgs e) + { + refreshRequired = true; + } + + private void DataSourceCollectionChanged(object sender, NotifyCollectionChangeEventArgs e) + { + refreshRequired = true; + UpdateHeaderColumnSize(); + } + + /// + /// Checks if the mouse is clicked at the Header Panel Button in the grid. + /// If yes select entire grid (TOOLS-2834) + /// cfr: http://documentation.devexpress.com/#WindowsForms/CustomDocument532 + /// "The header panel button belongs to both the column header panel and row + /// indicator panel elements. By default, the header panel button has no special + /// functionality. When the View is used to represent detail data, the header + /// panel button serves as a zoom button." + /// + /// + /// + private void HandleHeaderPanelButton(object sender, MouseEventArgs e) + { + var view = sender as GridView; + if (view == null) + { + return; + } + var hitInfo = view.CalcHitInfo(new Point(e.X, e.Y)); + if ((hitInfo.HitTest == GridHitTest.ColumnButton) && (hitInfo.InColumn == false)) + { + view.SelectAll(); + } + } + + private static DXMenuItem GetItemByStringId(DXPopupMenu menu, GridStringId id) + { + return menu.Items.Cast().FirstOrDefault(item => ((GridStringId) item.Tag) == id); + } + + private void SubscribeToDataSource() + { + if (dxGridControl.DataSource == null) + { + return; + } + + var propertyChanged = dxGridControl.DataSource as INotifyPropertyChanged; + if (propertyChanged != null) + { + propertyChanged.PropertyChanged += DataSourcePropertyChanged; + } + + var collectionChanged = dxGridControl.DataSource as INotifyCollectionChanged; + if (collectionChanged != null) + { + collectionChanged.CollectionChanged += DataSourceCollectionChanged; + } + + var dataTable = dxGridControl.DataSource as DataTable; + if (dataTable != null) + { + var table = dataTable; + table.Columns.CollectionChanged += DataSourceDataTableColumnsCollectionChanged; + } + + var bindingList = dxGridControl.DataSource as IBindingList; + if (bindingList != null) + { + bindingList.ListChanged += BindingListListChanged; + } + } + + private void UnSubscribeFromDataSource() + { + if (dxGridControl == null || dxGridControl.DataSource == null) + { + return; + } + + var propertyChanged = dxGridControl.DataSource as INotifyPropertyChanged; + if (propertyChanged != null) + { + propertyChanged.PropertyChanged -= DataSourcePropertyChanged; + } + + var notifyCollectionChanged = dxGridControl.DataSource as INotifyCollectionChanged; + if (notifyCollectionChanged != null) + { + notifyCollectionChanged.CollectionChanged -= DataSourceCollectionChanged; + } + + var dataTable = dxGridControl.DataSource as DataTable; + if (dataTable != null) + { + var table = dataTable; + table.Columns.CollectionChanged -= DataSourceDataTableColumnsCollectionChanged; + } + + var bindingSource = dxGridControl.DataSource as BindingSource; + if (bindingSource != null) + { + bindingSource.ListChanged -= BindingListListChanged; + } + } + + /// + /// Calculate width of the header column based on grid font + /// + private void UpdateHeaderColumnSize() + { + var indicatorWidth = (int) dxGridControl.Font.SizeInPoints*RowCount.ToString(CultureInfo.InvariantCulture).Length + 15; + dxGridView.IndicatorWidth = showRowNumbers ? indicatorWidth : -1; + Refresh(); + } + + /// + /// Returns true if the whole selection is readonly. This can be on cell,column or table level If a cell is not it returns false. + /// + /// + private bool GetSelectionIsReadonly() + { + //no selection use tableview readonly + if (selectedCells.Count == 0) + { + return ReadOnly; + } + + //A selection is readonly if ALL cells are readonly (otherwise i can change the not readonly part) + return selectedCells.All(cell => CellIsReadOnly(cell.RowIndex, cell.Column)); + } + + private void UpdateSelectionFromGridControl() + { + if (updatingSelection) + { + return; + } + + updatingSelection = true; + + ClearSelectedCells(); + + var gridViewSelectedCells = dxGridView.GetSelectedCells(); + foreach (var cell in gridViewSelectedCells) + { + var tableViewCell = new TableViewCell(cell.RowHandle, GetColumnByDxColumn(cell.Column)); + SelectCell(tableViewCell); + } + + if (!IsEditing && !isPasting) + { + if (SelectionChanged != null) + { + Log.DebugFormat(Resources.TableView_UpdateSelectionFromGridControl_Firing_selection_changed_event); + SelectionChanged(this, new TableSelectionChangedEventArgs(selectedCells.ToArray())); + } + } + + // Update the row context menu + RowContextMenu.Items.OfType().ForEachElementDo(mi => mi.Available = true); + RowContextMenu.Items.OfType() + .Where(mi => mi.Name == "btnDelete" || mi.Name == "btnPaste") + .ForEachElementDo(mi => mi.Available = !GetSelectionIsReadonly()); + + updatingSelection = false; + } + + private void BuildColumnWrappers() + { + if (!AutoGenerateColumns) + { + return; + } + + columns.Clear(); + + foreach (GridColumn dxColumn in dxGridView.Columns) + { + columns.Add(new TableViewColumn(dxGridView, dxGridControl, dxColumn, this, false) + { + SortingAllowed = AllowColumnSorting + }); + } + } + + private void ShowEditorIfRowSelect() + { + if (dxGridView.FocusedColumn != null && (RowSelect) && (dxGridView.ActiveEditor == null)) + { + dxGridView.ShowEditor(); + } + } + + private GridColumn GetDxColumnByDisplayIndex(int displayIndex) + { + return dxGridView.Columns[columns.First(c => c.DisplayIndex == displayIndex).AbsoluteIndex]; + } + + private void UpdateColumnHeaderMenu(GridMenuEventArgs e, TableViewColumn viewColumn) + { + //show grid menu is handled to remove menu-items. For grouping etc. + //No way to do this in a setting :( + //see http://community.devexpress.com/forums/t/61316.aspx + + var ids = new[] + { + GridStringId.MenuColumnGroupBox, + GridStringId.MenuColumnGroup, + GridStringId.MenuColumnRemoveColumn + }; + + var dxMenuItems = ids.Select(id => GetItemByStringId(e.Menu, id)); + var dxMenuItemsToHide = dxMenuItems.Where(item => item != null); + foreach (var item in dxMenuItemsToHide) + { + item.Visible = false; + } + + if (AllowColumnPinning && viewColumn != null) + { + var pinColumnMenuItem = new DXMenuCheckItem + { + Caption = viewColumn.Pinned ? Resources.TableView_UpdateColumnHeaderMenu_Unpin_Column : Resources.TableView_UpdateColumnHeaderMenu_Pin_Column, + Checked = viewColumn.Pinned, + Image = Resources.pin + }; + + pinColumnMenuItem.CheckedChanged += (sender, args) => { viewColumn.Pinned = pinColumnMenuItem.Checked; }; + + e.Menu.Items.Add(pinColumnMenuItem); + } + + var copyHeadersColumnMenuItem = new DXMenuItem + { + Caption = Resources.TableView_UpdateColumnHeaderMenu_Copy_all_headers, + Image = Resources.CopyHS + }; + + copyHeadersColumnMenuItem.Click += (sender, args) => + { + var sb = new StringBuilder(); + + CopyHeader(sb); + + Clipboard.Clear(); + Clipboard.SetData(DataFormats.Text, sb.ToString()); + }; + + e.Menu.Items.Add(copyHeadersColumnMenuItem); + } + + private bool ValidateAndCommitRow(int rowIndex) + { + string errorText; + if (!tableViewValidator.ValidateRow(rowIndex, out errorText)) + { + Log.ErrorFormat(Resources.TableView_ValidateAndCommitRow_Can_not_set_value_for_row_0_reason_1_, rowIndex, errorText); + dxGridView.CancelUpdateCurrentRow(); + tableViewValidator.RefreshRowData(); + dxGridView.DeleteRow(rowIndex); + return false; + } + + dxGridView.FocusedRowHandle = rowIndex; + //this line is needed for the changes to be 'commited' and the row + //to leave an updating state. http://community.devexpress.com/forums/p/30892/106718.aspx + //unfortunately hard to write a test without exposing/hacking too much + dxGridView.UpdateCurrentRow(); + tableViewValidator.RefreshRowData(); + return true; + } + + private bool SetCellValueInternal(int rowIndex, int columnDisplayIndex, object value) + { + var col = GetDxColumnByDisplayIndex(columnDisplayIndex); + + if (CellIsReadOnly(rowIndex, GetColumnByDxColumn(col))) + { + return false; + } + + //check if the value can be converted to the column type + object objectValue = value is string + ? ConvertStringValueToDataValue(col.AbsoluteIndex, (string) value) + : value; + if (objectValue == null) + { + Log.ErrorFormat(Resources.TableView_SetCellValueInternal_Can_not_set_value_into_cell_0_1_reason_2_, rowIndex, col.AbsoluteIndex, Resources.TableView_SetCellValueInternal_No_conversion_from_string_possible); + return false; + } + + string error; + if (!tableViewValidator.ValidateCell(new TableViewCell(rowIndex, GetColumnByDxColumn(col)), objectValue, out error)) + { + Log.ErrorFormat(Resources.TableView_SetCellValueInternal_Can_not_set_value_into_cell_0_1_reason_2_, rowIndex, col.AbsoluteIndex, error); + return false; + } + + // (Gijs) We are mixing the row handlers and indices throughout this wrapper: should be fixed, as + + dxGridView.FocusedRowHandle = rowIndex; + + dxGridView.SetRowCellValue(rowIndex, col, objectValue); + return true; + } + + private static object ConvertToColumnValue(string cellValue, Type columnType) + { + try + { + return TypeConverter.ConvertValueToTargetType(columnType, cellValue); + } + catch (Exception) + { + if (string.IsNullOrEmpty(cellValue.TrimStart())) + { + if (columnType.IsValueType) + { + return Activator.CreateInstance(columnType); + } + return null; + } + + // still try to parse double or float numbers + if (columnType == typeof(double) || columnType == typeof(float)) + { + double value; + if (double.TryParse(cellValue, out value)) + { + return value; + } + } + + Log.WarnFormat(Resources.TableView_ConvertToColumnValue_Unable_to_convert_string_0_to_1_for_paste, cellValue, columnType); + return null; + } + } + + #region Public properties + + /// + /// Specifies whether the edit buttons on the bottom of the table view is shown + /// + public bool EditButtons + { + get + { + return dxGridControl.UseEmbeddedNavigator; + } + set + { + dxGridControl.UseEmbeddedNavigator = value; + } + } + + public bool AllowDeleteRow + { + get + { + if (bindingSource == null) // lazy initialize + { + bindingSource = new BindingSource + { + DataSource = dxGridView.DataSource + }; + } + + var tableAllowRemove = dxGridView.OptionsBehavior.AllowDeleteRows; + var dataAllowsRemove = bindingSource.AllowRemove; + + // better code, but doesn't work for List (hacked through BindingSource): + // dataAllowsNew = xGridView.DataController != null && dxGridView.DataController.AllowNew; + + return (tableAllowRemove == DefaultBoolean.True || tableAllowRemove == DefaultBoolean.Default) && + dataAllowsRemove; + } + set + { + dxGridView.OptionsBehavior.AllowDeleteRows = value ? DefaultBoolean.True : DefaultBoolean.False; + if (dxGridControl.EmbeddedNavigator != null) + { + dxGridControl.EmbeddedNavigator.Buttons.Remove.Visible = value; + } + } + } + + public bool AllowAddNewRow + { + get + { + if (bindingSource == null) // lazy initialize + { + bindingSource = new BindingSource + { + DataSource = dxGridView.DataSource + }; + } + + var tableAllowNew = dxGridView.OptionsBehavior.AllowAddRows; + var dataAllowsNew = bindingSource.AllowNew; + + // better code, but doesn't work for List (hacked through BindingSource): + // dataAllowsNew = xGridView.DataController != null && dxGridView.DataController.AllowNew; + + return (tableAllowNew == DefaultBoolean.True || tableAllowNew == DefaultBoolean.Default) && + dataAllowsNew; + } + set + { + dxGridView.OptionsBehavior.AllowAddRows = value ? DefaultBoolean.True : DefaultBoolean.False; + dxGridView.OptionsView.NewItemRowPosition = value ? NewItemRowPosition.Bottom : NewItemRowPosition.None; + if (dxGridControl.EmbeddedNavigator != null) + { + dxGridControl.EmbeddedNavigator.Buttons.Append.Enabled = value; + } + } + } + + public bool AllowColumnSorting + { + get + { + return allowColumnSorting; + } + set + { + if (allowColumnSorting == value) + { + return; + } + + allowColumnSorting = value; + foreach (var column in columns) + { + column.SortingAllowed = allowColumnSorting; + } + } + } + + public bool AllowColumnPinning { get; set; } + + /// + /// Gets or sets whether multiple rows can be selected + /// + public bool MultiSelect + { + get + { + return dxGridView.OptionsSelection.MultiSelect; + } + set + { + dxGridView.OptionsSelection.MultiSelect = value; + } + } + + public bool IncludeHeadersOnCopy { get; set; } + + /// + /// Gets a boolean value indicating that the view is being edited or not + /// + [Browsable(false)] + public bool IsEditing + { + get + { + return dxGridView.IsEditing || dxGridView.FocusedRowModified; + } + } + + /// + /// TODO: If RowSelect is true, dxGridView.GetSelectedCells etc will give an empty array.... SelectedRows will stiull work. + /// + public bool RowSelect + { + get + { + return dxGridView.OptionsSelection.MultiSelectMode == GridMultiSelectMode.RowSelect; + } + set + { + dxGridView.OptionsSelection.EnableAppearanceFocusedCell = false; + dxGridView.FocusRectStyle = DrawFocusRectStyle.None; + dxGridView.OptionsSelection.MultiSelectMode = (value) ? GridMultiSelectMode.RowSelect : GridMultiSelectMode.CellSelect; + } + } + + public bool ShowRowNumbers + { + get + { + return showRowNumbers; + } + set + { + showRowNumbers = value; + UpdateHeaderColumnSize(); + } + } + + public bool ColumnAutoWidth + { + get + { + return dxGridView.OptionsView.ColumnAutoWidth; + } + set + { + dxGridView.OptionsView.ColumnAutoWidth = value; + } + } + + public bool UseCenteredHeaderText + { + get + { + return dxGridView.Appearance.HeaderPanel.TextOptions.HAlignment == HorzAlignment.Center; + } + set + { + dxGridView.Appearance.HeaderPanel.TextOptions.HAlignment = (value) + ? HorzAlignment.Center + : HorzAlignment.Default; + } + } + + public bool ReadOnly + { + get + { + return !dxGridView.Editable; + } + set + { + dxGridView.OptionsBehavior.Editable = !value; + } + } + + public bool MultipleCellEdit { get; set; } + + /// + /// Determines whether the tableview generates columns when + /// setting data + /// + public bool AutoGenerateColumns + { + get + { + return autoGenerateColumns; + } + set + { + autoGenerateColumns = value; + //update gridview behavior + dxGridView.OptionsBehavior.AutoPopulateColumns = value; + } + } + + public bool AutoSizeRows + { + get + { + return dxGridView.OptionsView.RowAutoHeight; + } + set + { + dxGridView.OptionsView.RowAutoHeight = value; + } + } + + public int HeaderHeigth + { + get + { + return dxGridView.ColumnPanelRowHeight; + } + set + { + if (value > 0) + { + dxGridView.Appearance.HeaderPanel.TextOptions.WordWrap = WordWrap.Wrap; + } + dxGridView.ColumnPanelRowHeight = value; + } + } + + public int RowHeight + { + get + { + return dxGridView.RowHeight; + } + set + { + dxGridView.RowHeight = value; + } + } + + /// + /// Number of rows in the grid excluding the newrow and filtered rows. + /// + [Browsable(false)] + public int RowCount + { + get + { + return dxGridView.DataController.VisibleCount; + } + } + + [Browsable(false)] + [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] + public int FocusedRowIndex + { + get + { + return dxGridView.FocusedRowHandle; + } + set + { + if (dxGridView.FocusedRowHandle != value && dxGridView.FocusedRowHandle != int.MinValue && value > -1) + { + dxGridView.FocusedRowHandle = value; + } + } + } + + [Browsable(false)] + public int[] SelectedRowsIndices + { + get + { + return dxGridView.GetSelectedRows(); + } + } + + [Browsable(false)] + public int[] SelectedColumnsIndices + { + get + { + return selectedCells.Select(c => c.Column.AbsoluteIndex).OrderBy(i => i).Distinct().ToArray(); + } + } + + /// + /// Gets or sets the disabled cell fore color + /// + public Color ReadOnlyCellForeColor { get; set; } + + /// + /// Gets or sets the disabled cell fore color + /// + public Color ReadOnlyCellBackColor { get; set; } + + /// + /// Gets or sets the background color of the invalid cell (value) + /// + public Color InvalidCellBackgroundColor { get; set; } + + /// + /// Returns the focused row (also works if the focused row is new or deleted) + /// + [Browsable(false)] + public object CurrentFocusedRowObject + { + get + { + return dxGridView.GetFocusedRow(); + } + } + + [Browsable(false)] + [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] + public object Data + { + get + { + return dxGridControl.DataSource; + } + set + { + dxGridView.CancelUpdateCurrentRow(); + UnSubscribeFromDataSource(); + bindingSource = null; + ClearSelection(); + + // clear before binding enables rebinding to new function; will remove old columns + if (dxGridControl.DataSource != value) + { + // do not explicitly clear columns; this will also remove user added column editors + + dxGridControl.DataSource = value; + + if (AutoGenerateColumns) + { + dxGridView.PopulateColumns(); + } + } + + if (value == null) + { + return; + } + + SubscribeToDataSource(); + + BeginInit(); + + BuildColumnWrappers(); + AddEnumCellEditors(); + UpdateHeaderColumnSize(); + + EndInit(); + } + } + + [Browsable(false)] + [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] + public TableViewPasteController PasteController { get; set; } + + [Browsable(false)] + [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] + public ValidationExceptionMode ExceptionMode { get; set; } + + [Browsable(false)] + public IEnumerable SelectedCells + { + get + { + return selectedCells; + } + } + + // avoid serialization of Columns into resx files, + // when something changes in columns designers becomes mad because of broken resx files + [Browsable(false)] + [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] + public ReadOnlyCollection Columns + { + get + { + return columns.AsReadOnly(); + } + } + + public override ContextMenuStrip ContextMenuStrip + { + get + { + return RowContextMenu; + } + set + { + RowContextMenu = value; + } + } + + public ContextMenuStrip RowContextMenu + { + get + { + return dxGridControl.ContextMenuStrip; + } + private set + { + dxGridControl.ContextMenuStrip = value; + } + } + + [Browsable(false)] + [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] + public IList ColumnMenuItems { get; set; } + + /// + /// Gets or sets the filter to evaluate if the value of the cell is invalid + /// + [Browsable(false)] + [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] + public Func InvalidCellFilter { get; set; } + + /// + /// Gets or sets the filter that can be used for making cells read-only + /// + [Browsable(false)] + [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] + public Func ReadOnlyCellFilter { get; set; } + + /// + /// Gets or sets the filter that can be used for styling a cell + /// + [Browsable(false)] + [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] + public Func DisplayCellFilter { get; set; } + + /// + /// Function for getting or setting unbound column values + /// Parameters : column index, datasource row index, is getter, is setter, value + /// + [Browsable(false)] + [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] + public Func UnboundColumnData { get; set; } + + /// + /// Gets or sets the row values validator. The validator should return a RowValidationResult + /// + /// ?Does not validate before commit to data source? + [Browsable(false)] + public Func RowValidator { get; set; } + + /// + /// Gets or sets the cell value editor validator. The validator should return true on valid values + /// + [Browsable(false)] + [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] + public Func> InputValidator { get; set; } + + /// + /// Gets or sets the function that checks if the current selection can be deleted. + /// When null or returning true, deletion is allowed. + /// + [Browsable(false)] + [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] + public Func CanDeleteCurrentSelection { get; set; } + + /// + /// Gets or sets the function for deleting selected rows (return value indicates if the deleting is handled) + /// When null or returning false the default delete will be executed + /// + [Browsable(false)] + [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] + public Func RowDeleteHandler { get; set; } + + public bool IsEndEditOnEnterKey { get; set; } + + /// + /// Enable filtering for all columns + /// + public bool AllowColumnFiltering + { + get + { + return columns.OfType().Any(c => c.FilteringAllowed); + } + set + { + foreach (var column in columns.OfType()) + { + column.FilteringAllowed = value; + } + } + } + + #endregion + + #region Public functions + + public new void ResetBindings() + { + dxGridControl.ResetBindings(); + if (AutoGenerateColumns) + { + dxGridView.PopulateColumns(); + BuildColumnWrappers(); + BestFitColumns(); + } + + base.ResetBindings(); + } + + /// + /// Function to check if the current focused row is a + /// new row (row that's not committed to the datasource) + /// + /// If the focused row is a new row + public bool OnNewRow() + { + return dxGridView.FocusedRowHandle.Equals(GridControl.NewItemRowHandle); + } + + /// + /// Clear selected rows + /// + public void ClearSelection() + { + dxGridView.ClearSelection(); + } + + /// + /// Allows to fit all columns to their contents. + /// + public void BestFitColumns(bool useOnlyFirstWordOfHeader = false) + { + dxGridView.BestFitMaxRowCount = columns.Count > 50 ? 10 : 50; + + if (useOnlyFirstWordOfHeader) + { + BestFitColumnsWithOnlyFirstWordOfHeader(); + } + else + { + dxGridView.BestFitColumns(); + } + } + + public int GetRowIndexByDataSourceIndex(int datarowIndex) + { + return dxGridView.GetRowHandle(datarowIndex); + } + + /// + /// Sets a display filter on a column. Note that it filters values on it's display text rather than the actual value. + /// + /// The name of the column to apply a display filter to + /// The SQL-like filter expression to apply + public void SetColumnFilter(string columnName, string filter) + { + if (filter == string.Empty) + { + // Remove the filter rather than add or change it + dxGridView.ActiveFilter.Remove(dxGridView.Columns[columnName]); + return; + } + var columnFilterInfo = new ColumnFilterInfo(filter); + dxGridView.ActiveFilter.Add(dxGridView.Columns[columnName], columnFilterInfo); + } + + public void BeginInit() + { + dxGridView.BeginUpdate(); + dxGridControl.BeginUpdate(); + } + + public void EndInit() + { + dxGridControl.EndUpdate(); + dxGridView.EndUpdate(); + } + + public TableViewColumn GetColumnByName(string columnName) + { + return columns.FirstOrDefault(c => c.Name == columnName); + } + + public void SelectRow(int index, bool clearPreviousSelection = true) + { + SelectRows(new[] + { + index + }, clearPreviousSelection); + } + + public void SelectRows(int[] indices, bool clearPreviousSelection = true) + { + dxGridView.BeginSelection(); + + if (clearPreviousSelection) + { + dxGridView.ClearSelection(); //clear any previous selection + } + + dxGridView.HideEditor(); //close any open editor + + for (int i = 0; i < indices.Length; i++) + { + if (i == 0) + { + dxGridView.SelectionChanged -= DxGridViewSelectionChanged; + } + + if (i == indices.Length - 1) + { + dxGridView.SelectionChanged += DxGridViewSelectionChanged; + } + + dxGridView.SelectRow(indices[i]); + } + dxGridView.EndSelection(); + } + + /// + /// Returns the index of the data source record which the specified row handle corresponds to. + /// + /// The visualized, zero-based row-index in the table + /// + /// An integer value representing the zero-based index of the data record to which the specified row handle corresponds + /// + public int GetDataSourceIndexByRowIndex(int rowIndex) + { + RefreshIfRequired(); + return dxGridView.GetDataSourceRowIndex(rowIndex); + } + + private void RefreshIfRequired() + { + if (refreshRequired) + { + RefreshData(); + refreshRequired = false; + } + } + + public void RefreshData() + { + dxGridControl.RefreshDataSource(); + dxGridView.LayoutChanged(); + } + + public void ScheduleRefresh() + { + refreshRequired = true; + } + + public bool CellIsReadOnly(int rowHandle, TableViewColumn column) + { + // Tableview readonly? + if (ReadOnly) + { + return true; + } + + // Column does not exist or cannot be found (not visible for example) + if (column == null) + { + return true; + } + + // Column readonly? + if (column.ReadOnly) + { + return true; + } + + // Cell readonly? + if (ReadOnlyCellFilter != null) + { + return ReadOnlyCellFilter(new TableViewCell(rowHandle, column)); + } + + // Cell is not read only + return false; + } + + /// + /// Assign a certain value to cell. + /// + /// Display index of the row + /// Display index of the column + /// String value to be set + public bool SetCellValue(int rowIndex, int columnIndex, object value) + { + tableViewValidator.AutoValidation = false; + + try + { + if (!SetCellValueInternal(rowIndex, columnIndex, value)) + { + return false; + } + + if (!ValidateAndCommitRow(rowIndex)) + { + return false; + } + } + finally + { + tableViewValidator.AutoValidation = true; + } + + return true; + } + + public bool SetRowCellValues(int rowIndex, int columnDisplayStartIndex, object[] cellValues) + { + tableViewValidator.AutoValidation = false; + var success = true; + + try + { + for (int i = 0; i < cellValues.Length; i++) + { + if (CellIsReadOnly(rowIndex, GetColumnByDisplayIndex(i + columnDisplayStartIndex))) // skip readonly cells, does not affect success. + { + continue; + } + success &= SetCellValueInternal(rowIndex, i + columnDisplayStartIndex, cellValues[i]); + } + + if (!success) + { + return false; + } + + success = ValidateAndCommitRow(rowIndex); + } + finally + { + tableViewValidator.AutoValidation = true; + } + + return success; + } + + public object GetRowObjectAt(int rowIndex) + { + return dxGridView.RowCount > rowIndex && rowIndex >= 0 ? dxGridView.GetRow(rowIndex) : null; + } + + /// + /// Gets value of a certain cell. + /// + /// Index of the row + /// Absolute index of the column + public object GetCellValue(int rowIndex, int absoluteColumnIndex) + { + return dxGridView.GetRowCellValue(rowIndex, dxGridView.Columns[absoluteColumnIndex]); + } + + /// + /// Gets value of a certain cell. + /// + public object GetCellValue(TableViewCell cell) + { + return GetCellValue(cell.RowIndex, cell.Column.AbsoluteIndex); + } + + /// + /// Selects cells in a square described by top,left -> bottom,right + /// + /// + /// + /// + /// + /// + public void SelectCells(int top, int left, int bottom, int right, bool clearOldSelection = true) + { + // dxGridControl.SuspendLayout(); + dxGridView.BeginSelection(); + if (RowSelect) + { + throw new InvalidOperationException(Resources.TableView_SelectCells_Unable_to_select_cells_when_tableView_has_RowSelect_enabled_Use_SelectRow_instead); + } + + if (clearOldSelection) + { + ClearSelectedCells(); + } + + for (int y = top; y <= bottom; y++) + { + for (int x = left; x <= right; x++) + { + var tableViewCell = new TableViewCell(y, GetColumnByDisplayIndex(x)); + SelectCell(tableViewCell); + } + } + dxGridView.EndSelection(); + //dxGridControl.ResumeLayout(); + } + + private void SelectCell(TableViewCell cell) + { + if (!updatingSelection) + { + selectedCells.Add(cell); + var gridColumn = GetDxColumnByDisplayIndex(cell.Column.DisplayIndex); + dxGridView.SelectCell(cell.RowIndex, gridColumn); + } + } + + private void ClearSelectedCells() + { + foreach (var cell in selectedCells.ToArray()) + { + DeselectCell(cell); + } + } + + private void DeselectCell(TableViewCell cell) + { + if (!updatingSelection && selectedCells.Remove(cell)) + { + var gridColumn = GetDxColumnByDisplayIndex(cell.Column.DisplayIndex); + dxGridView.UnselectCell(cell.RowIndex, gridColumn); + } + } + + /// + /// Pastes clipboard contens into current selection + /// + public void PasteClipboardContents() + { + isPasting = true; + PasteController.PasteClipboardContents(); + isPasting = false; + } + + /// + /// Copy original (not the display) values to the clipboard as strings + /// + public void CopySelectionToClipboard() + { + var sb = new StringBuilder(); + var areAllCellsSelected = dxGridView.GetSelectedCells().Length == (dxGridView.DataRowCount*dxGridView.VisibleColumns.Count); + + if (areAllCellsSelected && IncludeHeadersOnCopy) + { + CopyHeader(sb); + } + + var selectedGridCells = dxGridView.GetSelectedCells(); + var rowIndex = -1; + foreach (var cell in selectedGridCells) + { + if (rowIndex != cell.RowHandle) + { + if (rowIndex != -1) + { + sb.AppendLine(); + } + rowIndex = cell.RowHandle; + } + else + { + sb.Append("\t"); + } + + sb.Append(dxGridView.GetRowCellValue(cell.RowHandle, cell.Column)); + } + + if (rowIndex != -1) + { + sb.AppendLine(); + } + + Clipboard.Clear(); + Clipboard.SetData(DataFormats.Text, sb.ToString()); + } + + private void CopyHeader(StringBuilder sb) + { + var header = ""; + + for (var i = 0; i < dxGridView.Columns.Count; i++) + { + if (header != "") + { + header += "\t"; + } + + header += dxGridView.Columns[i].GetTextCaption().Replace("\n", " "); + } + + sb.AppendLine(header); + } + + public void SetFocus(int rowIndex, int columnIndex) + { + var column = GetDxColumnByDisplayIndex(columnIndex); + + dxGridView.FocusedRowHandle = rowIndex; + dxGridView.FocusedColumn = column; + + //this is needed to get the focus visible + dxGridView.ShowEditor(); + dxGridView.HideEditor(); + } + + public void DeleteCurrentSelection() + { + if (ReadOnly) + { + return; + } + + dxGridView.CancelUpdateCurrentRow(); // cancel any open changes (as that may trigger validation) + + // Nothing to delete? + if (dxGridView.GetSelectedRows().Length == 0) + { + return; + } + + // Is deletion allowed? + if (CanDeleteCurrentSelection != null && !CanDeleteCurrentSelection()) + { + return; + } + + //delete rows in case entire rows are selected + var groupBy = selectedCells.GroupBy(c => c.RowIndex); + var count = columns.Count(c => c.Visible); + if (AllowDeleteRow && (RowSelect || groupBy.All(g => g.Count() == count))) + { + if (RowDeleteHandler == null || !RowDeleteHandler()) + { + dxGridView.DeleteSelectedRows(); + } + return; + } + + var selectedGridCells = selectedCells.ToList(); + foreach (var c in selectedGridCells) + { + var defaultValue = c.Column.DefaultValue ?? + TypeUtils.GetDefaultValue(c.Column.ColumnType); + + SetCellValue(c.RowIndex, c.Column.DisplayIndex, Convert.ToString(defaultValue)); + } + } + + public void AddColumn(string dataSourcePropertyName, string columnCaption, bool readOnly = false, int width = 100, Type columnType = null, string displayFormat = null) + { + var dxColumn = dxGridView.Columns.AddField(dataSourcePropertyName); + dxColumn.Caption = columnCaption; + dxColumn.VisibleIndex = dxGridView.Columns.Count - 1; + dxColumn.OptionsColumn.ReadOnly = readOnly; + dxColumn.Width = width; + + var column = new TableViewColumn(dxGridView, dxGridControl, dxColumn, this, false); + + if (displayFormat != null) + { + column.DisplayFormat = displayFormat; + } + + columns.Add(column); + } + + public void ClearColumns() + { + dxGridView.Columns.Clear(); + columns.Clear(); + } + + public void Remove(TableViewColumn column) + { + if (columns.Remove(column)) + { + dxGridView.Columns.Remove(column.DxColumn); + } + } + + public void RemoveAllWhere(Func whereClause) + { + foreach (var tableViewColumn in columns.Where(whereClause).ToArray()) + { + Remove(tableViewColumn); + } + } + + /// + /// Adds an unbound column to the table. (Use to set values for the column) + /// + /// Name of the column + /// Type of the data the column is going to display + /// Index of the column + /// Editor to use for editing the values of this column + public void AddUnboundColumn(string columnName, Type columnType, int index = -1, Editors.ITypeEditor editor = null) + { + var unbColumn = dxGridView.Columns.AddField(columnName); + var column = new TableViewColumn(dxGridView, dxGridControl, unbColumn, this, true); + columns.Add(column); + + unbColumn.VisibleIndex = index != -1 ? index : dxGridView.Columns.Count; + + if (columnType == typeof(double)) + { + unbColumn.UnboundType = UnboundColumnType.Decimal; + unbColumn.DisplayFormat.FormatType = FormatType.Numeric; + } + else if (columnType == typeof(int)) + { + unbColumn.UnboundType = UnboundColumnType.Integer; + unbColumn.DisplayFormat.FormatType = FormatType.Numeric; + } + else if (columnType == typeof(string)) + { + unbColumn.UnboundType = UnboundColumnType.String; + unbColumn.DisplayFormat.FormatType = FormatType.None; + } + else if (columnType.IsEnum) + { + unbColumn.UnboundType = UnboundColumnType.Object; + } + else if (columnType == typeof(DateTime)) + { + unbColumn.UnboundType = UnboundColumnType.DateTime; + unbColumn.DisplayFormat.FormatType = FormatType.Custom; + } + else + { + throw new ArgumentException(string.Format(Resources.TableView_AddUnboundColumn_Unbound_columns_of_type_0_not_supported, columnType)); + } + if (editor != null) + { + column.Editor = editor; + } + + dxGridView.CustomUnboundColumnData -= DxGridViewCustomUnboundColumnData; + dxGridView.CustomUnboundColumnData += DxGridViewCustomUnboundColumnData; + } + + public string GetCellDisplayText(int rowIndex, int absoluteColumnIndex) + { + return dxGridView.GetDisplayTextByColumnValue(dxGridView.Columns[absoluteColumnIndex], GetCellValue(rowIndex, absoluteColumnIndex)); + } + + #endregion + + #region Public events + + public event EventHandler FocusedRowChanged; + + public event EventHandler SelectionChanged; + + public event EventHandler> CellChanged; + + public event EventHandler> ColumnFilterChanged; + + #endregion + + #region Internal functions + + /// + /// Returns true when any column is sorted + /// + internal bool IsSorted() + { + return columns.Any(c => c.SortOrder != SortOrder.None); + } + + internal TableViewCell GetFocusedCell() + { + //no selection + if (dxGridView.FocusedColumn == null) + { + return null; + } + //no row selected + if (dxGridView.FocusedRowHandle == int.MinValue) + { + return null; + } + //'new' row..select the bottom + if (dxGridView.FocusedRowHandle == (int.MinValue + 1)) + { + var rowIndex = Math.Max(0, dxGridView.RowCount - 1); + return new TableViewCell(rowIndex, GetColumnByDxColumn(dxGridView.FocusedColumn)); + } + return new TableViewCell(dxGridView.FocusedRowHandle, GetColumnByDxColumn(dxGridView.FocusedColumn)); + } + + internal void SetColumnError(TableViewColumn tableColumn, string errorText) + { + var dxGridColumn = tableColumn != null ? dxGridView.Columns[tableColumn.AbsoluteIndex] : null; + dxGridView.SetColumnError(dxGridColumn, errorText); + } + + internal void AddNewRowToDataSource() + { + if (bindingSource == null) + { + bindingSource = new BindingSource + { + DataSource = dxGridView.DataSource + }; + } + + if (!bindingSource.AllowNew) + { + Log.Debug(Resources.TableView_AddNewRowToDataSource_Adding_rows_to_this_table_is_not_allowed); + return; + } + bindingSource.AddNew(); + + //end edit is needed when we bind to datatable + if (bindingSource.DataSource is DataTable || bindingSource.DataSource is DataView) + { + bindingSource.EndEdit(); + } + } + + internal TableViewColumn GetColumnByDisplayIndex(int i) + { + return columns.FirstOrDefault(c => c.DisplayIndex == i); + } + + #endregion + + #region Gridview event handlers + + private void EmbeddedNavigatorButtonClick(object sender, NavigatorButtonClickEventArgs e) + { + if (e.Button != dxGridControl.EmbeddedNavigator.Buttons.Remove) + { + return; + } + + // reroute delete event to "our" delete function + e.Handled = true; + DeleteCurrentSelection(); + } + + /// + /// Do keyboard cursor interaction like in Excel (StackOverflow: (c)Jakob M�ll�s) + /// + /// + /// + private void DxGridControlEditorKeyDown(object sender, KeyEventArgs e) + { + if (e.KeyCode == Keys.Enter && UserIsHoldingDownControlForCellFill()) + { + // grab selected cells here because changing the first value may cause the + // data source to refresh and the selection to be lost + cellsToFill = dxGridView.GetSelectedCells(); + return; + } + + if (e.KeyData != Keys.Left && e.KeyData != Keys.Right) + { + return; + } + + var gridControl = sender as GridControl; + if (gridControl == null) + { + return; + } + + var view = gridControl.FocusedView as GridView; + if (view == null) + { + return; + } + + var textEdit = view.ActiveEditor as TextEdit; + if (textEdit == null) + { + return; + } + + var left = e.KeyData == Keys.Left; + var right = e.KeyData == Keys.Right; + + // Handle initial case - everything selected in control + if ((left || right) && + textEdit.SelectionLength == textEdit.Text.Length && + textEdit.SelectionStart == 0) + { + textEdit.SelectionStart = left ? 0 : textEdit.Text.Length; //minor adjustment + textEdit.SelectionLength = 0; + e.Handled = true; + return; + } + + // Handle left & rightmost positions (prevent focus change) + e.Handled = left && textEdit.SelectionStart == 0 || + right && textEdit.SelectionStart == textEdit.Text.Length; + } + + private void DxGridViewDoubleClick(object sender, EventArgs e) + { + OnDoubleClick(e); + } + + private void DxGridViewCustomDrawCell(object sender, RowCellCustomDrawEventArgs e) + { + var tableViewColumn = GetColumnByDxColumn(e.Column); + + var buttonControl = tableViewColumn.Editor as ButtonTypeEditor; + if (buttonControl == null || !buttonControl.HideOnReadOnly) + { + return; + } + + var cellReadOnly = CellIsReadOnly(e.RowHandle, tableViewColumn); + if (!cellReadOnly) + { + return; + } + + var buttonEditViewInfo = ((GridCellInfo) e.Cell).ViewInfo as ButtonEditViewInfo; + if ((buttonEditViewInfo == null) || (buttonEditViewInfo.RightButtons.Count != 1)) + { + return; + } + + e.Appearance.FillRectangle(new GraphicsCache(e.Graphics), e.Bounds); + e.Handled = true; + } + + private void DxGridViewColumnFilterChanged(object sender, EventArgs e) + { + if (ColumnFilterChanged == null) + { + return; + } + + var selectedColumn = columns.OfType() + .FirstOrDefault(c => c.DxColumn == dxGridView.FocusedColumn); + + ColumnFilterChanged(sender, new EventArgs(selectedColumn)); + } + + private void DxGridViewCustomDrawRowIndicator(object sender, RowIndicatorCustomDrawEventArgs e) + { + if (!showRowNumbers) + { + return; + } + + // check whether the indicator cell belongs to a data row + if (e.Info.IsRowIndicator && e.RowHandle >= 0) + { + e.Info.DisplayText = (e.RowHandle + 1).ToString(CultureInfo.InvariantCulture); + e.Info.ImageIndex = -1; + e.Info.Appearance.TextOptions.HAlignment = HorzAlignment.Far; + + if (FocusedRowIndex == e.RowHandle) + { + e.Info.ImageIndex = 0; + } + } + } + + private void DxGridViewShowDxGridMenu(object sender, GridMenuEventArgs e) + { + bool first = true; + + if (e.MenuType == GridMenuType.Column) + { + TableViewColumn tableViewColumn = null; + + if (e.HitInfo.Column != null) //on a column + { + tableViewColumn = columns.FirstOrDefault(c => c.Caption == e.HitInfo.Column.GetTextCaption()); + } + + UpdateColumnHeaderMenu(e, tableViewColumn); + + foreach (var menuItem in ColumnMenuItems.Where(menuItem => menuItem.ShouldShow(tableViewColumn))) + { + if (first) + { + menuItem.InternalItem.BeginGroup = true; + first = false; + } + else + { + menuItem.InternalItem.BeginGroup = false; + } + + e.Menu.Items.Add(menuItem.InternalItem); + } + } + } + + private void DxGridView2RowCellStyle(object sender, RowCellStyleEventArgs e) + { + var selected = ((!RowSelect && dxGridView.IsCellSelected(e.RowHandle, e.Column)) || + (RowSelect && dxGridView.IsRowSelected(e.RowHandle))); + + if (DisplayCellFilter != null) + { + var tableViewCellStyle = new TableViewCellStyle(e.RowHandle, GetColumnByDxColumn(e.Column), selected) + { + ForeColor = e.Appearance.ForeColor, + BackColor = e.Appearance.BackColor + }; + + if (DisplayCellFilter(tableViewCellStyle)) + { + e.Appearance.ForeColor = tableViewCellStyle.ForeColor; + e.Appearance.BackColor = tableViewCellStyle.BackColor; + return; + } + } + + if (selected) + { + e.Appearance.ForeColor = Color.White; + e.Appearance.BackColor = SystemColors.Highlight; + return; + } + + var isReadOnly = CellIsReadOnly(e.RowHandle, GetColumnByDxColumn(e.Column)); + if (isReadOnly) + { + e.Appearance.ForeColor = ReadOnlyCellForeColor; + e.Appearance.BackColor = ReadOnlyCellBackColor; + } + + if (InvalidCellFilter == null) + { + return; + } + if (InvalidCellFilter(new TableViewCell(e.RowHandle, GetColumnByDxColumn(e.Column)))) + { + e.Appearance.BackColor = InvalidCellBackgroundColor; + } + } + + private void DxGridViewShownEditor(object sender, EventArgs e) + { + var view = sender as GridView; + if (view == null) + { + return; + } + + var textEditor = view.ActiveEditor as TextEdit; + if (f2Pressed && textEditor != null && textEditor.IsEditorActive) + { + textEditor.SelectionStart = textEditor.Text.Length; + } + + var buttonEditor = view.ActiveEditor as ButtonEdit; + if (buttonEditor != null) + { + buttonEditor.PerformClick(null); + } + + dxGridControl.EmbeddedNavigator.Buttons.Append.Enabled = AllowAddNewRow && !OnNewRow(); + + f2Pressed = false; + } + + private void DxGridViewShowingEditor(object sender, CancelEventArgs e) + { + var view = sender as GridView; + if (view == null) + { + return; + } + + e.Cancel = CellIsReadOnly(view.FocusedRowHandle, GetColumnByDxColumn(view.FocusedColumn)); + } + + private void DxGridControlProcessDxGridKey(object sender, KeyEventArgs e) + { + f2Pressed = e.KeyCode == Keys.F2; + + //TODO: get to switch like stament + if (((e.Shift) && (e.KeyCode == Keys.Insert)) || + ((e.Control) && (e.KeyCode == Keys.V))) + { + //paste the glipboard if we are not editing a cell + if ((dxGridView.OptionsBehavior.Editable) && (dxGridView.State != GridState.Editing)) + { + PasteClipboardContents(); + //we need to suppres ctrl + v for being passing to child + //controls. Others wise the column goes into an editing state + e.SuppressKeyPress = true; + e.Handled = true; + } + } + if (((e.Control) && (e.KeyCode == Keys.Insert)) || + ((e.Control) && (e.KeyCode == Keys.C))) + { + CopySelectionToClipboard(); + e.Handled = true; //prevent XtraGrid from doing another copy resulting in an exception + } + if ((e.KeyCode == Keys.Delete) && (dxGridView.State == GridState.Normal)) + { + DeleteCurrentSelection(); + } + + if (e.KeyCode == Keys.Enter && IsEndEditOnEnterKey && (dxGridView.IsEditing || OnNewRow())) + { + dxGridControl.EmbeddedNavigator.Buttons.DoClick(dxGridControl.EmbeddedNavigator.Buttons.EndEdit); + e.Handled = true; + e.SuppressKeyPress = true; + } + } + + private void DxGridViewFocusedColumnChanged(object sender, FocusedColumnChangedEventArgs e) + { + if (e.FocusedColumn != null && !dxGridView.Columns.Contains(e.FocusedColumn)) + { + // This is an awkward situation that can arise when a user clicks in the grid somewhere, after entering a value without Enter. + dxGridView.FocusedColumn = null; + } + + ShowEditorIfRowSelect(); + } + + private void DxGridViewClick(object sender, EventArgs e) + { + var gridHitInfo = dxGridView.CalcHitInfo(PointToClient(MousePosition)); + + if (gridHitInfo.Column != null && gridHitInfo.Column.ColumnEdit is RepositoryItemButtonEdit) + { + dxGridView.ShowEditor(); // Reduces the number of clicks needed to actually click buttons by one + } + + if (gridHitInfo.InColumn && (!gridHitInfo.InColumnPanel && RowSelect) && gridHitInfo.Column != null) + { + var columnIndex = gridHitInfo.Column.VisibleIndex; + if (((ModifierKeys & Keys.Control) == Keys.Control)) + { + if (!DeselectSelectCells(0, columnIndex, dxGridView.RowCount - 1, columnIndex)) + { + SelectCells(0, columnIndex, dxGridView.RowCount - 1, columnIndex, false); + } + } + else + { + SelectCells(0, columnIndex, dxGridView.RowCount - 1, columnIndex, true); + } + } + + //bubble click.. + OnClick(e); + } + + /// + /// Called when a cell value is validated and the new value is set to the current cell. + /// If the user presses CTRL+ENTER the new value is copied to all selected cells. This + /// mimics the behaviour in Excel XP. + /// TODO: when the user presses cancel after the CTRL+ENTER only the current cell is reset. + /// + private void DxGridViewCellValueChanged(object sender, CellValueChangedEventArgs e) + { + if (UserIsHoldingDownControlForCellFill()) + { + // temporarily disable value changed event + dxGridView.CellValueChanged -= DxGridViewCellValueChanged; + + try + { + if (cellsToFill == null) + { + return; + } + + foreach (GridCell gridcell in cellsToFill) + { + // only set new value to cell of same type + // todo add support for mixing double, float and int? + if (gridcell.Column.ColumnType == e.Value.GetType()) + { + dxGridView.SetRowCellValue(gridcell.RowHandle, gridcell.Column, e.Value); + } + } + } + finally + { + dxGridView.CellValueChanged += DxGridViewCellValueChanged; + cellsToFill = null; + } + } + if (CellChanged != null) + { + CellChanged(this, new EventArgs(new TableViewCell(e.RowHandle, GetColumnByDxColumn(e.Column)))); + } + } + + private bool UserIsHoldingDownControlForCellFill() + { + return MultipleCellEdit && ModifierKeys == Keys.Control && !isPasting; + } + + private void DxGridViewSelectionChanged(object sender, SelectionChangedEventArgs e) + { + if (!isSelectionChanging) + { + isSelectionChanging = true; + } + UpdateSelectionFromGridControl(); + } + + private void DxGridViewFocusedRowChanged(object sender, FocusedRowChangedEventArgs e) + { + if (FocusedRowChanged != null) + { + FocusedRowChanged(sender, EventArgs.Empty); + } + } + + private void DxGridViewCustomUnboundColumnData(object sender, CustomColumnDataEventArgs e) + { + if (UnboundColumnData == null) + { + return; + } + + var result = UnboundColumnData(e.Column.AbsoluteIndex, e.ListSourceRowIndex, e.IsGetData, e.IsSetData, e.Value); + if (result != null) + { + e.Value = result; + } + } + + private void DxGridViewMouseEnter(object sender, EventArgs e) + { + OnMouseEnter(e); + } + + private void DxGridViewMouseDown(object sender, MouseEventArgs e) + { + // Check edit single click when in cell select mode + // http://www1.devexpress.com/Support/Center/p/Q144046.aspx + if ((ModifierKeys & Keys.Control) != Keys.Control && (ModifierKeys & Keys.Shift) != Keys.Shift) + { + var hi = dxGridView.CalcHitInfo(e.Location); + if (hi.InRowCell && hi.Column.RealColumnEdit.GetType() == typeof(RepositoryItemCheckEdit)) + { + dxGridView.FocusedRowHandle = hi.RowHandle; + dxGridView.FocusedColumn = hi.Column; + dxGridView.ShowEditor(); + + // get active editor or create one (when cell is readonly and no ActiveEditor is set) + var checkEdit = (dxGridView.ActiveEditor ?? hi.Column.RealColumnEdit.CreateEditor()) as CheckEdit; + if (checkEdit != null) + { + var checkInfo = (CheckEditViewInfo) checkEdit.GetViewInfo(); + var glyphRect = checkInfo.CheckInfo.GlyphRect; + + var viewInfo = dxGridView.GetViewInfo() as GridViewInfo; + if (viewInfo != null) + { + var gridGlyphRect = new Rectangle(viewInfo.GetGridCellInfo(hi).Bounds.X + glyphRect.X, + viewInfo.GetGridCellInfo(hi).Bounds.Y + glyphRect.Y, + glyphRect.Width, + glyphRect.Height); + + dxGridView.ClearSelection(); + + if (!gridGlyphRect.Contains(e.Location)) + { + dxGridView.CloseEditor(); + if (!RowSelect) + { + if (!dxGridView.IsCellSelected(hi.RowHandle, hi.Column)) + { + dxGridView.SelectCell(hi.RowHandle, hi.Column); + } + else + { + dxGridView.UnselectCell(hi.RowHandle, hi.Column); + } + } + } + else + { + checkEdit.Checked = !checkEdit.Checked; + dxGridView.CloseEditor(); + } + + if (RowSelect) + { + dxGridView.SelectRow(hi.RowHandle); + } + } + } + + var dxMouseEventArgs = e as DXMouseEventArgs; + if (dxMouseEventArgs != null) + { + dxMouseEventArgs.Handled = true; + } + } + } + + HandleHeaderPanelButton(sender, e); + OnMouseDown(e); + } + + private void DxGridViewInvalidRowException(object sender, InvalidRowExceptionEventArgs e) + { + switch (ExceptionMode) + { + case ValidationExceptionMode.Ignore: + e.ExceptionMode = DevExpress.XtraEditors.Controls.ExceptionMode.Ignore; + break; + case ValidationExceptionMode.NoAction: + e.ExceptionMode = DevExpress.XtraEditors.Controls.ExceptionMode.NoAction; + break; + case ValidationExceptionMode.DisplayError: + e.ExceptionMode = DevExpress.XtraEditors.Controls.ExceptionMode.DisplayError; + break; + case ValidationExceptionMode.ThrowException: + e.ExceptionMode = DevExpress.XtraEditors.Controls.ExceptionMode.ThrowException; + break; + } + } + + private static void DxGridControlPreviewKeyDown(object sender, PreviewKeyDownEventArgs e) + { + if (e.KeyCode == Keys.Enter) + { + e.IsInputKey = true; //do no use special processing + } + } + + private void DxGridViewHiddenEditor(object sender, EventArgs e) + { + dxGridControl.EmbeddedNavigator.Buttons.Append.Enabled = AllowAddNewRow; + } + + private void OnDxGridViewOnFocusedRowChanged(object o, FocusedRowChangedEventArgs args) + { + DxGridViewFocusedRowChanged(o, args); + } + + #endregion + + #region Initialization functions + + private void ConfigureContextMenu() + { + var btnCopy = new ToolStripMenuItem + { + Name = "btnCopy", Image = Resources.CopyHS, Size = new Size(116, 22), Text = Resources.TableView_ConfigureContextMenu_Copy, Tag = "btnCopy" + }; + var btnPaste = new ToolStripMenuItem + { + Name = "btnPaste", Image = Resources.PasteHS, Size = new Size(116, 22), Text = Resources.TableView_ConfigureContextMenu_Paste, Tag = "btnPaste" + }; + var btnDelete = new ToolStripMenuItem + { + Name = "btnDelete", Image = Resources.DeleteHS1, Size = new Size(116, 22), Text = Resources.TableView_ConfigureContextMenu_Delete, Tag = "btnDelete" + }; + + btnCopy.Click += delegate { CopySelectionToClipboard(); }; + btnPaste.Click += delegate { PasteClipboardContents(); }; + btnDelete.Click += delegate { DeleteCurrentSelection(); }; + + var viewContextMenu = new ContextMenuStrip(); + viewContextMenu.Items.AddRange(new ToolStripItem[] + { + btnCopy, + btnPaste, + btnDelete + }); + + RowContextMenu = viewContextMenu; + } + + private void CreateRefreshTimer() + { + refreshTimer = new Timer(); + refreshTimer.Tick += OnRefreshTimerOnTick; + + refreshTimer.Interval = 300; + refreshTimer.Enabled = true; + refreshTimer.Start(); + } + + private void OnRefreshTimerOnTick(object sender, EventArgs e) + { + RefreshIfRequired(); + } + + private void SubscribeEvents() + { + // mouse events + dxGridView.Click += DxGridViewClick; + dxGridView.DoubleClick += DxGridViewDoubleClick; + dxGridView.MouseEnter += DxGridViewMouseEnter; + dxGridView.MouseDown += DxGridViewMouseDown; + + dxGridView.InvalidRowException += DxGridViewInvalidRowException; + + // keyboard events + dxGridControl.PreviewKeyDown += DxGridControlPreviewKeyDown; + dxGridControl.ProcessGridKey += DxGridControlProcessDxGridKey; + + // change of focus + dxGridView.FocusedRowChanged += OnDxGridViewOnFocusedRowChanged; + dxGridView.FocusedRowChanged += tableViewValidator.RowLostFocus; + dxGridView.FocusedColumnChanged += DxGridViewFocusedColumnChanged; + + // value changes + dxGridView.CellValueChanged += tableViewValidator.OnCellValueChanged; + dxGridView.CellValueChanged += DxGridViewCellValueChanged; + + // filtering events + dxGridView.ColumnFilterChanged += DxGridViewColumnFilterChanged; + + // drawing events + dxGridView.CustomDrawRowIndicator += DxGridViewCustomDrawRowIndicator; + dxGridView.CustomDrawCell += DxGridViewCustomDrawCell; + dxGridView.RowCellStyle += DxGridView2RowCellStyle; + + // editor events + dxGridView.ShowingEditor += DxGridViewShowingEditor; + dxGridView.ShownEditor += DxGridViewShownEditor; + dxGridView.HiddenEditor += tableViewValidator.HiddenEditor; + dxGridView.HiddenEditor += DxGridViewHiddenEditor; + + dxGridView.ValidatingEditor += (s, e) => + { + var cell = new TableViewCell(FocusedRowIndex, GetColumnByDxColumn(dxGridView.FocusedColumn)); + tableViewValidator.OnValidateCell(cell, e); + }; + dxGridControl.EditorKeyDown += DxGridControlEditorKeyDown; + + // selection events + dxGridView.SelectionChanged += DxGridViewSelectionChanged; + + dxGridView.ShowGridMenu += DxGridViewShowDxGridMenu; + dxGridView.ValidateRow += tableViewValidator.OnValidateRow; + dxGridControl.EmbeddedNavigator.ButtonClick += EmbeddedNavigatorButtonClick; + + PasteController.PasteFailed += CopyPasteControllerPasteFailed; + } + + #endregion + } +} \ No newline at end of file Index: Core/Common/src/Core.Common.Controls.Table/TableView.resx =================================================================== diff -u --- Core/Common/src/Core.Common.Controls.Table/TableView.resx (revision 0) +++ Core/Common/src/Core.Common.Controls.Table/TableView.resx (revision 46f5191a65faec434930a191e65f4c23d9ff8cfe) @@ -0,0 +1,120 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file Index: Core/Common/src/Core.Common.Controls.Table/TableViewCell.cs =================================================================== diff -u --- Core/Common/src/Core.Common.Controls.Table/TableViewCell.cs (revision 0) +++ Core/Common/src/Core.Common.Controls.Table/TableViewCell.cs (revision 46f5191a65faec434930a191e65f4c23d9ff8cfe) @@ -0,0 +1,21 @@ +namespace Core.Common.Controls.Table +{ + public class TableViewCell + { + public TableViewCell(int rowIndex, TableViewColumn column) + { + RowIndex = rowIndex; + Column = column; + } + + /// + /// Row index of the cell + /// + public int RowIndex { get; set; } + + /// + /// Column of the cell + /// + public TableViewColumn Column { get; set; } + } +} \ No newline at end of file Index: Core/Common/src/Core.Common.Controls.Table/TableViewCellFormatterProvider.cs =================================================================== diff -u --- Core/Common/src/Core.Common.Controls.Table/TableViewCellFormatterProvider.cs (revision 0) +++ Core/Common/src/Core.Common.Controls.Table/TableViewCellFormatterProvider.cs (revision 46f5191a65faec434930a191e65f4c23d9ff8cfe) @@ -0,0 +1,31 @@ +using System; + +namespace Core.Common.Controls.Table +{ + /// + /// Wrapper for ICustomFormatter, so that IFormatProvider won't have to be implemented. + /// http://documentation.devexpress.com/#WindowsForms/CustomDocument3045 + /// + public class TableViewCellFormatterProvider : IFormatProvider + { + private readonly ICustomFormatter formatter; + + public TableViewCellFormatterProvider(ICustomFormatter formatter) + { + this.formatter = formatter; + } + + /// + /// Returns an object that provides formatting services for the specified type. + /// + /// + /// An instance of the object specified by , + /// if the implementation can supply that type of object; otherwise, null. + /// + /// An object that specifies the type of format object to return. + public object GetFormat(Type formatType) + { + return formatter; + } + } +} \ No newline at end of file Index: Core/Common/src/Core.Common.Controls.Table/TableViewCellStyle.cs =================================================================== diff -u --- Core/Common/src/Core.Common.Controls.Table/TableViewCellStyle.cs (revision 0) +++ Core/Common/src/Core.Common.Controls.Table/TableViewCellStyle.cs (revision 46f5191a65faec434930a191e65f4c23d9ff8cfe) @@ -0,0 +1,18 @@ +using System.Drawing; + +namespace Core.Common.Controls.Table +{ + public class TableViewCellStyle : TableViewCell + { + public TableViewCellStyle(int rowIndex, TableViewColumn column, bool selected) : base(rowIndex, column) + { + Selected = selected; + } + + public Color ForeColor { get; set; } + + public Color BackColor { get; set; } + + public bool Selected { get; private set; } + } +} \ No newline at end of file Index: Core/Common/src/Core.Common.Controls.Table/TableViewColumn.cs =================================================================== diff -u --- Core/Common/src/Core.Common.Controls.Table/TableViewColumn.cs (revision 0) +++ Core/Common/src/Core.Common.Controls.Table/TableViewColumn.cs (revision 46f5191a65faec434930a191e65f4c23d9ff8cfe) @@ -0,0 +1,410 @@ +using System; +using System.Drawing; +using System.Linq; +using System.Windows.Forms; +using Core.Common.Controls.Table.Properties; +using DevExpress.Data; +using DevExpress.Utils; +using DevExpress.XtraGrid; +using DevExpress.XtraGrid.Columns; +using DevExpress.XtraGrid.Views.Grid; + +namespace Core.Common.Controls.Table +{ + public class TableViewColumn + { + private readonly GridView dxGridView; + private readonly GridColumn dxColumn; + private readonly TableView tableView; + private readonly GridControl dxGridControl; + private Editors.ITypeEditor editor; + + private string displayFormat = ""; + private int visibleIndex; + private ICustomFormatter customFormatter; + + public TableViewColumn(GridView view, GridControl control, GridColumn column, TableView tableView, bool unbound) + { + dxGridView = view; + dxGridControl = control; + dxColumn = column; + this.tableView = tableView; + IsUnbound = unbound; + + dxColumn.FilterMode = dxColumn.ColumnType == typeof(DateTime) || + dxColumn.ColumnType == typeof(double) || + dxColumn.ColumnType == typeof(int) + ? ColumnFilterMode.Value + : ColumnFilterMode.DisplayText; + dxColumn.OptionsColumn.AllowMove = false; + } + + public bool FilteringAllowed + { + get + { + return dxColumn.OptionsFilter.AllowFilter; + } + set + { + dxColumn.OptionsFilter.AllowFilter = value; + } + } + + /// + /// The name of the column + /// + public string Name + { + // XtraGrid prefixes the Name with a "col", we need the FieldName for DataBinding + get + { + return dxColumn.FieldName; + } + } + + public string Caption + { + get + { + return dxColumn.GetCaption(); + } //get actual displayed value + set + { + dxColumn.Caption = value; + } //set custom value + } + + public int DisplayIndex + { + get + { + return dxColumn.VisibleIndex; + } + set + { + dxColumn.VisibleIndex = value; + } + } + + public object DefaultValue { get; set; } + + public bool IsUnbound { get; private set; } + + /// + /// Index of the column in column collection of the gridview. + /// This collection includes invisible columns etc + /// + public int AbsoluteIndex + { + get + { + return dxColumn.AbsoluteIndex; + } + set + { + dxColumn.AbsoluteIndex = value; + } + } + + /// + /// Allows to override the way cell text is rendered. + /// + /// Will reset + /// + public ICustomFormatter CustomFormatter + { + get + { + return customFormatter; + } + set + { + customFormatter = value; + + SetXtraGridCustomFormatterCore(dxColumn.DisplayFormat, value); + if (dxColumn.ColumnEdit != null) + { + SetXtraGridCustomFormatterCore(dxColumn.ColumnEdit.DisplayFormat, value); + } + } + } + + /// + /// Sets the displayformat of the column. For example c2, D or AA{0} + /// If CustomFormatter is used then this property is skipped. + /// + public string DisplayFormat + { + get + { + return displayFormat; + } + set + { + displayFormat = value; + SetXtraGridDisplayFormat(value); + } + } + + public bool Pinned + { + get + { + return dxColumn.Fixed == FixedStyle.Left; + } + set + { + dxColumn.Fixed = (value ? FixedStyle.Left : FixedStyle.None); + if (!Pinned) + { + // Restore original display index + var unPinnedColumns = tableView.Columns.Where(c => !c.Pinned).ToList(); + var columnToTheLeft = unPinnedColumns.LastOrDefault(c => c.AbsoluteIndex < AbsoluteIndex); + DisplayIndex = columnToTheLeft != null + ? columnToTheLeft.DisplayIndex + 1 + : tableView.Columns.Count - unPinnedColumns.Count; + } + } + } + + /// + /// The visibility of the column + /// + public bool Visible + { + get + { + return dxColumn.Visible; + } + set + { + dxColumn.Visible = value; + // Table BestFitColumns ignores columns with AllowSize set to false; It does noet use the visible + // property. For best performance disable AllowSize if column is hidden. + dxColumn.OptionsColumn.AllowSize = dxColumn.Visible; + if (!value) + { + // remember old column index + if (dxColumn.VisibleIndex != -1) + { + visibleIndex = dxColumn.VisibleIndex; + } + dxColumn.VisibleIndex = -1; + } + else + { + dxColumn.VisibleIndex = visibleIndex; + } + } + } + + public Editors.ITypeEditor Editor + { + get + { + return editor; + } + set + { + if (value == null) + { + return; + } + + editor = value; + + var repositoryItem = XtraGridRepositoryItemBuilder.CreateFromTypeEditor(editor, dxGridControl, dxColumn, Caption); + dxGridControl.RepositoryItems.Add(repositoryItem); + dxColumn.ColumnEdit = repositoryItem; + } + } + + public int Width + { + get + { + return dxColumn.Width; + } + set + { + dxColumn.Width = value; + } + } + + public bool SortingAllowed + { + get + { + return dxColumn.OptionsColumn.AllowSort != DefaultBoolean.False; + } + set + { + dxColumn.OptionsColumn.AllowSort = (value) ? DefaultBoolean.True : DefaultBoolean.False; + } + } + + /// + /// Get or set column filter. Use a syntax like "[Naam] = 'kees'" + /// + public string FilterString + { + get + { + return dxColumn.FilterInfo.FilterString; + } + set + { + dxColumn.FilterInfo = new ColumnFilterInfo(value); + } + } + + /// + /// Set the column sortorder. + /// + public SortOrder SortOrder + { + get + { + //some conversion between sortorders :( + //who needs more?? + switch (dxColumn.SortOrder) + { + case ColumnSortOrder.Ascending: + return SortOrder.Ascending; + case ColumnSortOrder.Descending: + return SortOrder.Descending; + default: + return SortOrder.None; + } + } + set + { + switch (value) + { + case SortOrder.None: + dxColumn.SortOrder = ColumnSortOrder.None; + break; + case SortOrder.Ascending: + dxColumn.SortOrder = ColumnSortOrder.Ascending; + break; + case SortOrder.Descending: + dxColumn.SortOrder = ColumnSortOrder.Descending; + break; + } + } + } + + public Type ColumnType + { + get + { + var type = typeof(object); + try + { + if (dxColumn.ColumnHandle != -1) + { + type = dxColumn.ColumnType; + } + } + catch (NullReferenceException) + { + //gulp: can throw nullreference exception for some reason + } + return type; + } + } + + public string ToolTip + { + get + { + return dxColumn.ToolTip; + } + set + { + dxColumn.ToolTip = value; + } + } + + public bool ReadOnly + { + get + { + return dxColumn.OptionsColumn.ReadOnly; + } + set + { + dxColumn.OptionsColumn.AllowEdit = !value; // false; + dxColumn.OptionsColumn.ReadOnly = value; + //copy readonly style from tableview + if (dxColumn.OptionsColumn.ReadOnly) + { + dxColumn.AppearanceCell.ForeColor = tableView.ReadOnlyCellForeColor; + dxColumn.AppearanceCell.BackColor = tableView.ReadOnlyCellBackColor; + } + else + { + //reset to defaults + dxColumn.AppearanceCell.ForeColor = Color.Empty; + //'empty' + dxColumn.AppearanceCell.BackColor = Color.Empty; + // dxColumn.AppearanceCell.BackColor = Color.White; + } + } + } + + public void Dispose() + { + if (editor != null) + { + editor.Dispose(); + } + } + + internal GridColumn DxColumn + { + get + { + return dxColumn; + } + } + + private void SetXtraGridDisplayFormat(string value) + { + SetXtraGridDisplayFormatCore(dxColumn.DisplayFormat, value); + if (dxColumn.ColumnEdit != null) + { + SetXtraGridDisplayFormatCore(dxColumn.ColumnEdit.DisplayFormat, value); + } + } + + private void SetXtraGridDisplayFormatCore(FormatInfo dxFormatInfo, string value) + { + dxFormatInfo.FormatType = GetFormatType(value); + dxFormatInfo.FormatString = value; + } + + private static void SetXtraGridCustomFormatterCore(FormatInfo dxFormatInfo, ICustomFormatter value) + { + if (value == null) + { + dxFormatInfo.FormatType = FormatType.None; + return; + } + + dxFormatInfo.FormatType = FormatType.Custom; + dxFormatInfo.Format = new TableViewCellFormatterProvider(value); + dxFormatInfo.FormatString = Resources.TableViewColumn_SetXtraGridCustomFormatterCore_custom; //must be non null/empty for custom formatting to work + } + + private FormatType GetFormatType(string value) + { + return string.IsNullOrEmpty(value) + ? FormatType.None + : (ColumnType == typeof(DateTime) + ? FormatType.DateTime + : FormatType.Numeric); + } + } +} \ No newline at end of file Index: Core/Common/src/Core.Common.Controls.Table/TableViewColumnMenuItem.cs =================================================================== diff -u --- Core/Common/src/Core.Common.Controls.Table/TableViewColumnMenuItem.cs (revision 0) +++ Core/Common/src/Core.Common.Controls.Table/TableViewColumnMenuItem.cs (revision 46f5191a65faec434930a191e65f4c23d9ff8cfe) @@ -0,0 +1,72 @@ +using System; +using System.ComponentModel; +using System.Drawing; +using DevExpress.Utils.Menu; + +namespace Core.Common.Controls.Table +{ + public class TableViewColumnMenuItem + { + public event EventHandler Click; + + public event CancelEventHandler Showing; + private readonly DXMenuItem internalItem; + + public TableViewColumnMenuItem(string caption) + { + internalItem = new DXMenuItem(caption); + internalItem.Click += InternalItemClick; + } + + public DXMenuItem InternalItem + { + get + { + return internalItem; + } + } + + public string Caption + { + get + { + return internalItem.Caption; + } + } + + public Image Image + { + get + { + return internalItem.Image; + } + set + { + internalItem.Image = value; + } + } + + public bool ShouldShow(TableViewColumn column) + { + if (Showing != null) + { + var args = new CancelEventArgs(); + Showing(column, args); + if (args.Cancel) + { + return false; + } + } + internalItem.Tag = column; + return true; + } + + private void InternalItemClick(object sender, EventArgs e) + { + if (Click != null) + { + Click(internalItem.Tag, e); + } + } + } +} \ No newline at end of file Index: Core/Common/src/Core.Common.Controls.Table/TableViewComboBoxItem.cs =================================================================== diff -u --- Core/Common/src/Core.Common.Controls.Table/TableViewComboBoxItem.cs (revision 0) +++ Core/Common/src/Core.Common.Controls.Table/TableViewComboBoxItem.cs (revision 46f5191a65faec434930a191e65f4c23d9ff8cfe) @@ -0,0 +1,119 @@ +using System; +using Core.Common.Utils; + +namespace Core.Common.Controls.Table +{ + public class TableViewComboBoxItem : IConvertible + { + public object Value { get; set; } + + public string DisplayText + { + get + { + if (CustomFormatter != null) + { + return CustomFormatter.Format(null, Value, null); + } + + return Value.ToString(); + } + } + + public ICustomFormatter CustomFormatter { get; set; } + + public override string ToString() + { + return Value != null ? Value.ToString() : "null"; + } + + #region Implementation of IConvertible + + public TypeCode GetTypeCode() + { + return TypeCode.String; + } + + public bool ToBoolean(IFormatProvider provider) + { + throw new NotImplementedException(); + } + + public char ToChar(IFormatProvider provider) + { + throw new NotImplementedException(); + } + + public sbyte ToSByte(IFormatProvider provider) + { + throw new NotImplementedException(); + } + + public byte ToByte(IFormatProvider provider) + { + throw new NotImplementedException(); + } + + public short ToInt16(IFormatProvider provider) + { + throw new NotImplementedException(); + } + + public ushort ToUInt16(IFormatProvider provider) + { + throw new NotImplementedException(); + } + + public int ToInt32(IFormatProvider provider) + { + throw new NotImplementedException(); + } + + public uint ToUInt32(IFormatProvider provider) + { + throw new NotImplementedException(); + } + + public long ToInt64(IFormatProvider provider) + { + throw new NotImplementedException(); + } + + public ulong ToUInt64(IFormatProvider provider) + { + throw new NotImplementedException(); + } + + public float ToSingle(IFormatProvider provider) + { + throw new NotImplementedException(); + } + + public double ToDouble(IFormatProvider provider) + { + throw new NotImplementedException(); + } + + public decimal ToDecimal(IFormatProvider provider) + { + throw new NotImplementedException(); + } + + public DateTime ToDateTime(IFormatProvider provider) + { + throw new NotImplementedException(); + } + + public string ToString(IFormatProvider provider) + { + return ToString(); + } + + public object ToType(Type conversionType, IFormatProvider provider) + { + return Value; + } + + #endregion + } +} \ No newline at end of file Index: Core/Common/src/Core.Common.Controls.Table/TableViewExceptionMessageController.cs =================================================================== diff -u --- Core/Common/src/Core.Common.Controls.Table/TableViewExceptionMessageController.cs (revision 0) +++ Core/Common/src/Core.Common.Controls.Table/TableViewExceptionMessageController.cs (revision 46f5191a65faec434930a191e65f4c23d9ff8cfe) @@ -0,0 +1,15 @@ +using Core.Common.Controls.Table.Properties; +using DevExpress.XtraGrid.Localization; + +namespace Core.Common.Controls.Table +{ + public class TableViewExceptionMessageController : GridLocalizer + { + public override string GetLocalizedString(GridStringId id) + { + return id == GridStringId.ColumnViewExceptionMessage + ? Resources.TableViewExceptionMessageController_GetLocalizedString + : base.GetLocalizedString(id); + } + } +} \ No newline at end of file Index: Core/Common/src/Core.Common.Controls.Table/TableViewPasteBehaviourOptions.cs =================================================================== diff -u --- Core/Common/src/Core.Common.Controls.Table/TableViewPasteBehaviourOptions.cs (revision 0) +++ Core/Common/src/Core.Common.Controls.Table/TableViewPasteBehaviourOptions.cs (revision 46f5191a65faec434930a191e65f4c23d9ff8cfe) @@ -0,0 +1,8 @@ +namespace Core.Common.Controls.Table +{ + public enum TableViewPasteBehaviourOptions + { + SkipCellWhenValueIsInvalid, + SkipRowWhenValueIsInvalid + } +} \ No newline at end of file Index: Core/Common/src/Core.Common.Controls.Table/TableViewPasteController.cs =================================================================== diff -u --- Core/Common/src/Core.Common.Controls.Table/TableViewPasteController.cs (revision 0) +++ Core/Common/src/Core.Common.Controls.Table/TableViewPasteController.cs (revision 46f5191a65faec434930a191e65f4c23d9ff8cfe) @@ -0,0 +1,541 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Windows.Forms; +using Core.Common.Controls.Table.Properties; +using Core.Common.Utils.Events; + +using log4net; + +namespace Core.Common.Controls.Table +{ + /// + /// Class add copy paste functionality to a tableview. Based on ITableView + /// + public class TableViewPasteController + { + public event EventHandler> PasteFailed; + + public event EventHandler PasteFinished; + + private const int NewRowSelectedIndex = int.MinValue + 1; + private static readonly ILog Log = LogManager.GetLogger(typeof(TableViewPasteController)); + + public TableViewPasteController(TableView tableView) + { + TableView = tableView; + PastedRows = new List(); + PastedBlocks = new List(); + } + + /// + /// Gets or sets the paste behaviour value + /// + public TableViewPasteBehaviourOptions PasteBehaviour { get; set; } + + public bool IsPasting { get; private set; } + + /// + /// This method does most of the work. It Pastes Clipboard content to the XtraGrid. + /// If OptionsSelection.EnableAppearanceFocusedRow == true then it will paste row (if + /// any row is present in the clipboard) to the currently selected row. It will not + /// replace Readonly or Not Editable Fields as well as key fields for the child tables + /// and details. It works not on the XtraGrid level but on the DataTable level. + /// If the currently selected row in the XtraGrid is the New Row then it will populate + /// it with the values from the row in the Clipboard. + /// + public void PasteClipboardContents() + { + // for now only allow to paste text + if (!Clipboard.ContainsText()) + { + Log.Debug(Resources.TableViewPasteController_PasteClipboardContents_Clipboard_does_not_contain_text_so_it_cannot_be_pasted_to_the_grid); + return; + } + + string[] clipboardLines = GetClipboardLines(); + //nothing to paste. + if (clipboardLines.Length == 0) + { + return; + } + + PasteLines(clipboardLines); + } + + /// + /// Paste value string into tableview at current selection + /// + /// + public void PasteLines(string[] lines) + { + IsPasting = true; + + lines = RemoveHeaderIfPresent(lines); + + //get the selection in which we are to paste + var targetSelection = GetPasteTargetSelection(); + //check if we can paste or fail + string message; + if (!CanPaste(lines, out message)) + { + OnPasteFailed(message); + + IsPasting = false; + + return; //don't paste + } + + //pastevalues returns the pasted selection + + var tableViewImpl = TableView as TableView; + + if (tableViewImpl != null) + { + tableViewImpl.BeginInit(); + } + + PastedRows.Clear(); + PastedBlocks.Clear(); + + PasteValues(lines, targetSelection, (!TableView.IsSorted()) && (TableView.AllowAddNewRow)); + + if (tableViewImpl != null) + { + tableViewImpl.EndInit(); + } + + SetSelection(); + + PastedRows.Clear(); + PastedBlocks.Clear(); + + IsPasting = false; + + OnPasteFinished(); + } + + protected TableView TableView { get; private set; } + protected List PastedBlocks { private get; set; } + + /// + /// Overload without message parameter. + /// + /// + protected RectangleSelection GetPasteTargetSelection() + { + string message; + return GetPasteTargetSelection(out message); + } + + /// + /// Gets the target selection from tableview or raises paste failed event in case + /// the target selection is invalid (non-rectangular) + /// + /// + protected RectangleSelection GetPasteTargetSelection(out string errorMessage) + { + errorMessage = ""; + + var topLeft = new TableViewCell(0, null); + //in RowSelect don't used selected cells because they don't work + if (TableView.RowSelect) + { + return GetRowSelectSelection(); + } + + var cells = TableView.SelectedCells.ToList(); + if (cells.Count == 0) + { + //base selection on focused cell + var focusedCell = TableView.GetFocusedCell(); + if (focusedCell != null) + { + return new RectangleSelection(focusedCell, focusedCell); + } + //no focused cell must mean empty table..start pasting left,top + return new RectangleSelection(topLeft, topLeft); + } + + //return a selection based on the first and last cell in the selection. Tricky..should check the most upper etc.. + RectangleSelection selection = GetRectangleSelection(cells); + + if (selection == null) + { + errorMessage = Resources.TableViewPasteController_GetPasteTargetSelection_Cannot_paste_into_non_rectangular_selection; + } + + return selection; + } + + protected RectangleSelection GetRowSelectSelection() + { + var selectedRows = TableView.SelectedRowsIndices; + var topLeft = selectedRows.Length == 0 + ? new TableViewCell(TableView.RowCount, TableView.GetColumnByDisplayIndex(0)) + : new TableViewCell(selectedRows[0], TableView.GetColumnByDisplayIndex(0)); + + return new RectangleSelection(topLeft, topLeft); + } + + /// + /// Returns rectangle for a collection of cells. Or null if cells don't make up a rectangle + /// + /// + /// + protected RectangleSelection GetRectangleSelection(IList cells) + { + int left = cells.Min(cell => cell.Column.DisplayIndex); + int right = cells.Max(cell => cell.Column.DisplayIndex); + int top = cells.Min(cell => cell.RowIndex); + int bottom = cells.Max(cell => cell.RowIndex); + + //if the selection is on 'new' row change to rowcount.. + if ((bottom == NewRowSelectedIndex) && (top == NewRowSelectedIndex)) + { + bottom = TableView.RowCount; + top = TableView.RowCount; + } + //do a check if we have enought cells... + if (cells.Count != (right + 1 - left)*(bottom + 1 - top)) + { + return null; + } + + return new RectangleSelection(new TableViewCell(top, TableView.GetColumnByDisplayIndex(left)), new TableViewCell(bottom, TableView.GetColumnByDisplayIndex(right))); + } + + /// + /// Checks whether the target tableView is filtered or the target selection contains a sorted column + /// + /// + /// + /// + protected virtual bool CanPaste(string[] clipboardLines, out string errorMessage) + { + //get a targetselection. Can fail if target is non square. Then error message is filled + var targetSelection = GetPasteTargetSelection(out errorMessage); + if (targetSelection == null) + { + return false; + } + + if (clipboardLines.Length == 0) + { + errorMessage = Resources.TableViewPasteController_CanPaste_There_are_no_values_to_paste_Headers_are_skipped; + return false; + } + + //how many columns do if hit when we paste? + var pasteColumnSpan = SplitToCells(clipboardLines[0]).Length; + + int[] pastedColumnIndexes = Enumerable.Range(targetSelection.Left, pasteColumnSpan).ToArray(); + + //is there sorted column in our pasted columns? + var sortedColumnExists = (from col in TableView.Columns + where col.SortOrder != SortOrder.None && pastedColumnIndexes.Contains(col.DisplayIndex) + select col).Any(); + if (sortedColumnExists) + { + errorMessage = Resources.TableViewPasteController_CanPaste_Cannot_paste_into_sorted_column; //todo: add name of column here? + return false; + } + if (TableView.Columns.Any(col => !string.IsNullOrEmpty(col.FilterString))) + { + errorMessage = Resources.TableViewPasteController_CanPaste_Cannot_paste_into_filtered_tableview; //todo: add name of column here? + return false; + } + return true; + } + + /// + /// Pastes values into target selection. + /// + protected virtual void PasteValues(string[] clipboardLines, RectangleSelection targetSelection, + bool allowNewRows, bool wrapInEditAction = true) + { + if (wrapInEditAction) + { + PasteValuesCore(clipboardLines, targetSelection, allowNewRows); + } + else + { + PasteValuesCore(clipboardLines, targetSelection, allowNewRows); + } + } + + /// + /// Pastes the given contents to the table at row startRowIndex, increasing the number of rows if necessary and allowed. + /// + /// The row index at which the pasting effectively occured, -1 if no pasting was done. + protected int PasteCellsToRow(string[] content, int startRowIndex, int startColumnIndex, int pasteWidth, bool addNewRow, bool cellBased) + { + var index = startRowIndex; + if (addNewRow) + { + TableView.AddNewRowToDataSource(); + } + else + { + if (startRowIndex >= TableView.RowCount) + { + return -1; + } + } + var exceptionMode = TableView.ExceptionMode; + TableView.ExceptionMode = TableView.ValidationExceptionMode.ThrowException; //throw exception + try + { + if (cellBased) + { + var contentWidth = content.Length; + for (var i = 0; i < pasteWidth; i++) + { + if (!SafeSetCellValue(index, startColumnIndex + i, content[i%contentWidth])) + { + Log.ErrorFormat(Resources.TableViewPasteController_PasteCellsToRow_Can_not_paste_value_into_cell_0_1_Row_0_will_be_skipped, + startRowIndex, startColumnIndex + i); + if (addNewRow) + { + TableView.SelectRow(index); + TableView.DeleteCurrentSelection(); + } + return -1; + } + } + UpdatePastedBlocks(startColumnIndex, pasteWidth, index); + } + else + { + var contentWidth = content.Length; + var values = new List(); + for (var i = 0; i < pasteWidth; i++) + { + values.Add(content[i%contentWidth]); + } + if (!SafeSetRowCellValues(index, startColumnIndex, values)) + { + Log.ErrorFormat(Resources.TableViewPasteController_PasteCellsToRow_Skipping_invalid_row_0_from_pasting, + startRowIndex); + if (addNewRow) + { + TableView.SelectRow(index); + TableView.DeleteCurrentSelection(); + } + return -1; + } + PastedRows.Add(index); + } + } + catch (Exception e) + { + Log.ErrorFormat(Resources.TableViewPasteController_PasteCellsToRow_Pasting_values_failed_0_, e.Message); + } + finally + { + TableView.ExceptionMode = exceptionMode; + } + return index; + } + + protected static string[] SplitToCells(string p) + { + //tab delimited data: excel, and xtragrid copy (todo think about how to implement pasting of space delimited data) + return p.Split(new[] + { + "\t" + }, StringSplitOptions.None); + } + + private List PastedRows { get; set; } + + private string[] RemoveHeaderIfPresent(string[] lines) + { + if (lines.Length > 0 && string.Equals(lines[0], GetTableHeaderString())) + { + return lines.Skip(1).ToArray(); //skip header + } + return lines; + } + + private string GetTableHeaderString() + { + //The function xtragrid uses to get the header string is protected and uses dxColumn.GetTextCaption(), + //which may differ from dxColumn.GetCaption we use. In those cases this may break. Also if the ordering + //of columns is out of sync (can that happen?) + return String.Join("\t", TableView.Columns.Where(c => c.Visible).Select(c => c.Caption).ToArray()); + } + + private void OnPasteFailed(string message) + { + Log.Warn(message); + + if (PasteFailed != null) + { + PasteFailed(this, new EventArgs(message)); + } + } + + private void OnPasteFinished() + { + if (PasteFinished != null) + { + PasteFinished(this, new EventArgs()); + } + } + + private void PasteValuesCore(string[] clipboardLines, RectangleSelection targetSelection, bool allowNewRows) + { + var startRowIndex = targetSelection.Top; + var startColumnIndex = targetSelection.Left; + if (startRowIndex < 0) + { + throw new ArgumentException(string.Format(Resources.TableViewPasteController_PasteValuesCore_Invalid_row_number_0_, startRowIndex), + "targetSelection"); + } + + //paste all the lines once... + int lastRowIndex = Math.Max(startRowIndex + clipboardLines.Length - 1, targetSelection.Bottom); + + int currentClipBoardLineIndex = 0; + int canceledNewRows = 0; + for (int j = startRowIndex; j <= lastRowIndex; j++) + { + string[] cols = SplitToCells(clipboardLines[currentClipBoardLineIndex]); + //Simply set values as text. + var pasteWidth = Math.Max(cols.Length, targetSelection.Right - targetSelection.Left + 1); + //paste cannot be wider than tablewidth - startColumnIndex + pasteWidth = Math.Min(pasteWidth, TableView.Columns.Count(c => c.Visible) - startColumnIndex); + + //do the pasting + bool checkCells = (PasteBehaviour == TableViewPasteBehaviourOptions.SkipRowWhenValueIsInvalid); + bool addNewRow = allowNewRows && (j >= TableView.RowCount); + var pasteStartRowIndex = j - canceledNewRows; + + var pasteResult = PasteCellsToRow(cols, pasteStartRowIndex, startColumnIndex, pasteWidth, addNewRow, + checkCells); + + if (addNewRow && pasteResult == -1) + { + canceledNewRows++; + } + + //update clipboard line index..loop + currentClipBoardLineIndex++; + if (currentClipBoardLineIndex == clipboardLines.Length) + { + //break;//do really want repeat data like below? + currentClipBoardLineIndex = 0; + } + } + } + + private bool SafeSetRowCellValues(int index, int startColumnIndex, List values) + { + try + { + return TableView.SetRowCellValues(index, startColumnIndex, values.ToArray()); + } + catch (Exception e) + { + Log.ErrorFormat(Resources.TableViewPasteController_SafeSetCellValue_Invalid_row_reason_0_, e.Message); + return false; + } + } + + private bool SafeSetCellValue(int index, int columnIndex, string value) + { + try + { + return TableView.SetCellValue(index, columnIndex, value); + } + catch (Exception e) + { + Log.ErrorFormat(Resources.TableViewPasteController_SafeSetCellValue_Invalid_row_reason_0_, e.Message); + return false; + } + } + + private void UpdatePastedBlocks(int startColumnIndex, int pasteWidth, int index) + { + var topLeftCell = new TableViewCell(index, TableView.GetColumnByDisplayIndex(startColumnIndex)); + var bottomRightCell = new TableViewCell(index, TableView.GetColumnByDisplayIndex(startColumnIndex + pasteWidth - 1)); + if (PastedBlocks.Count == 0) + { + PastedBlocks.Add(new RectangleSelection(topLeftCell, bottomRightCell)); + } + else + { + // if we can extend a rectangular block, do it... + var selectBlock = PastedBlocks.Where(b => b.Bottom + 1 == index); + if (selectBlock.Any()) + { + selectBlock.First().Bottom++; + } + else + { + PastedBlocks.Add(new RectangleSelection(topLeftCell, bottomRightCell)); + } + } + } + + private void SetSelection() + { + if (PastedRows.Count != 0) + { + TableView.ClearSelection(); + TableView.SelectRows(PastedRows.ToArray()); + } + + if (PastedBlocks.Count != 0) + { + TableView.ClearSelection(); + foreach (var selection in PastedBlocks) + { + TableView.SelectCells(selection.Top, selection.Left, selection.Bottom, selection.Right, false); + } + } + } + + private static string[] GetClipboardLines() + { + var strPasteText = Clipboard.GetText(); + var lines = strPasteText.Split(new[] + { + "\r\n" + }, StringSplitOptions.None); + return RemoveLastLineIfEmpty(lines); + } + + private static string[] RemoveLastLineIfEmpty(string[] lines) + { + if (lines[lines.Length - 1] == "") + { + return lines.ToList().Take(lines.Length - 1).ToArray(); + } + return lines; + } + + /// + /// Rectangular selection on a tableview. + /// + protected class RectangleSelection + { + public RectangleSelection(TableViewCell topLeft, TableViewCell bottomRight) + { + Top = topLeft.RowIndex; + Left = topLeft.Column == null ? 0 : topLeft.Column.DisplayIndex; + Bottom = bottomRight.RowIndex; + Right = bottomRight.Column == null ? 0 : bottomRight.Column.DisplayIndex; + } + + public int Top { get; set; } + + public int Left { get; set; } + + public int Bottom { get; set; } + + public int Right { get; set; } + } + } +} \ No newline at end of file Index: Core/Common/src/Core.Common.Controls.Table/Validation/RowValidationResult.cs =================================================================== diff -u --- Core/Common/src/Core.Common.Controls.Table/Validation/RowValidationResult.cs (revision 0) +++ Core/Common/src/Core.Common.Controls.Table/Validation/RowValidationResult.cs (revision 46f5191a65faec434930a191e65f4c23d9ff8cfe) @@ -0,0 +1,23 @@ +using System; + +namespace Core.Common.Controls.Table.Validation +{ + public class RowValidationResult + { + public RowValidationResult(string errorText) : this(-1, errorText) //-1 = no specific column, row error + {} + + public RowValidationResult(int columnIndex, string errorText) + { + ColumnIndex = columnIndex; + ErrorText = errorText; + Valid = String.IsNullOrEmpty(ErrorText); + } + + public int ColumnIndex { get; private set; } + + public string ErrorText { get; private set; } + + public bool Valid { get; private set; } + } +} \ No newline at end of file Index: Core/Common/src/Core.Common.Controls.Table/Validation/TableViewValidator.cs =================================================================== diff -u --- Core/Common/src/Core.Common.Controls.Table/Validation/TableViewValidator.cs (revision 0) +++ Core/Common/src/Core.Common.Controls.Table/Validation/TableViewValidator.cs (revision 46f5191a65faec434930a191e65f4c23d9ff8cfe) @@ -0,0 +1,172 @@ +using System; +using System.Linq; +using Core.Common.Controls.Table.Properties; +using DevExpress.XtraEditors.Controls; +using DevExpress.XtraGrid.Views.Base; +using DevExpress.XtraGrid.Views.Grid; + +namespace Core.Common.Controls.Table.Validation +{ + public class TableViewValidator + { + private readonly TableView tableView; + + private object[] originalRowValues; + private bool editingRow; + private int currentRowIndex; + + public TableViewValidator(TableView tableView) + { + this.tableView = tableView; + AutoValidation = true; + } + + public bool ValidateRow(int rowIndex, out string firstError) + { + firstError = ""; + BeginEditRow(rowIndex); + + if (tableView.RowValidator != null) + { + //clear all errors first + foreach (var column in tableView.Columns) + { + tableView.SetColumnError(column, ""); + } + + tableView.SetColumnError(null, ""); //clear row error + + var result = tableView.RowValidator(rowIndex, GetRowValues()); + + if (!result.Valid) + { + firstError = string.Format(Resources.TableViewValidator_ValidateRow_Validation_of_row_failed_0_, result.ErrorText); + tableView.SetColumnError(result.ColumnIndex == -1 ? null : tableView.Columns[result.ColumnIndex], + result.ErrorText); + return false; + } + } + + return true; + } + + public bool ValidateCell(TableViewCell cell, object newValue, out string error) + { + BeginEditRow(cell.RowIndex); + + error = ""; + + if (tableView.InputValidator != null) + { + var result = tableView.InputValidator(cell, newValue); + if (!result.Item2) + { + error = string.Format(Resources.TableViewValidator_ValidateCell_Validation_of_cell_failed_0_, result.Item1); + return false; + } + } + return true; + } + + public void RefreshRowData() + { + EndEditRow(); + } + + private void BeginEditRow(int rowIndex) + { + if (currentRowIndex >= 0 && rowIndex != currentRowIndex) + { + EndEditRow(); + } + + if (editingRow) + { + return; + } + + currentRowIndex = rowIndex; + + editingRow = true; + + originalRowValues = GetRowValues(); + } + + private object[] GetRowValues() + { + return tableView.Columns + .Where(column => column.Visible) + .Select(c => tableView.GetCellValue(currentRowIndex, c.AbsoluteIndex)) + .ToArray(); + } + + private void EndEditRow() + { + if (!editingRow) + { + return; + } + + editingRow = false; + currentRowIndex = -1; + originalRowValues = null; + } + + private object[] GetOriginalRowValues() + { + if (editingRow) + { + return originalRowValues; + } + + return GetRowValues(); //otherwise just get the values directly + } + + #region Event Handlers + + public void RowLostFocus(object sender, FocusedRowChangedEventArgs e) + { + if (e.FocusedRowHandle != int.MinValue && e.FocusedRowHandle != currentRowIndex) + { + EndEditRow(); + } + } + + public bool AutoValidation { get; set; } + + public void OnCellValueChanged(object sender, CellValueChangedEventArgs e) //after cell value changed, check the entire row + { + if (AutoValidation) + { + string error; + ValidateRow(e.RowHandle, out error); + } + } + + public void OnValidateCell(TableViewCell cell, BaseContainerValidateEditorEventArgs e) //before cell value changed + { + string error; + e.Valid = ValidateCell(cell, e.Value, out error); + e.ErrorText = error; + + tableView.SetColumnError(cell.Column, error); + } + + public void OnValidateRow(object sender, ValidateRowEventArgs e) //all values might have changed, do a full validation + { + string error; + e.Valid = ValidateRow(e.RowHandle, out error); + } + + public void HiddenEditor(object sender, EventArgs e) + { + var view = sender as GridView; + if (view != null) + { + view.ClearColumnErrors(); + } + } + + #endregion + } +} \ No newline at end of file Index: Core/Common/src/Core.Common.Controls.Table/WizardDialog.Designer.cs =================================================================== diff -u --- Core/Common/src/Core.Common.Controls.Table/WizardDialog.Designer.cs (revision 0) +++ Core/Common/src/Core.Common.Controls.Table/WizardDialog.Designer.cs (revision 46f5191a65faec434930a191e65f4c23d9ff8cfe) @@ -0,0 +1,119 @@ +using System; +using System.Linq; +using System.Windows.Forms; + +namespace Core.Common.Controls.Table +{ + partial class WizardDialog + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + private Timer updateButtonsTimer = new Timer(); + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + KeyUp -= OnPageModified; + + if (disposing && (updateButtonsTimer != null)) + { + updateButtonsTimer.Dispose(); + } + + if (disposing && (components != null)) + { + foreach (var wizardPage in wizardPages.OfType()) + { + wizardPage.Dispose(); + } + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Component Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(WizardDialog)); + this.wizardControl1 = new DevExpress.XtraWizard.WizardControl(); + this.welcomeWizardPage1 = new DevExpress.XtraWizard.WelcomeWizardPage(); + this.richTextBoxWelcome = new System.Windows.Forms.RichTextBox(); + this.completionWizardPage1 = new DevExpress.XtraWizard.CompletionWizardPage(); + this.richTextBoxFinished = new System.Windows.Forms.RichTextBox(); + ((System.ComponentModel.ISupportInitialize)(this.wizardControl1)).BeginInit(); + this.wizardControl1.SuspendLayout(); + this.welcomeWizardPage1.SuspendLayout(); + this.completionWizardPage1.SuspendLayout(); + this.SuspendLayout(); + // + // wizardControl1 + // + this.wizardControl1.Controls.Add(this.welcomeWizardPage1); + this.wizardControl1.Controls.Add(this.completionWizardPage1); + this.wizardControl1.LookAndFeel.UseDefaultLookAndFeel = false; + this.wizardControl1.LookAndFeel.UseWindowsXPTheme = true; + this.wizardControl1.Name = "wizardControl1"; + this.wizardControl1.Pages.AddRange(new DevExpress.XtraWizard.BaseWizardPage[] { + this.welcomeWizardPage1, + this.completionWizardPage1}); + // + // welcomeWizardPage1 + // + this.welcomeWizardPage1.Controls.Add(this.richTextBoxWelcome); + this.welcomeWizardPage1.Name = "welcomeWizardPage1"; + resources.ApplyResources(this.welcomeWizardPage1, "welcomeWizardPage1"); + // + // richTextBoxWelcome + // + this.richTextBoxWelcome.BackColor = System.Drawing.SystemColors.Window; + this.richTextBoxWelcome.BorderStyle = System.Windows.Forms.BorderStyle.None; + resources.ApplyResources(this.richTextBoxWelcome, "richTextBoxWelcome"); + this.richTextBoxWelcome.Name = "richTextBoxWelcome"; + this.richTextBoxWelcome.ReadOnly = true; + // + // completionWizardPage1 + // + this.completionWizardPage1.Controls.Add(this.richTextBoxFinished); + this.completionWizardPage1.Name = "completionWizardPage1"; + resources.ApplyResources(this.completionWizardPage1, "completionWizardPage1"); + // + // richTextBoxFinished + // + this.richTextBoxFinished.BackColor = System.Drawing.SystemColors.Window; + this.richTextBoxFinished.BorderStyle = System.Windows.Forms.BorderStyle.None; + resources.ApplyResources(this.richTextBoxFinished, "richTextBoxFinished"); + this.richTextBoxFinished.Name = "richTextBoxFinished"; + this.richTextBoxFinished.ReadOnly = true; + // + // WizardDialog + // + resources.ApplyResources(this, "$this"); + this.Controls.Add(this.wizardControl1); + this.Name = "WizardDialog"; + ((System.ComponentModel.ISupportInitialize)(this.wizardControl1)).EndInit(); + this.wizardControl1.ResumeLayout(false); + this.welcomeWizardPage1.ResumeLayout(false); + this.completionWizardPage1.ResumeLayout(false); + this.ResumeLayout(false); + + } + + #endregion + + protected DevExpress.XtraWizard.WizardControl wizardControl1; + private DevExpress.XtraWizard.WelcomeWizardPage welcomeWizardPage1; + private DevExpress.XtraWizard.CompletionWizardPage completionWizardPage1; + private System.Windows.Forms.RichTextBox richTextBoxWelcome; + private System.Windows.Forms.RichTextBox richTextBoxFinished; + } +} \ No newline at end of file Index: Core/Common/src/Core.Common.Controls.Table/WizardDialog.cs =================================================================== diff -u --- Core/Common/src/Core.Common.Controls.Table/WizardDialog.cs (revision 0) +++ Core/Common/src/Core.Common.Controls.Table/WizardDialog.cs (revision 46f5191a65faec434930a191e65f4c23d9ff8cfe) @@ -0,0 +1,367 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Drawing; +using System.Linq; +using System.Windows.Forms; +using Core.Common.Controls.Dialogs; +using Core.Common.Controls.Table.Properties; +using Core.Common.Controls.Views; +using DevExpress.XtraWizard; + +namespace Core.Common.Controls.Table +{ + public partial class WizardDialog : DialogBase, IView + { + private readonly IList pages; + private readonly IDictionary wizardPages = new Dictionary(); + + public WizardDialog(IWin32Window owner, Icon icon) : base(owner, icon, 450, 300) + { + pages = new List(); + InitializeComponent(); + wizardControl1.SelectedPageChanged += WizardControl1SelectedPageChanged; + wizardControl1.SelectedPageChanging += WizardControl1SelectedPageChanging; + wizardControl1.FinishClick += WizardControl1FinishClick; + wizardControl1.CancelClick += WizardControl1CancelClick; + wizardControl1.NextClick += WizardControl1NextClick; + wizardControl1.PrevClick += WizardControl1PrevClick; + + KeyPreview = true; //catch key events in pages + KeyUp += OnPageModified; + + updateButtonsTimer.Interval = 300; + updateButtonsTimer.Tick += UpdateNavigationButtonsTimerTick; + } + + public virtual object Data { get; set; } + + public IEnumerable Pages + { + get + { + return pages; + } + } + + public IList PageTitles + { + get + { + return Enumerable.OfType(wizardControl1.Pages).Select(p => p.Text).ToList(); + } + } + + public IList PageDescriptions + { + get + { + return Enumerable.OfType(wizardControl1.Pages).Select(p => p.DescriptionText).ToList(); + } + } + + public IComponent CurrentPage + { + get + { + if ((wizardControl1.SelectedPageIndex == 0) || + (wizardControl1.SelectedPageIndex == wizardControl1.Pages.Count - 1)) + { + return wizardControl1.Pages[wizardControl1.SelectedPageIndex]; + } + return pages[wizardControl1.SelectedPageIndex - 1]; + } + set + { + wizardControl1.SelectedPageIndex = pages.IndexOf(value) + 1; + } + } + + public string WelcomeMessage + { + get + { + return welcomeWizardPage1.IntroductionText; + } + set + { + welcomeWizardPage1.IntroductionText = value; + richTextBoxWelcome.Text = value; + } + } + + public string FinishedPageMessage + { + get + { + return completionWizardPage1.FinishText; + } + set + { + completionWizardPage1.FinishText = value; + richTextBoxFinished.Text = value; + } + } + + public string Title + { + get + { + return wizardControl1.Text; + } + set + { + wizardControl1.Text = value; + } + } + + public virtual void UpdateNavigationButtons() + { + if (!(CurrentPage is IWizardPage) || wizardPages == null || !wizardPages.ContainsKey(CurrentPage)) + { + return; + } + + var wizardPage = CurrentPage as IWizardPage; + var containerPage = wizardPages[CurrentPage]; + + if (containerPage != null) + { + containerPage.AllowBack = wizardPage.CanDoPrevious(); + containerPage.AllowNext = wizardPage.CanDoNext(); + } + } + + public void AddPage(IComponent page, string title, string description) + { + var pageControl = (Control) page; + pageControl.Dock = DockStyle.Fill; + + var wizardPage = new WizardPage + { + Text = title, DescriptionText = description, Dock = DockStyle.Fill + }; + wizardPage.Controls.Add(pageControl); + + wizardControl1.Controls.Add(wizardPage); + wizardControl1.Pages.Insert(wizardControl1.Pages.Count - 1, wizardPage); + + wizardPages[page] = wizardPage; + pages.Add(page); + } + + public void RemovePage(IComponent page) + { + var wizardPage = wizardControl1.Controls.OfType().FirstOrDefault(p => p.Controls.Contains((Control) page)); + if (wizardPage == null) + { + return; + } + + wizardControl1.Controls.Remove(wizardPage); + wizardControl1.Pages.Remove(wizardPage); + + wizardPages.Remove(page); + pages.Remove(page); + } + + public DialogResult ShowModal() + { + if (ShowDialog() == DialogResult.OK) + { + return DialogResult.OK; + } + return DialogResult.Cancel; + } + + protected bool WelcomePageVisible + { + set + { + welcomeWizardPage1.Visible = value; + } + } + + protected bool CompletionPageVisible + { + set + { + completionWizardPage1.Visible = value; + } + } + + protected virtual void OnPageReverted(IWizardPage page) {} + + protected virtual void OnPageCompleted(IWizardPage page) {} + + protected virtual void OnDialogFinished() {} + + /// + /// Override this method if you want to choose the next page on basis of choices that were made in one of the pages + /// The direction is forward + /// + /// The index of the page you are leaving + /// The next page index, -1 if the default is used + protected virtual int FindNextPageIndexMovingForward(int previousPageIndex) + { + return -1; + } + + /// + /// Override this method if you want to choose the next page on basis of choices that were made in one of the pages + /// The direction is backward + /// + /// The index of the page you are leaving + /// The next page index, -1 if the default is used + protected virtual int FindNextPageIndexMovingBackward(int previousPageIndex) + { + return -1; + } + + protected virtual void WizardControl1SelectedPageChanging(object sender, WizardPageChangingEventArgs e) + { + var nextPageIndex = EvaluateNextPageIndex(wizardControl1.SelectedPageIndex, e.Direction); + if (nextPageIndex > 0) + { + e.Page = wizardControl1.Pages[nextPageIndex]; + } + } + + private void WizardControl1SelectedPageChanged(object sender, WizardPageChangedEventArgs e) + { + UpdateNavigationButtons(); + } + + private void WizardControl1PrevClick(object sender, WizardCommandButtonClickEventArgs e) + { + if (CurrentPage is IWizardPage) + { + IWizardPage wizardPage = (IWizardPage) CurrentPage; + if (!wizardPage.CanDoPrevious()) + { + // setting handled to true will prevent default handling + e.Handled = true; + } + else + { + try + { + OnPageReverted(wizardPage); + } + catch (Exception ee) + { + ShowExceptionInMessageWindow(ee); + e.Handled = true; + } + } + } + } + + private void WizardControl1NextClick(object sender, WizardCommandButtonClickEventArgs e) + { + if (CurrentPage is IWizardPage) + { + var wizardPage = (IWizardPage) CurrentPage; + if (!wizardPage.CanDoNext()) + { + // setting handled to true will prevent default handling + e.Handled = true; + } + else + { + try + { + OnPageCompleted(wizardPage); + } + catch (Exception ee) + { + ShowExceptionInMessageWindow(ee); + e.Handled = true; + } + } + } + } + + private void ShowExceptionInMessageWindow(Exception ee) + { + var message = string.Format(Resources.WizardDialog_WizardControl1NextClick_An_error_occurred_Please_verify_your_input_Error_0_, ee.Message); + MessageBox.Show(message, Resources.WizardDialog_WizardControl1NextClick_Error_occurred, MessageBoxButtons.OK, MessageBoxIcon.Warning); + } + + private void WizardControl1CancelClick(object sender, CancelEventArgs e) + { + DialogResult = DialogResult.Cancel; + Close(); + } + + private void WizardControl1FinishClick(object sender, CancelEventArgs e) + { + if (CurrentPage is IWizardPage) + { + IWizardPage wizardPage = (IWizardPage) CurrentPage; + if (!wizardPage.CanFinish()) + { + return; + } + } + + OnDialogFinished(); + DialogResult = DialogResult.OK; + Close(); + } + + /// + /// Sometimes you want hide a page depending on choices in other pages + /// Use this method to determine the index of the page you want to go to + /// depending on choices that were made and the direction you are moving + /// + /// The index of the page you are leaving + /// Moving forward or backward through the wizard + /// The next page index, -1 if the default is used + private int EvaluateNextPageIndex(int previousPageIndex, Direction direction) + { + return (direction == Direction.Forward) ? FindNextPageIndexMovingForward(previousPageIndex) : FindNextPageIndexMovingBackward(previousPageIndex); + } + + #region Auto Updates + + private void OnPageModified(object sender, object e) + { + updateButtonsTimer.Start(); //delayed refresh + } + + protected override void WndProc(ref Message m) + { + const int WM_PARENTNOTIFY = 0x0210; + const int WM_SETFOCUS = 0x0007; + const int WM_LBUTTONDOWN = 0x0201; + + if (m.Msg == WM_SETFOCUS) //called after child (file) dialog is closed + { + OnPageModified(null, null); + } + else if (m.Msg == WM_PARENTNOTIFY) + { + var subEvent = m.WParam.ToInt32() & 0xFFFF; //LOWORD + if (subEvent == WM_LBUTTONDOWN) //called after mouse down anywhere in dialog + { + OnPageModified(null, null); + } + } + base.WndProc(ref m); + } + + private void UpdateNavigationButtonsTimerTick(object sender, EventArgs e) + { + UpdateNavigationButtons(); //refresh + updateButtonsTimer.Stop(); + } + + #endregion + + protected override Button GetCancelButton() + { + return null; // Cancel support already implemented by WizardControl + } + } +} \ No newline at end of file Index: Core/Common/src/Core.Common.Controls.Table/WizardDialog.resx =================================================================== diff -u --- Core/Common/src/Core.Common.Controls.Table/WizardDialog.resx (revision 0) +++ Core/Common/src/Core.Common.Controls.Table/WizardDialog.resx (revision 46f5191a65faec434930a191e65f4c23d9ff8cfe) @@ -0,0 +1,347 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + + Fill + + + + 0, 0 + + + 493, 345 + + + + 0 + + + Welkom paginatekst + + + richTextBoxWelcome + + + System.Windows.Forms.RichTextBox, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + welcomeWizardPage1 + + + 0 + + + Klik op Volgende om door te gaan. + + + 493, 345 + + + Welkom bij de wizard. + + + welcomeWizardPage1 + + + DevExpress.XtraWizard.WelcomeWizardPage, DevExpress.XtraWizard.v9.3, Version=9.3.7.0, Culture=neutral, PublicKeyToken=cef13554f3ca1f2d + + + wizardControl1 + + + 6 + + + Fill + + + 0, 0 + + + 493, 345 + + + 2 + + + voltooide paginatekst + + + richTextBoxFinished + + + System.Windows.Forms.RichTextBox, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + completionWizardPage1 + + + 0 + + + De wizard is succesvol voltooid. + + + Klik op Voltooien om deze wizard af te sluiten. + + + 493, 345 + + + Voltooien van de wizard. + + + completionWizardPage1 + + + DevExpress.XtraWizard.CompletionWizardPage, DevExpress.XtraWizard.v9.3, Version=9.3.7.0, Culture=neutral, PublicKeyToken=cef13554f3ca1f2d + + + wizardControl1 + + + 7 + + + wizardControl1 + + + DevExpress.XtraWizard.WizardControl, DevExpress.XtraWizard.v9.3, Version=9.3.7.0, Culture=neutral, PublicKeyToken=cef13554f3ca1f2d + + + $this + + + 0 + + + True + + + 710, 478 + + + + AAABAAIAICAAAAEAIACoEAAAJgAAABAQAAABACAAaAQAAM4QAAAoAAAAIAAAAEAAAAABACAAAAAAAIAQ + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAJBQEBBAIABQAAAAkAAAALAAAACgEAAAgDAQAEBQMBAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAIBMIAg0HAw4AAAAeAAAAKQAAAC4AAAAwAAAALwAAACYBAAAZBgMBDAkFAQMAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAqGAoIRyoTR2U8HJR0RiHCdkchznRGIMtqQB66Ti4VlSEUCWEEAgE4AQAAIQcD + AQ8LBgIDAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABNLhQKXzgYI2c/HDpwRB9PfkwjcY1VKKmYXCvhl1wr9HZH + Iso2IQ99DAcCQAQDAB0MBwIKDQcCAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAhlElBINQ + JSGMVSh4ml4t2JheLPJuQyC/LBsMawgFAS4LBwIPEQkEAwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAGA6GwFrQh9IiFQnwZ9iLveNVijgSy0VjxMLBD0OCAMTFg0FAwAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAWDQUBIBMJBR8SCB1aNhqPnF8t7qZlMP2cXy3vYjwcqB0SCEkQCQQWGQ8GBAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAoFAgEKBgIIAwEAEwAAAB4AAAAoEQoERGA7HKWgYi7wqmgx/atpMv6iYy/yakEeriEU + CUcVDQUQHREHAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADgsIAQAA + AAAAAAAAAAAAAAAAAAARCgQBEQkEDQcDAScWDAZPMh4Odk0vFpR8SyTEo2Mw8KxqM/yuazT+rms0/q5r + NP6iYzDuZz8eoR4SCC8lFgoGAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACof + GwYGBQQVDAkIDiYdGAMAAAAAAAAAABoQBgciFAkuUTEXhppeLeCybTX9sm01/rJtNf6ybTX+sm01/rJt + Nf6ybTX+sm01/rJtNf6RWCvTTS8WZjEdDQ8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAOCskC5FvXX00KSFEJR0YEiYeGAIAAAAAKBgLFVY0GWeVWyvRtnA2/rZwNv62cDb+tnA2/rZw + Nv62cDb+tnA2/rZwNv62cDb+tnA2/qloMel+TSSURisTFQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAABaRjsIp4Jtj5RzYZovJB89IxsWCiseFgE6JBMYdkgjfK5qM+W5cjf+uXI3/rly + N/65cjf+uXI3/rlyN/65cjf+uXI3/rlyN/65cjf+sW006pZcLJVoQB4RAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAIlsXAKPcWBT0qaOymxVSYEgGRQqKB0VCEwyHRJ8TCVlq2gz0710 + Of69dDn+vXQ5/r10Of69dDn+vXQ5/r10Of60bzbznmAv2I1VKbOGUSd2cUUhJFc1GAIAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIxvYBfSp5Cuz6aP0VZFO3EYEg0iOCYXC21G + JiyeYTCXvnU59cB3Ov7Adzr+wHc6/sB3Ov7Adzr+wHc6/qxqM+hhOxybFAwFRAwGAx0mFwoKMh8OAQAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAsY56Ba6Me1ThtZ/NxaCMz1NC + OnAWEAwlOSYXEXVLKDSpaDSdwnc69MR5O/7EeTv+xHk7/sR5O/7EeTv+xHk7/rhxN/GDUCa7Mx4OaggE + ATANCAMSIRQIAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAvpqGENGr + l4frwargzKeU1GBORX4UDwwxKBoPFWNAIyKeYjF2v3U43Md6O/3Hejv9x3o7/sd6O/7Hejv+x3o7/sZ5 + O/yxbDXocEUhoiATCD0hFAgKAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AADEoI0ByKSRJOG6pqX2y7Xw37ik5IZuY58jHRlMCwcDHy8eEA9ySCYrqWk0hMB1ONjIejr5yXs6/cl7 + Ov7Jezr+yXs6/sl7Ov6+dDbuilUnoTIeDRMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAADVsJwF2rWiO+zGsbH807749My49sKjks9dT0aCEA0LPwgEAh8oGg4OXjsfGI9Z + LFCvazOZwHU41ch6OfTKezr9yns6/sV4OfCtaTGncEUgDQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADjvqoH6sWxQPTOurD81cH4/NXB/PHMuPO7no/KWUtEgBMQ + DkUCAQAoDggEGCscDg5NMBkSbUMhJoFQJz6IUyhGiFMoM3lKIw4AAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADfu6kG6MSxN/LOu6H82MTz/trG/v7Z + xf761sP61LWl3YNxZ6E1LSlmCwkIQQAAADAAAAAnAAAAIQQDARsaEgsTQi8eBwAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACBbWMDqJCDItW2 + p4D41cPj/tvJ/v7byf7+28n+/tvJ/vjWxPjZu6zfqJGFvYFvZ6FrXFWOV0tFejgwLFQoIh8aTkM7AQAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADgwLAQgHBwUIBwcHExAPBiwm + IgRLQTsDbl5WFqKMgGzgw7Pa/t7M/v7ezP7+3sz+/t7M/v7ezP7+3sz+/t7M/v7ezP7+3cv83sKxy4h2 + bEZVSkMEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACUiHwUKCQgXAAAAKgAA + ADQAAAAzAAAAKwAAACMCAgIhHhoZPpSCeKT93s78/uDP/v7gz/7+4M/+6My96sKqncfErJ+t38O1md/D + tHLKsaM1p5GGBgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFxQSFklB + PGOejIKxwq2h0rqlmsuUg3uuaFtWj1FIQ4JvYlyXxq+k1P7h0v7+4tL+/uLS/v7i0v7Ks6fSW1FMckQ8 + OCOJd24FAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFBI + QwJKQz470rywz/zh0/v+49X+/uPV/v7j1f7+49X+/uPV/v7j1f7+49X+/uPV/v7j1f7+49X+/uPV/v3h + 1Py/qqDFal9ZXFhOSRIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAZVtVAn1waUniy8DZ/uXY/v7l2P7+5dj+/uXY/v7l2P7+5dj+/uXY/v7l2P7+5dj+/uXY/v7l + 2P7+5dj+/uXY/vfe0u6zoZiLZFpVGwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAm42EHeDMwbvy29DuxrOquLypoW/VwLZU6dPHa/Te0Zb649fE/eba6P7n + 2/r+59v9/ufb/f7n2/7+59v89N7Sz9bBtmSikosQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADFs6kFx7atVd3LwcOLf3iNWVFMK4+CewQAAAAAAAAAAAAA + AAD649cJ+uTXIPnj1zz549dT+uPYV/bf1EHu18wd48zCBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADWxboL3s3CatHBuamEenVTb2ZhBQAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADFtq0KyLiwN7Sn + oCd/dnEFAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP//////gH///wAf//8AB///gAH///wA//// + AH///gA///AAH/3gAB/4YAAf+CAAH/gAAB/4AAAf/AAAH/wAAA/+AAAP/gAAD/8AAA//gAAf/8AAH//g + AA/+AAAP/AAAH/wAAP/4AAD/+AAA//wAAP/8DgH//g////8P////////KAAAABAAAAAgAAAAAQAgAAAA + AABABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAABAAAAAUBAAADAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAJBUJFjYgDl86IxB8LxwNbBUM + BT8GAwEWBQMBBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFczFwFyRR8VgE0jLYpU + J2KKVCerYzwcqScXC1QJBQIPAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAQCcSHHFFIJCOVynhUDEXiA8JBBgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAJBQINEgsFNTEeDmp2SCK8rGkz/ZxgLupkPR2WFw4GDAAAAAAAAAAAAAAAAAAAAAAuIx4EMiYgOCge + GgsfFAsDVDMYcphdLNu0bzX+tG81/rRvNf60bzX+nWEu1kotFUQAAAAAAAAAAAAAAAAAAAAAVkM4Aa2I + dJk4LCY5MiIWCodUKpa0bzbvu3M4/rtzOP+5cTf8sGw07ZhdLLBrQR4wAAAAAAAAAAAAAAAAAAAAAAAA + AACriXZJso98rUAxKUBkQCNEqWk0u8F3OvzCeDr+vXU4+ZBZK8kyHw5YGQ8GEQAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAANqzno6+nYu8T0A3X0sxHDqRWi2Fv3Y53ch7O/7Hejv+tnA263NGIZQsGwwFAAAAAAAA + AAAAAAAAAAAAAAAAAADMqpcL8cq2nu3HtOKagnWuQTQtVTYjFDBoQCBQlFsshqdmMJuZXixxAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAKCHegvVtqWA9dLA4fLQvvTBpZjPeWhflkc9OGkxKiVKLiQcIQAA + AAAAAAAAAAAAAAAAAAAAAAAAEg8OBwYEBBoPDQwaKSMgFYRzaXzdwbLg/t/O/vHTw/LjxrfZ5sq5sa6Y + jFEAAAAAAAAAAAAAAAAAAAAAAAAAAF9VT2TMtqvV0ryw3rKflcfKtKjY8dbI9P/i1P/MtarTfW5nY459 + cwMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAC2pZuE4s3B2ufRxbb03NC+/OTX4/7m2fn+5tr++uLW7824 + rpZZUEsBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAw7KqFci4r5qGe3QuvauiAu/ZzQL649gS++TZJffg + 1R/kz8UHAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADMvbQTsKOcBwAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD4/wAA8B8AAPAPAAD/BwAA/AMAAMADAADAAwAA4AMAAPAB + AADwAwAA+AMAAOADAADgBwAA4AcAAOAPAADz/wAA + + + + NoControl + + + CenterParent + + + WizardDialog + + + System.Windows.Forms.Form, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file Index: Core/Common/src/Core.Common.Controls.Table/XtraGridRepositoryItemBuilder.cs =================================================================== diff -u --- Core/Common/src/Core.Common.Controls.Table/XtraGridRepositoryItemBuilder.cs (revision 0) +++ Core/Common/src/Core.Common.Controls.Table/XtraGridRepositoryItemBuilder.cs (revision 46f5191a65faec434930a191e65f4c23d9ff8cfe) @@ -0,0 +1,257 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Drawing; +using System.Linq; +using System.Windows.Forms; +using Core.Common.Controls.Table.Editors; +using DevExpress.Utils; +using DevExpress.XtraEditors; +using DevExpress.XtraEditors.Controls; +using DevExpress.XtraEditors.Repository; +using DevExpress.XtraGrid; +using DevExpress.XtraGrid.Columns; +using log4net; + +namespace Core.Common.Controls.Table +{ + public static class XtraGridRepositoryItemBuilder + { + private static readonly ILog Log = LogManager.GetLogger(typeof(TableViewColumn)); + + public static RepositoryItem CreateFromTypeEditor(Editors.ITypeEditor typeEditor, GridControl gridControl, GridColumn column, string caption) + { + if (typeEditor is MultiLineTextEdior) + { + // do not use wordwrap + column.AppearanceCell.Options.UseTextOptions = true; + column.AppearanceCell.TextOptions.WordWrap = WordWrap.NoWrap; + column.AppearanceCell.TextOptions.Trimming = Trimming.EllipsisWord; + + return new RepositoryItemMemoEdit + { + WordWrap = false + }; + } + + var comboBoxTypeEditor = typeEditor as ComboBoxTypeEditor; + if (comboBoxTypeEditor != null) + { + return CreateComboBoxRepositoryItem(comboBoxTypeEditor, gridControl, caption); + } + + var buttonEditor = typeEditor as ButtonTypeEditor; + if (buttonEditor != null) + { + var buttonTypeEditorRepositoryItem = new RepositoryItemButtonEdit + { + TextEditStyle = TextEditStyles.HideTextEditor + }; + var editorButton = buttonTypeEditorRepositoryItem.Buttons[0]; + + editorButton.ToolTip = buttonEditor.Tooltip; + + if (buttonEditor.Caption != null || buttonEditor.Image != null) + { + editorButton.Kind = ButtonPredefines.Glyph; + editorButton.Caption = buttonEditor.Caption; + editorButton.Image = buttonEditor.Image; + } + + buttonTypeEditorRepositoryItem.ButtonClick += (s, e) => ButtonTypeEditorRepositoryItemButtonClick(e, typeEditor); + return buttonTypeEditorRepositoryItem; + } + + // the mechanisms for validating do not work as expected; perhaps some of the encapsulating layers + // consumes events? + var repositoryItem = new RepositoryItemPopupContainerEdit + { + CloseOnOuterMouseClick = false + }; + + var popupControl = new PopupContainerControl + { + AutoSize = true + }; + var editorControl = (Control) typeEditor; + popupControl.Controls.Add(editorControl); + + repositoryItem.PopupControl = popupControl; + + repositoryItem.QueryPopUp += RepositoryItemQueryPopUp; + repositoryItem.QueryResultValue += RepositoryItemQueryResultValue; + repositoryItem.Validating += RepositoryItemValidating; + + repositoryItem.CloseUp += (sender, e) => RepositoryItemCloseUp(e, typeEditor); + //close and open with enter + repositoryItem.CloseUpKey = new KeyShortcut(Keys.Enter); + + return repositoryItem; + } + + /// + /// Creates a ComboBox editor as . The requested width for rendering + /// is determined by the rendersize of the largest string in the selection set or the caption. + /// + /// It has been assumed the final caption is already set before calling this function. + private static RepositoryItem CreateComboBoxRepositoryItem(ComboBoxTypeEditor comboBoxEditor, GridControl dxGridControl, string caption) + { + RepositoryItem comboBoxRepositoryItem; + + // TODO: make it check if Items is evented, if yes - refresh + var items = comboBoxEditor.Items.Cast().Select(i => new TableViewComboBoxItem + { + Value = i + }).ToList(); + items.ForEach(i => i.CustomFormatter = comboBoxEditor.CustomFormatter); + + if (!comboBoxEditor.ItemsMandatory) + { + var repositoryItemComboBox = new RepositoryItemComboBox(); + + repositoryItemComboBox.Items.AddRange(items); + repositoryItemComboBox.CloseUp += RepositoryItemComboBoxCloseUp; + repositoryItemComboBox.TextEditStyle = TextEditStyles.DisableTextEditor; // disable editing + repositoryItemComboBox.DrawItem += OnDrawItem; + comboBoxRepositoryItem = repositoryItemComboBox; + } + else + { + var repositoryItemLookUpEdit = new RepositoryItemLookUpEdit + { + SearchMode = SearchMode.AutoFilter + }; + + repositoryItemLookUpEdit.Columns.Add(new LookUpColumnInfo("DisplayText")); + repositoryItemLookUpEdit.DataSource = items; + repositoryItemLookUpEdit.DisplayMember = "Value"; + repositoryItemLookUpEdit.ValueMember = "Value"; + repositoryItemLookUpEdit.TextEditStyle = TextEditStyles.DisableTextEditor; + repositoryItemLookUpEdit.ShowHeader = false; + repositoryItemLookUpEdit.ShowFooter = false; + repositoryItemLookUpEdit.AllowNullInput = DefaultBoolean.False; + repositoryItemLookUpEdit.NullText = ""; + comboBoxRepositoryItem = repositoryItemLookUpEdit; + } + + // Needed for formatting the value in the textbox during editing -> this is done separately from the items + if (comboBoxEditor.CustomFormatter != null) + { + comboBoxRepositoryItem.DisplayFormat.FormatType = FormatType.Custom; + comboBoxRepositoryItem.DisplayFormat.Format = new TableViewCellFormatterProvider(comboBoxEditor.CustomFormatter); + } + + comboBoxRepositoryItem.EditValueChanged += (sender, args) => dxGridControl.FocusedView.CloseEditor(); + comboBoxRepositoryItem.BestFitWidth = GetBestFitEditorWidth(items, comboBoxRepositoryItem.Appearance.Font, caption); + + return comboBoxRepositoryItem; + } + + private static void RepositoryItemComboBoxCloseUp(object sender, CloseUpEventArgs e) + { + var comboBoxItem = e.Value as TableViewComboBoxItem; + if (comboBoxItem != null) + { + e.Value = comboBoxItem.Value; + } + } + + private static int GetBestFitEditorWidth(IEnumerable items, Font font, string caption) + { + int bestFitWidth = -1; // Default, auto-size + //Determine longest string in combobox and estimate it's rendering size + foreach (var item in items) + { + Size textSize = TextRenderer.MeasureText(item.ToString(), font); + if (textSize.Width > bestFitWidth && textSize.Width != 0) + { + bestFitWidth = textSize.Width; + } + } + + // Use caption render width if it's the largest + Size captionRenderSize = TextRenderer.MeasureText(caption, font); + if (captionRenderSize.Width > bestFitWidth && captionRenderSize.Width != 0) + { + bestFitWidth = captionRenderSize.Width; + } + // If we have determined a BestFitWidth, add margin for dorpdown menu button + if (bestFitWidth != -1) + { + bestFitWidth += 30; + } + return bestFitWidth; + } + + // Work around for DevExpress bug : Formatting RepositoryItemComboBox items text + // http://www.devexpress.com/Support/Center/p/DQ23557.aspx + private static void OnDrawItem(object sender, ListBoxDrawItemEventArgs e) + { + var comboboxitem = e.Item as TableViewComboBoxItem; + if (comboboxitem == null) + { + throw new NotSupportedException("Unknown item type"); + } + + e.Cache.FillRectangle(new SolidBrush(e.Appearance.BackColor), e.Bounds); + e.Cache.DrawString(comboboxitem.DisplayText, e.Appearance.Font, new SolidBrush(e.Appearance.ForeColor), e.Bounds, e.Appearance.GetStringFormat()); + e.Handled = true; + } + + /// + /// Called when the popup is closed + /// + private static void RepositoryItemCloseUp(CloseUpEventArgs e, Editors.ITypeEditor editor) + { + if (e.CloseMode == PopupCloseMode.Cancel) + { + return; + } + if (!editor.CanAcceptEditValue()) + { + e.AcceptValue = false; + } + } + + private static void RepositoryItemValidating(object sender, CancelEventArgs e) + { + var popupContainer = (PopupContainerEdit) sender; + var typeEditor = (Editors.ITypeEditor) popupContainer.Properties.PopupControl.Controls[0]; + if (!typeEditor.Validate()) + { + e.Cancel = true; + } + } + + private static void ButtonTypeEditorRepositoryItemButtonClick(ButtonPressedEventArgs e, Editors.ITypeEditor editor) + { + var buttonTypeEditor = (ButtonTypeEditor) editor; + if (buttonTypeEditor.ButtonClickAction != null) + { + buttonTypeEditor.ButtonClickAction(); + } + } + + private static void RepositoryItemQueryResultValue(object sender, QueryResultValueEventArgs e) + { + var popupContainer = (PopupContainerEdit) sender; + var typeEditor = (Editors.ITypeEditor) popupContainer.Properties.PopupControl.Controls[0]; + e.Value = typeEditor.EditableValue; + } + + private static void RepositoryItemQueryPopUp(object sender, CancelEventArgs e) + { + var popupContainer = (PopupContainerEdit) sender; + + var typeEditor = (Editors.ITypeEditor) popupContainer.Properties.PopupControl.Controls[0]; + if (!typeEditor.CanPopup()) + { + Log.Warn("repositoryItem_QueryPopUp ! CanPopup"); + e.Cancel = true; + return; + } + var editValue = popupContainer.EditValue; + typeEditor.EditableValue = editValue; + } + } +} \ No newline at end of file Index: Core/Common/test/Core.Common.Controls.Swf.Test/Core.Common.Controls.Swf.Test.csproj =================================================================== diff -u -r8cae5d69ac2d4cf678486ac2b457c0dfe97089d5 -r46f5191a65faec434930a191e65f4c23d9ff8cfe --- Core/Common/test/Core.Common.Controls.Swf.Test/Core.Common.Controls.Swf.Test.csproj (.../Core.Common.Controls.Swf.Test.csproj) (revision 8cae5d69ac2d4cf678486ac2b457c0dfe97089d5) +++ Core/Common/test/Core.Common.Controls.Swf.Test/Core.Common.Controls.Swf.Test.csproj (.../Core.Common.Controls.Swf.Test.csproj) (revision 46f5191a65faec434930a191e65f4c23d9ff8cfe) @@ -76,11 +76,6 @@ - - - - - Fisheye: Tag 46f5191a65faec434930a191e65f4c23d9ff8cfe refers to a dead (removed) revision in file `Core/Common/test/Core.Common.Controls.Swf.Test/Table/TableViewCopyPasteTest.cs'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 46f5191a65faec434930a191e65f4c23d9ff8cfe refers to a dead (removed) revision in file `Core/Common/test/Core.Common.Controls.Swf.Test/Table/TableViewPasteControllerTest.cs'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 46f5191a65faec434930a191e65f4c23d9ff8cfe refers to a dead (removed) revision in file `Core/Common/test/Core.Common.Controls.Swf.Test/Table/TableViewTest.cs'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 46f5191a65faec434930a191e65f4c23d9ff8cfe refers to a dead (removed) revision in file `Core/Common/test/Core.Common.Controls.Swf.Test/Table/TestClasses/ClassWithEnum.cs'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 46f5191a65faec434930a191e65f4c23d9ff8cfe refers to a dead (removed) revision in file `Core/Common/test/Core.Common.Controls.Swf.Test/Table/TestClasses/Person.cs'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 46f5191a65faec434930a191e65f4c23d9ff8cfe refers to a dead (removed) revision in file `Core/Common/test/Core.Common.Controls.Swf.Test/test-data/TestPasteData.txt'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 46f5191a65faec434930a191e65f4c23d9ff8cfe refers to a dead (removed) revision in file `Core/Common/test/Core.Common.Controls.Swf.Test/test-data/TestPasteData_DutchDates.txt'. Fisheye: No comparison available. Pass `N' to diff? Index: Core/Common/test/Core.Common.Controls.Table.Test/Core.Common.Controls.Table.Test.csproj =================================================================== diff -u -r78b769cdeacaa9a56939825e527e7fe71c3a0281 -r46f5191a65faec434930a191e65f4c23d9ff8cfe --- Core/Common/test/Core.Common.Controls.Table.Test/Core.Common.Controls.Table.Test.csproj (.../Core.Common.Controls.Table.Test.csproj) (revision 78b769cdeacaa9a56939825e527e7fe71c3a0281) +++ Core/Common/test/Core.Common.Controls.Table.Test/Core.Common.Controls.Table.Test.csproj (.../Core.Common.Controls.Table.Test.csproj) (revision 46f5191a65faec434930a191e65f4c23d9ff8cfe) @@ -38,8 +38,37 @@ true + + ..\..\..\..\lib\DevExpress.Data.v9.3.dll + + + ..\..\..\..\lib\DevExpress.Utils.v9.3.dll + + + ..\..\..\..\lib\DevExpress.XtraEditors.v9.3.dll + + + ..\..\..\..\lib\DevExpress.XtraGrid.v9.3.dll + + + ..\..\..\..\lib\DevExpress.XtraWizard.v9.3.dll + + + ..\..\..\..\packages\log4net.2.0.4\lib\net40-full\log4net.dll + True + + + ..\..\..\..\packages\NUnit.2.6.4\lib\nunit.framework.dll + True + + + ..\..\..\..\packages\RhinoMocks.3.6.1\lib\net\Rhino.Mocks.dll + True + + + @@ -48,13 +77,33 @@ + + + + + {4b2add09-ecac-439d-82fc-dbf8aa63772d} Core.Common.Controls.Table + + {9a2d67e6-26ac-4d17-b11a-2b4372f2f572} + Core.Common.Controls + + + {f49bd8b2-332a-4c91-a196-8cce0a2c7d98} + Core.Common.Utils + + + {d749ee4c-ce50-4c17-bf01-9a953028c126} + Core.Common.TestUtil + + + +