Subversion Repositories autosfx

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
1 daniel-mar 1
{*******************************************************************************
2
   Class: TSortGrid
3
   Copyright 1996,1997,1999
4
   Author: Bill Menees
5
           bmenees@usit.net
6
                   www.public.usit.net/bmenees
7
   Modified by Russell Peters, Jan 2003
8
    - Stop comparison exceptions (Versions 6+)
9
   Modified by Eric W. Engler, Feb 1997
10
    - fixed a bug in autodetection of type
11
    - OnBeginSort event was called before the autodetect of type; moved to after.
12
    - expanded date sort to incl datetime (these are usu compatible in Delphi)
13
    - added a time sort
14
   Modified by Ivo Eichler <eichler@sce.cz>, Jan 1999
15
    - now supports the national string setting in the control panel by
16
      using ANSICompare and ANSIUppercase functions.
17
   Modified by Chris Vleghert Jan. 19 1999.
18
    - Fixed a memory leak in the procedure TSortedList.Reset;
19
   Modified by Andrea Gnesutta Mar. 8 1999.  (gnes@zero.it)
20
    - Added property LastSortDirection (ReadOnly)
21
    - Added property SortState (ReadOnly)
22
    - Added property LastSortedCol (ReadOnly)
23
   Modified by Chris Vleghert Mar. 10 1999. (RCV02)
24
    - Changed property LastSortDirection into SortDirection (R/W)
25
    - Changed property LastSortedCol into SortColumn (R/W)
26
    - Changed property ClickSorting into SortOnClick
27
    - Added property SortSymbol
28
    - Added property SortSpacingHor
29
    - Added property SortSpacingVert
30
    - Added property SortBitMapA
31
    - Added property SortBitMapD
32
    - Added property SortFooter
33
    - Added property FooterRows
34
    - Added property FooterColor
35
    - Added property FooterFont
36
    - Added property FooterBevelStyle
37
    - Added function InsertRows
38
    - Added function InsertCols
39
    - Added function ClearRows
40
    - Added function ClearFrom
41
    - Added function RemoveRows
42
    - Added function RemoveCols
43
    - Added function ClearCols
44
    - Added function FindFirst
45
    - Added function FindNext
46
    - Added event OnMouseEnter
47
    - Added event OnMouseLeave
48
   Modified by Chris Vleghert Jan. 1 2000. (RCV03)
49
   (integrated MultiGrd http://www.pablop.demon.co.uk/marley/tmultigrid.htm into SortGrid)
50
    - Added extended multiselect
51
    - Added property Selected[RowNumber], do not use the Selection property anymore!
52
    - Added property SelectedCount
53
    - Added property SelectedItems[1 to SelectedCount];
54
    - Added function ClearSelection
55
   Modified by Chris Vleghert May. 11 2000. (RCV04)
56
    - Added method ShowRows( StartRow, EndRow: LongInt )
57
    - Added method HideRows( StartRow, EndRow: LongInt )
58
    - Added method AutoSizeRow( aRow: LongInt )
59
    - Added method AutoSizeRows( StartRow, EndRow: LongInt )
60
    - Added method AutoSizeVisibleRows( StartRow, EndRow: LongInt )
61
    - Added method AutoSizeHiddenRows( StartRow, EndRow: LongInt )
62
    - Added method HideCols( StartCol, EndCol: LongInt )
63
    - Added method ShowCols( StartCol, EndCol: LongInt )
64
    - Added method Print            only D4+ and BCB4+
65
    - Added method PrintPreview     only D4+ and BCB4+
66
    - Added method PageCount        only D4+ and BCB4+
67
    - Added method UpdatePreview( aCanvas: TCanvas )         only D4+ and BCB4+
68
    - Added property PrintOptions   only D4+ and BCB4+
69
    - Added property WordWrap
70
   Modified by Chris Vleghert Jul. 28 2000, Bug report: Florian Schick
71
    - FindFirst and FindNext did not do what they were supposed to be doing.
72
 
73
 
74
   IMPORTANT!  Do NOT use BCB's or Delphi's "Break on Exception" option if
75
   you run a program that uses this component from the GUI.  This VCL uses
76
   exceptions during normal processing.
77
***************************************************************************}
78
(************************************************************************
79
 Copyright (C) 2009, 2010  by Russell J. Peters, Roger Aelbrecht,
80
      Eric W. Engler and Chris Vleghert.
81
 
82
   This file is part of TZipMaster Version 1.9.
83
 
84
    TZipMaster is free software: you can redistribute it and/or modify
85
    it under the terms of the GNU Lesser General Public License as published by
86
    the Free Software Foundation, either version 3 of the License, or
87
    (at your option) any later version.
88
 
89
    TZipMaster is distributed in the hope that it will be useful,
90
    but WITHOUT ANY WARRANTY; without even the implied warranty of
91
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
92
    GNU Lesser General Public License for more details.
93
 
94
    You should have received a copy of the GNU Lesser General Public License
95
    along with TZipMaster.  If not, see <http://www.gnu.org/licenses/>.
96
 
97
    contact: problems@delphizip.org (include ZipMaster in the subject).
98
    updates: http://www.delphizip.org
99
    DelphiZip maillist subscribe at http://www.freelists.org/list/delphizip
100
************************************************************************)
101
 
102
 
103
UNIT SortGrid;
104
 
105
{$INCLUDE '..\..\ZipVers19.inc'}
106
 
107
INTERFACE
108
 
109
uses
110
  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
111
  StdCtrls, Grids, Printers;
112
 
113
type
114
  {TSortCompare must return < 0 if Str1 is less than Str2,
115
 
116
  TSortCompare = function (const Str1, Str2: String): Integer;
117
 
118
  TSortDirection = ( sdAscending, sdDescending );
119
  TSortStyle     = ( ssAutomatic, ssAlphabetic, ssNumeric, ssDateTime, ssTime,ssCustom );
120
  TSortSymbol    = ( sgNone, sgArrow, sgGlyph, sgCustom );
121
  TSortState     = ( ssUnsorted, ssSorted );  // Line modified/added by gnes@zero.it
122
  TAutoSize      = ( asAll, asVisible, asHidden );
123
  TPrintMode     = ( pmPrint, pmPreview, pmPageCount );
124
 
125
  {**************************************************************}
126
  {*** NOTE: These are the options you can set to affect sorting.}
127
  TSortOptions = record
128
    SortStyle:         TSortStyle;
129
    SortDirection:     TSortDirection;
130
    SortCaseSensitive: Boolean;
131
    SortCompare:       TSortCompare;  //Used only if SortStyle = ssCustom.
132
  end;
133
 
134
  TSortedListEntry = record
135
    Str:    String;
136
    RowNum: LongInt;
137
  end;
138
  pSortedListEntry = ^TSortedListEntry;
139
 
140
  TSortedList = class( TList )
141
  public
142
    function GetItem( const i: Integer ): pSortedListEntry;
143
    procedure Reset;
144
  end;
145
 
146
  TOldRowColEntry = record
147
    IsRowCol:    Integer;
148
          RowColNum:   LongInt;
149
    RowColValue: Integer;
150
  end;
151
  pOldRowColEntry = ^TOldRowColEntry;
152
 
153
  TOldRowColValueList = class( TList )
154
  public
155
     procedure SetValue( const rc: LongInt; Const rcValue, IsRC: Integer );
156
     function  GetValue( const rc: LongInt; Const IsRC: Integer ): Integer;
157
     procedure RemRC( Const rc: LongInt; Const IsRC: Integer );
158
     procedure MoveUp( Const rc: LongInt; Const IsRC: Integer );
159
     procedure MoveDown( Const rc: LongInt; Const IsRC: Integer );
160
     procedure Reset;
161
  end;
162
 
163
  TCellBevelStyle = ( cbNone, cbRaised, cbLowered );
164
  {**********************************************************}
165
  {*** NOTE: This is one of the structures in TFormatOptions.}
166
  TCellBevel = record
167
    Style:           TCellBevelStyle;
168
    UpperLeftColor:  TColor;
169
    LowerRightColor: TColor;
170
  end;
171
  TVertAlignment = ( taTopJustify, taBottomJustify, taMiddle );
172
 
173
  {**************************************************}
174
  {*** NOTE: These are the display options you can set
175
             for each cell in OnGetCellFormat.}
176
  TFormatOptions = record
177
    Brush:         TBrush;
178
    Font:          TFont;
179
    AlignmentHorz: TAlignment;
180
    AlignmentVert: TVertAlignment;
181
    Bevel:         TCellBevel;
182
    HideText:      Boolean;
183
  end;
184
 
185
  TPrintOptions = class( TPersistent )
186
    private
187
      fJobTitle:        String;
188
      fPageTitle:       String;
189
      fPageTitleMargin: Cardinal;
190
      fCopies:          Cardinal;
191
      fPreviewPage:     Cardinal;
192
      fFromRow:         Cardinal;
193
      fToRow:           Cardinal;
194
            fBorderStyle:     TBorderStyle;
195
      fLeftPadding:     Cardinal;
196
      fMarginBottom:    Cardinal;
197
      fMarginLeft:      Cardinal;
198
      fMarginTop:       Cardinal;
199
      fMarginRight:     Cardinal;
200
      fPageFooter:      String;
201
      fDateFormat:      String;
202
      fTimeFormat:      String;
203
      fHeaderSize:      Cardinal;
204
      fFooterSize:      Cardinal;
205
      fOrientation:     TPrinterOrientation;
206
      fLogo:            String;
207
 
208
      procedure SetMarginBottom( Const Value: Cardinal );
209
      procedure SetMarginLeft( Const Value: Cardinal );
210
      procedure SetMarginTop( Const Value: Cardinal );
211
      procedure SetMarginRight( Const Value: Cardinal );
212
      procedure SetPageFooter( Const Value: String );
213
      procedure SetDateFormat( Const Value: String );
214
      procedure SetTimeFormat( Const Value: String );
215
      procedure SetFooterSize( Const Value: Cardinal);
216
      procedure SetHeaderSize( Const Value: Cardinal );
217
            procedure SetOrientation( Const Value: TPrinterOrientation );
218
      procedure SetLogo( Const Value: String );
219
 
220
    public
221
      constructor Create;
222
 
223
    published
224
      property Orientation: TPrinterOrientation read fOrientation write SetOrientation;
225
      property JobTitle: String read fJobTitle write fJobTitle;
226
      property PageTitle: String read fPageTitle write fPageTitle;
227
      property Logo: String read fLogo write SetLogo;
228
      property PageTitleMargin: Cardinal read fpageTitleMargin write fpageTitleMargin;
229
      property PageFooter: String read fPageFooter write SetPageFooter;
230
      property HeaderSize: Cardinal read fHeaderSize write SetHeaderSize;
231
      property FooterSize: Cardinal read fFooterSize write SetFooterSize;
232
      property DateFormat: String read fDateFormat write SetDateFormat;
233
      property TimeFormat: String read fTimeFormat write SetTimeFormat;
234
      property Copies: Cardinal read fCopies write fCopies default 1;
235
      property FromRow: Cardinal read fFromRow write fFromRow;
236
      property ToRow: Cardinal read fToRow write fToRow;
237
      property PreviewPage: Cardinal read fPreviewPage write fPreviewPage default 1;
238
      property BorderStyle: TBorderstyle read fBorderStyle write fBorderStyle;
239
      property Leftpadding: Cardinal read fLeftpadding write fLeftPadding default 2;
240
            property MarginBottom: Cardinal read fMarginBottom write SetMarginBottom;
241
      property MarginLeft: Cardinal read fMarginLeft write SetMarginLeft;
242
      property MarginTop: Cardinal read fMarginTop write SetMarginTop;
243
      property MarginRight: Cardinal read fMarginRight write SetMarginRight;
244
  end;
245
 
246
  {These are the new events defined for TSortGrid.}
247
  TFormatDrawCellEvent = procedure( Sender: TObject; Col, Row: LongInt; State: TGridDrawState;
248
                                    var FormatOptions: TFormatOptions ) of object;
249
  TClickSortEvent      = procedure( Sender: TObject; Col, Row: LongInt; var SortOptions: TSortOptions ) of object;
250
  TUpdateGridEvent     = procedure( Sender: TObject; Index: LongInt ) of object;
251
  TSizeChangedEvent    = procedure( Sender: TObject; OldColCount, OldRowCount: LongInt ) of object;
252
  TBeginSortEvent      = procedure( Sender: TObject; Col: LongInt; var SortOptions: TSortOptions ) of object;
253
  TEndSortEvent        = procedure( Sender: TObject; Col: LongInt ) of object;
254
  TCellValidateEvent   = procedure( Sender: TObject; Col, Row: LongInt; var Value: String;
255
                                    var Valid: Boolean ) of object;
256
 
257
  {Here's the main new class: TSortGrid}
258
  TSortGrid = class( TStringGrid )
259
  private
260
    { Private declarations }
261
    fSortedList:             TSortedList;
262
    fAlignmentHorz:          TAlignment;
263
          fAlignmentVert:          TVertAlignment;
264
    fBevelStyle:             TCellBevelStyle;
265
    fSortState:              TSortState;               // Line modified/added by gnes@zero.it
266
    fSortDirection:          TSortDirection;
267
    fProportionalScrollBars: Boolean;
268
    fCaseSensitive:          Boolean;
269
    fExtendedKeys:           Boolean;
270
    fSorting:                Boolean;
271
    fModified:               Boolean;
272
    fOldModifiedValue:       Boolean;
273
    fEntered:                Boolean;
274
    fSortOnClick:            Boolean;
275
    fSortFooter:             Boolean;
276
    fOldCellText:            String;
277
    fOldCol, fOldRow:        LongInt;
278
    fSortSymbol:             TSortSymbol;
279
    fSortSpacingHor:         Integer;
280
    fSortSpacingVert:        Integer;
281
    fSortColumn:             Integer; // Line modified/added by gnes@zero.it
282
    fFooterRows:             Integer;
283
    gFooterSub:              Integer;
284
    fSortBMA:                TBitmap;
285
    fSortBMD:                TBitmap;
286
          fFooterColor:            TColor;
287
    fFooterFont:             TFont;
288
    fFooterBevelStyle:       TCellBevelStyle;
289
 
290
    fSelectedRows:           TList;
291
    fAnchor:                 LongInt;
292
    fLastMoveOn:             LongInt;
293
    fLastTopRow:             LongInt;
294
    fMouseIsDown:            Boolean;
295
 
296
    fOldRowCol:              TOldRowColValueList;
297
    fWordWrap:               Boolean;
298
    fPrintOptions:           TPrintOptions;
299
    fPageCount:              Cardinal;
300
    fPrintImage:             TBitmap;
301
    fOldFont:                TFont;
302
    fOldBrush:               TBrush;
303
 
304
    fOnGetCellFormat:        TFormatDrawCellEvent;
305
    fOnClickSort:            TClickSortEvent;
306
    fOnRowInsert:            TUpdateGridEvent;
307
          fOnRowDelete:            TUpdateGridEvent;
308
    fOnColumnInsert:         TUpdateGridEvent;
309
    fOnColumnDelete:         TUpdateGridEvent;
310
    fOnColumnWidthsChanged:  TNotifyEvent;
311
    fOnRowHeightsChanged:    TNotifyEvent;
312
    fOnSizeChanged:          TSizeChangedEvent;
313
    fOnBeginSort:            TBeginSortEvent;
314
    fOnEndSort:              TEndSortEvent;
315
    fOnCellValidate:         TCellValidateEvent;
316
    fOnMouseEnter:           TNotifyEvent;
317
    fOnMouseLeave:           TNotifyEvent;
318
 
319
    GSortBM:     TBitmap;
320
    GASE:        Boolean;
321
    GFindString: String;
322
    GStartRow, GEndRow, GStartCol, GEndCol: LongInt;
323
 
324
    procedure SetSortBMA( Value: TBitmap );
325
    procedure SetSortBMD( Value: TBitmap );
326
    procedure SetSortSymbol( Value: TSortSymbol );
327
    procedure SetBevelStyle( Value: TCellBevelStyle );
328
    procedure SetSortColumn( Value: Integer );
329
    procedure SetSortOnClick( Value: Boolean );
330
          procedure SetSortFooter( Value: Boolean );
331
    procedure SetAlignmentHorz( Value: TAlignment );
332
    procedure SetAlignmentVert( Value: TVertAlignment );
333
    procedure SetSortDirection( Value: TSortDirection );
334
    procedure SetSortSpacingHor( Value: Integer );
335
    procedure SetSortSpacingVert( Value: Integer );
336
    procedure SetProportionalScrollBars( Value: Boolean );
337
    procedure SetFooterRows( Value: Integer );
338
    procedure SetFooterColor( Value: TColor );
339
    procedure SetFooterFont( Value: TFont );
340
    procedure SetFooterBevelStyle( Value: TCellBevelStyle );
341
    function  GetSelected( Row: LongInt ): Boolean;
342
    procedure SetSelected( Row: LongInt; Select: Boolean );
343
    function  GetSelectedCount: LongInt;
344
    function  GetSelItems( Index: LongInt ): LongInt;
345
    procedure SetWordWrap( const Value: Boolean );
346
 
347
    procedure SetGSortSymbol;
348
    function  CheckRange( startcr, endcr: Integer; IsRow: Boolean): Boolean;
349
    procedure SetResetASE( SetASE: Boolean );
350
    procedure ToggleRow( aRow: LongInt );
351
    procedure SelectRow( aRow: LongInt; Select: Boolean );
352
    procedure SelectRows( aRow, bRow : LongInt; Select: Boolean );
353
        procedure InvalidateRow( aRow : LongInt );
354
    procedure AutoSizeRowsInt( StartRow, EndRow: LongInt; How: TAutoSize );
355
    procedure ShowRC( StartRC, EndRC: LongInt; IsRC: Integer );
356
    procedure HideRC( StartRC, EndRC: LongInt; IsRC: Integer );
357
    procedure DrawToCanvas( aCanvas: TCanvas; Mode: TPrintMode; FromRow, ToRow: Integer );
358
    procedure WMSize( var Msg: TWMSize); message WM_SIZE;
359
    procedure CMMouseEnter( var Message ); message CM_MOUSEENTER;
360
    procedure CMMouseLeave( var Message ); message CM_MOUSELEAVE;
361
 
362
  protected
363
    { Protected declarations }
364
    procedure ListQuickSort( const aCol: LongInt; const SortOptions: TSortOptions ); virtual;
365
    function  DetermineSortStyle( const aCol: LongInt ): TSortStyle; virtual;
366
    procedure InitializeFormatOptions( const aCol, aRow: LongInt; var FmtOpts: TFormatOptions );
367
    procedure DrawCell( aCol, aRow: LongInt; aRect: TRect; aState: TGridDrawState ); override;
368
    procedure MouseUp( Button: TMouseButton; Shift: TShiftState; X, Y: Integer ); override;
369
    procedure ColWidthsChanged; override;
370
    procedure RowHeightsChanged; override;
371
    procedure SizeChanged( OldColCount, OldRowCount: LongInt ); override;
372
    procedure UpdateScrollPage; virtual;
373
    procedure KeyDown( var Key: Word; Shift: TShiftState ); override;
374
          procedure SetEditText( aCol, aRow: LongInt; const Value: string ); override;
375
    procedure Click; override;
376
    procedure DoEnter; override;
377
    procedure DoExit; override;
378
    procedure InitValidate; virtual;
379
    procedure KeyPress( var Key: Char ); override;
380
    procedure DrawSortSymbol( x, y: Integer );
381
    procedure MouseDown( Button: TMouseButton; Shift: TShiftState; X, Y: Integer );override;
382
    procedure MouseMove( Shift: TShiftState; X, Y: Integer );override;
383
    procedure TopLeftChanged; override;
384
 
385
  public
386
    GSortBMWidth: Integer;
387
    GSortBMHeight: Integer;
388
    { Public declarations }
389
    { run time properties }
390
 
391
    property  Sorting: Boolean read fSorting default False;
392
    property  Modified: Boolean read fModified write fModified default False;
393
    property  SortState: TSortState read fSortState;                       // Line modified/added by gnes@zero.it
394
    property  Selected[ Row: LongInt ]: Boolean read GetSelected write SetSelected;
395
    property  SelectedCount: LongInt read GetSelectedCount;
396
    property  SelectedItems[ Index: LongInt ]: LongInt read GetSelItems;
397
 
398
    constructor Create( AOwner: TComponent ); override;
399
    destructor  Destroy; override;
400
 
401
    procedure MoveTo( aCol, aRow: LongInt ); virtual;
402
    function  Clear: Boolean; virtual;
403
    function  ClearFrom( FromRow: LongInt ): Boolean; virtual;
404
    procedure InsertRow( aRow: LongInt ); virtual;
405
    procedure InsertColumn( aCol: LongInt ); virtual;
406
    procedure DeleteRow( aRow: LongInt ); reintroduce; virtual;
407
    procedure DeleteColumn( aCol: LongInt ); reintroduce; virtual;
408
    procedure MoveRow( FromIndex, ToIndex: LongInt ); virtual;
409
    procedure MoveColumn( FromIndex, ToIndex: LongInt ); virtual;
410
    procedure SwapRows( aRow1, aRow2: LongInt ); virtual;
411
    procedure SwapColumns( aCol1, aCol2: LongInt ); virtual;
412
    procedure AutoSizeCol( const aCol: LongInt ); virtual;
413
    procedure AutoSizeColumns( const DoFixedCols: Boolean; const Padding: Integer ); virtual;
414
    procedure SortByColumn( const aCol: LongInt; SortOptions: TSortOptions ); virtual;
415
    function  IsCell( const Value: String; var aCol, aRow: LongInt ): Boolean; virtual;
416
    procedure LoadFromFile( const FileName: String; const Delimiter: Char ); virtual;
417
    procedure SaveToFile( const FileName: String; const Delimiter: Char ); virtual;
418
    function  CanUndoSort: Boolean; virtual;
419
    procedure UndoSort; virtual;
420
        function  GetCellDrawState( const aCol, aRow: LongInt ): TGridDrawState;
421
    function  SelectCell( aCol, aRow: LongInt ): Boolean; override;
422
    procedure ValidateCell; virtual;
423
    function  InsertRows( aRow, rCount: Integer ): Boolean; virtual;
424
    function  InsertCols( aCol, cCount: Integer ): Boolean; virtual;
425
    function  ClearRows( sRow, eRow: Integer ): Boolean; virtual;
426
    function  RemoveRows( sRow, eRow: Integer ): Boolean; virtual;
427
    function  RemoveCols( sCol, eCol: Integer ): Boolean; virtual;
428
    function  ClearCols( sCol, eCol: Integer ): Boolean; virtual;
429
    function  FindFirst( const aStr: String; var sCol, sRow: LongInt; eCol, eRow: LongInt ): Boolean; virtual;
430
    function  FindNext( var aCol, aRow: LongInt ): Boolean; virtual;
431
    procedure ClearSelection;
432
    procedure ShowRows( StartRow, EndRow: LongInt ); virtual;
433
    procedure HideRows( StartRow, EndRow: LongInt ); virtual;
434
    procedure ShowCols( StartCol, EndCol: LongInt ); virtual;
435
    procedure HideCols( StartCol, EndCol: LongInt ); virtual;
436
    procedure AutoSizeRow( aRow: LongInt ); virtual;
437
    procedure AutoSizeRows( StartRow, EndRow: LongInt ); virtual;
438
    procedure AutoSizeVisibleRows( StartRow, EndRow: LongInt ); virtual;
439
    procedure AutoSizeHiddenRows( StartRow, EndRow: LongInt ); virtual;
440
//    {$IfDef VERD4+}
441
    procedure Print;
442
    procedure PrintPreview;
443
        procedure UpdatePreview( aCanvas: TCanvas );
444
    function  PageCount: Integer;
445
    procedure SmoothResize( var Src, Dst: TBitmap );
446
//    {$EndIf}
447
 
448
  published
449
    { Published declarations }
450
    property CaseSensitive: Boolean read fCaseSensitive write fCaseSensitive;
451
    property AlignmentHorz: TAlignment read fAlignmentHorz write SetAlignmentHorz;
452
    property AlignmentVert: TVertAlignment read fAlignmentVert write SetAlignmentVert;
453
    property BevelStyle: TCellBevelStyle read fBevelStyle write SetBevelStyle default cbNone;
454
    property ProportionalScrollBars: Boolean read fProportionalScrollBars write SetProportionalScrollBars;
455
    property ExtendedKeys: Boolean read fExtendedKeys write fExtendedKeys;
456
    property SortSymbol: TSortSymbol read FSortSymbol write SetSortSymbol default sgNone;
457
    property SortSpacingHor: Integer read FSortSpacingHor write SetSortSpacingHor default 2;
458
    property SortSpacingVert: Integer read FSortSpacingVert write SetSortSpacingVert default 0;
459
    property SortDirection: TSortDirection read FSortDirection write SetSortDirection default sdAscending;
460
    property SortBitMapA: TBitmap read FSortBMA write SetSortBMA nodefault;
461
    property SortBitMapD: TBitmap read FSortBMD write SetSortBMD nodefault;
462
    property SortColumn: Integer read FSortColumn write SetSortColumn default 1;
463
    property SortOnClick: Boolean read FSortOnClick write SetSortOnClick default False;
464
    property SortFooter: Boolean read FSortFooter write SetSortFooter default False;
465
    property FooterRows: Integer read FFooterRows write SetFooterRows default 0;
466
        property FooterColor: TColor read FFooterColor write SetFooterColor default clAqua;
467
    property FooterFont: TFont read FFooterFont write SetFooterFont;
468
    property FooterBevelStyle: TCellBevelStyle read fFooterBevelStyle write SetFooterBevelStyle default cbNone;
469
//    {$IfDef VERD4+}
470
    property PrintOptions: TPrintOptions read fPrintOptions write fPrintOptions;
471
//    {$EndIf}
472
    property WordWrap: Boolean read fWordWrap write SetWordWrap;
473
 
474
    { Published events }
475
    property OnGetCellFormat: TFormatDrawCellEvent read fOnGetCellFormat write fOnGetCellFormat;
476
    property OnClickSort: TClickSortEvent read fOnClickSort write fOnClickSort;
477
    property OnRowInsert: TUpdateGridEvent read fOnRowInsert write fOnRowInsert;
478
    property OnRowDelete: TUpdateGridEvent read fOnRowDelete write fOnRowDelete;
479
    property OnColumnInsert: TUpdateGridEvent read fOnColumnInsert write fOnColumnInsert;
480
    property OnColumnDelete: TUpdateGridEvent read fOnColumnDelete write fOnColumnDelete;
481
    property OnColumnWidthsChanged: TNotifyEvent read fOnColumnWidthsChanged write fOnColumnWidthsChanged;
482
    property OnRowHeightsChanged: TNotifyEvent read fOnRowHeightsChanged write fOnRowHeightsChanged;
483
    property OnSizeChanged: TSizeChangedEvent read fOnSizeChanged write fOnSizeChanged;
484
    property OnBeginSort: TBeginSortEvent read fOnBeginSort write fOnBeginSort;
485
    property OnEndSort: TEndSortEvent read fOnEndSort write fOnEndSort;
486
    property OnCellValidate: TCellValidateEvent read fOnCellValidate write fOnCellValidate;
487
    property OnMouseEnter: TNotifyEvent read fOnMouseEnter write fOnMouseEnter;
488
    property OnMouseLeave: TNotifyEvent read fOnMouseLeave write fOnMouseLeave;
489
  end;
490
 
491
//procedure Register;
492
 
493
function StringCompare( const Str1, Str2: String ): Integer;
494
function DateTimeCompare( const Str1, Str2: String ): Integer;
495
function NumericCompare( const Str1, Str2: String ): Integer;
496
function TimeCompare( const Str1, Str2: String ): Integer;  
497
{$IFDEF VERDPre6}
498
// version 5 or less
499
function TryStrToFloat(s: string; var v: extended): boolean;
500
function TryStrToInt(s: string; var v: integer): boolean;
501
function TryStrToTime(s: string; var v: TDateTime): boolean;
502
function TryStrToDateTime(s: string; var v: TDateTime): boolean;
503
{$endif}
504
 
505
IMPLEMENTATION
506
 
507
uses SortGridPreview;
508
 
509
{$R SortGrid.Res}
510
{$R DefaultSort.Res}
511
 
512
var
513
   //This is here for Compare.  I can't pass it as a parameter,
514
   //and I can't make Compare a method.  So I had to use a global. :-(
515
   GlobalSortOptions: TSortOptions;
516
{$IFDEF VERDPre6}
517
// version 5 or less                     
518
// IF YOU GET AN EXCEPTION HERE WHEN RUNNING FROM THE IDE,
519
// THEN YOU NEED TO TURN OFF "Break on Exception"
520
function TryStrToFloat(s: string; var v: extended): boolean;
521
begin                
522
  if (s = '') or not (s[1] in ['0'..'9']) then
523
    Result := False
524
  else
525
  begin
526
    Result:= true;
527
    try
528
      v := StrToFloat(s);
529
    except
530
      on EConvertError do
531
        Result := false;
532
    end;
533
  end;
534
end;
535
function TryStrToInt(s: string; var v: integer): boolean;
536
begin          
537
  if (s = '') or not (s[1] in ['0'..'9','$']) then
538
    Result := False
539
  else
540
  begin
541
    Result:= true;
542
    try
543
      v := StrToInt(s);
544
    except
545
      on EConvertError do
546
        Result := false;
547
    end;
548
  end;
549
end;
550
function TryStrToTime(s: string; var v: TDateTime): boolean;
551
begin
552
  if (s = '') or not (s[1] in ['0'..'9']) then
553
    Result := False
554
  else
555
  begin
556
    Result:= true;
557
    try
558
      v := StrToTime(s);
559
    except
560
      on EConvertError do
561
        Result := false;
562
    end;
563
  end;
564
end;
565
function TryStrToDateTime(s: string; var v: TDateTime): boolean;
566
begin            
567
  if (s = '') or not (s[1] in ['0'..'9']) then
568
    Result := False
569
  else
570
  begin
571
    Result:= true;
572
    try
573
      v := StrToDateTime(s);
574
    except
575
      on EConvertError do
576
        Result := false;
577
    end;
578
  end;
579
end;
580
{$endif}
581
 
582
{******************************************************************************}
583
{** Miscellaneous Non-Member Functions                                       **}
584
{******************************************************************************}
585
procedure TokenizeGridString( const S: String; const Delimiter: Char; Tokens: TStringList );
586
var
587
   i, Len:   Integer;
588
   CurToken: String;
589
begin
590
   Tokens.Clear;
591
   CurToken := '';
592
   Len:=Length( S );
593
   for i := 1 to Len do
594
   begin
595
      if S[i] = Delimiter then
596
      begin
597
           Tokens.Add( CurToken );
598
           CurToken := '';
599
      end
600
      else
601
          CurToken := CurToken + S[i];
602
   end;
603
   Tokens.Add( CurToken );
604
end;
605
 
606
function StringCompare( const Str1, Str2: String ): Integer;
607
var
608
   c: Integer;
609
begin
610
   c := AnsiCompareStr( str1, str2 );
611
   if c < 0 then Result := -1
612
   else if c > 0 then Result := 1
613
   else Result := 0;
614
end;
615
 
616
function DateTimeCompare( const Str1, Str2: String ): Integer;
617
var
618
   Val1, Val2: TDateTime;
619
begin
620
        Result := 0;
621
   try
622
        if not (TryStrToDateTime( Str1 , Val1 ) and TryStrToDateTime( Str2 , Val2 )) then
623
                exit;
624
 {        Val1 := StrToDateTime( Str1 );
625
          Val2 := StrToDateTime( Str2 );  }
626
      if Val1 < Val2 then Result := -1
627
      else if Val2 < Val1 then Result := 1
628
      else Result := 0;
629
   except
630
      on EConvertError do Result := 0;
631
   end;
632
end;
633
 
634
function TimeCompare( const Str1, Str2: String ): Integer;
635
var
636
   Val1, Val2: TDateTime;
637
begin
638
        Result := 0;
639
   try                      
640
        if not (TryStrToTime( Str1 , Val1 ) and TryStrToTime( Str2 , Val2 )) then
641
                exit;
642
{      Val1:=StrToTime( Str1 );
643
          Val2:=StrToTime( Str2 ); }
644
      if Val1 < Val2 then Result := -1
645
      else if Val2 < Val1 then Result := 1
646
      else Result := 0;
647
   except
648
      on EConvertError do Result := 0;
649
   end;
650
end;
651
 
652
function NumericCompare( const Str1, Str2: String ): Integer;
653
var
654
   Val1, Val2: Extended;
655
begin  
656
        Result := 0;
657
   try                  
658
        if not (TryStrToFloat( Str1 , Val1 ) and TryStrToFloat( Str2 , Val2 )) then
659
                exit;
660
{      Val1 := StrToFloat( Str1 );
661
          Val2 := StrToFloat( Str2 ); }
662
      if Val1 < Val2 then Result := -1
663
      else if Val2 < Val1 then Result := 1
664
      else Result := 0;
665
   except
666
      on EConvertError do Result := 0;
667
   end;
668
end;
669
 
670
//This looks at the global variable GlobalSortOptions.
671
//I hated to use a global, but I can't pass any additional
672
//parameters to Compare, and I can't make Compare a
673
//method of an object.  A global seemed the only choice.
674
function Compare( Item1, Item2: Pointer ): Integer;
675
var
676
   Entry1, Entry2: pSortedListEntry;
677
begin
678
   Entry1 := Item1;
679
   Entry2 := Item2;
680
 
681
   //Handle Case-Insensitivity.
682
   if NOT GlobalSortOptions.SortCaseSensitive then
683
   begin
684
      Entry1^.Str := ANSIUppercase( Entry1^.Str );
685
      Entry2^.Str := ANSIUppercase( Entry2^.Str );
686
   end;
687
 
688
   //Determine compare type and do the comparison.
689
   case GlobalSortOptions.SortStyle of
690
      ssNumeric:  Result := NumericCompare( Entry1^.Str, Entry2^.Str );
691
      ssDateTime: Result := DateTimeCompare( Entry1^.Str, Entry2^.Str );
692
      ssTime:     Result := TimeCompare( Entry1^.Str, Entry2^.Str );
693
      ssCustom:   Result := GlobalSortOptions.SortCompare( Entry1^.Str, Entry2^.Str );
694
      else        Result := StringCompare( Entry1^.Str, Entry2^.Str );
695
   end;
696
 
697
   //Now, make sure we don't swap the rows if the Keys are equal.
698
   //If they're equal then we sort by row number.
699
   if Result = 0 then
700
   begin
701
      if Entry1^.RowNum < Entry2^.RowNum then Result := -1
702
      else if Entry1^.RowNum > Entry2^.RowNum then Result := 1
703
      else Result := 0; //Sometimes an item does get compared to itself.
704
   end
705
   else //Reverse polarity if descending sort.
706
      if GlobalSortOptions.SortDirection = sdDescending then
707
         Result := -1 * Result;
708
end;
709
 
710
{******************************************************************************}
711
{** Public Members for TSortedList                                           **}
712
{******************************************************************************}
713
function TSortedList.GetItem( const i: Integer ): pSortedListEntry;
714
begin
715
   //Cast the pointer.
716
   Result := pSortedListEntry( Items[ i ] );
717
end;
718
 
719
procedure TSortedList.Reset;
720
var
721
   i:     Integer;
722
   Item: pSortedListEntry;
723
begin
724
   //Dispose of anything in the list first.
725
   for i := 0 to Count - 1 do
726
   begin
727
          if Items[i] <> nil then
728
      begin
729
         Item      := Items[ i ];
730
         Item^.Str := '';
731
         Dispose( Items[ i ] );
732
      end;
733
   end;
734
   // Now clear the list.
735
   Clear();
736
end;
737
 
738
{******************************************************************************}
739
{** Public Members for TOldRowColValue                                       **}
740
{******************************************************************************}
741
procedure TOldRowColValueList.SetValue( const rc: LongInt; Const rcValue, IsRC: Integer );
742
var
743
   Item: pOldRowColEntry;
744
begin
745
   New( Item );
746
   Item^.IsRowCol    := IsRC;
747
   Item^.RowColNum   := rc;
748
   Item^.RowColValue := rcValue;
749
   Add( Item );
750
end;
751
 
752
function TOldRowColValueList.GetValue( const rc: LongInt; Const IsRC: Integer ): Integer;
753
var
754
   i:     Integer;
755
   Item: pOldRowColEntry;
756
begin
757
   Result := -1;
758
   for i := 0 to Count - 1 do  // Find the row or column
759
   begin
760
      Item := Items[ i ];
761
      if (Item^.IsRowCol = IsRC) and (Item^.RowColNum = rc) then
762
      begin
763
         Result := Item^.RowColValue;
764
         Exit;
765
      end;
766
   end;
767
end;
768
 
769
procedure TOldRowColValueList.RemRC( Const rc: LongInt; Const IsRC: Integer );
770
var
771
   i:     Integer;
772
   Item: pOldRowColEntry;
773
begin
774
   for i := Count - 1 DownTo 0 do
775
   begin
776
      if Items[ i ] <> nil then
777
      begin
778
         Item := Items[ i ];
779
         if (Item^.IsRowCol = IsRC) and (Item^.RowColNum = rc) then
780
         begin
781
            Dispose( Item );
782
            Delete( i );
783
            Exit;
784
         end;
785
      end;
786
   end;
787
end;
788
 
789
procedure TOldRowColValueList.MoveUp( Const rc: LongInt; Const IsRC: Integer );
790
var
791
   i:     Integer;
792
   Item: pOldRowColEntry;
793
begin
794
   for i := 0 to Count - 1 do if Items[ i ] <> nil then
795
   begin
796
          Item := Items[ i ];
797
      if (Item^.IsRowCol = IsRC) and (Item^.RowColNum >= rc) then
798
         Inc( Item^.RowColNum );
799
   end;
800
 
801
end;
802
 
803
procedure TOldRowColValueList.MoveDown( Const rc: LongInt; Const IsRC: Integer );
804
var
805
   i:     Integer;
806
   Item: pOldRowColEntry;
807
begin
808
   for i := 0 to Count - 1 do if Items[ i ] <> nil then
809
   begin
810
      Item := Items[ i ];
811
      if (Item^.IsRowCol = IsRC) and (Item^.RowColNum < rc) then
812
         Dec( Item^.RowColNum );
813
   end;
814
end;
815
 
816
procedure TOldRowColValueList.Reset;
817
var
818
   i:     Integer;
819
   Item: pOldRowColEntry;
820
begin
821
   for i := 0 to Count - 1 do   // Dispose of anything in the list first.
822
   begin
823
      if Items[ i ] <> nil then
824
      begin
825
         Item := Items[ i ];
826
         Dispose( Item );
827
      end;
828
   end;
829
   Clear();  // Now clear the list.
830
end;
831
 
832
{******************************************************************************}
833
{** Private Members for TSortGrid                                            **}
834
{******************************************************************************}
835
procedure TSortGrid.SetAlignmentHorz(Value: TAlignment);
836
begin
837
   fAlignmentHorz:=Value;
838
   Invalidate;
839
end;
840
 
841
procedure TSortGrid.SetAlignmentVert(Value: TVertAlignment);
842
begin
843
   fAlignmentVert:=Value;
844
   Invalidate;
845
end;
846
 
847
procedure TSortGrid.SetBevelStyle(Value: TCellBevelStyle);
848
begin
849
   fBevelStyle:=Value;
850
   Invalidate;
851
end;
852
 
853
procedure TSortGrid.WMSize(var Msg: TWMSize);
854
begin
855
   inherited;
856
   UpdateScrollPage;
857
end;
858
 
859
procedure TSortGrid.SetProportionalScrollBars( Value: Boolean );
860
begin
861
   fProportionalScrollBars := Value;
862
   UpdateScrollPage;
863
end;
864
 
865
procedure TSortGrid.SetSortBMA( Value: TBitmap );
866
begin
867
        if Value <> fSortBMA then
868
   begin
869
                fSortBMA.Assign( Value );
870
                SetGSortSymbol();
871
                InvalidateRow( 0 );
872
   end;
873
end;
874
 
875
procedure TSortGrid.SetSortBMD( Value: TBitmap );
876
begin
877
        if Value <> fSortBMD then
878
   begin
879
                fSortBMD.Assign( Value );
880
                SetGSortSymbol();
881
                InvalidateRow( 0 );
882
        end;
883
end;
884
 
885
procedure TSortGrid.SetSortOnClick( Value: Boolean );
886
begin
887
        if fSortOnClick <> Value then
888
   begin
889
                fSortOnClick := Value;
890
                InvalidateRow( 0 );
891
        end;
892
end;
893
 
894
procedure TSortGrid.SetSortDirection( Value: TSortDirection );
895
begin
896
        if fSortDirection <> Value then
897
   begin
898
                fSortDirection := Value;
899
                SetGSortSymbol();
900
                InvalidateRow( 0 );
901
        end;
902
end;
903
 
904
procedure TSortGrid.SetSortColumn( Value: Integer );
905
begin
906
        if (fSortColumn <> Value) and (Value >= 0) and (Value < ColCount) then
907
   begin
908
                fSortColumn := Value;
909
                InvalidateRow( 0 );
910
        end;
911
end;
912
 
913
procedure TSortGrid.SetSortSpacingHor( Value: Integer );
914
begin
915
        if fSortSpacingHor <> Value then
916
   begin
917
                fSortSpacingHor := Value;
918
                InvalidateRow( 0 );
919
        end;
920
end;
921
 
922
procedure TSortGrid.SetSortSpacingVert( Value: Integer );
923
begin
924
   if fSortSpacingVert <> Value then
925
   begin
926
                fSortSpacingVert := Value;
927
                InvalidateRow( 0 );
928
        end;
929
end;
930
 
931
procedure TSortGrid.SetSortSymbol( Value: TSortSymbol );
932
begin
933
        if fSortSymbol <> Value then
934
   begin
935
                fSortSymbol := Value;
936
                SetGSortSymbol();
937
                InvalidateRow( 0 );
938
   end;
939
end;
940
 
941
procedure TSortGrid.CMMouseEnter( var Message );
942
begin
943
   if Assigned( fOnMouseEnter ) then
944
      fOnMouseEnter( Self );
945
end;
946
 
947
procedure TSortGrid.CMMouseLeave( var Message );
948
begin
949
   if Assigned( fOnMouseLeave ) then
950
      fOnMouseLeave( Self );
951
end;
952
 
953
procedure TSortGrid.SetSortFooter( Value: Boolean );
954
begin
955
   if fSortFooter <> Value then
956
      fSortFooter := Value;
957
   if fSortFooter then
958
      gFooterSub := 0
959
   else
960
      gFooterSub := fFooterRows;
961
end;
962
 
963
procedure TSortGrid.SetFooterRows( Value: Integer );
964
var
965
   i, FootStart: Integer;
966
begin
967
   if (Value >= 0) and (Value <= RowCount - FixedRows) and (fFooterRows <> Value) then
968
   begin
969
      if Value > fFooterRows then
970
         FootStart := Value
971
      else
972
         FootStart := fFooterRows;
973
      for i := RowCount - 1 downto RowCount - FootStart do
974
         InvalidateRow( i );
975
      fFooterRows := Value;
976
   end;
977
   if NOT fSortFooter then
978
      gFooterSub := fFooterRows;
979
end;
980
 
981
procedure TSortGrid.SetFooterColor( Value: TColor );
982
var
983
   i: Integer;
984
begin
985
   if fFooterColor <> Value then
986
   begin
987
      fFooterColor := Value;
988
      for i := RowCount - 1 downto RowCount - fFooterRows do
989
         InvalidateRow( i );
990
   end;
991
end;
992
 
993
procedure TSortGrid.SetFooterFont( Value: TFont );
994
var
995
   i: Integer;
996
begin
997
   if fFooterFont <> Value then
998
   begin
999
      fFooterFont.Assign( Value );
1000
      for i := RowCount - 1 downto RowCount - fFooterRows do
1001
         InvalidateRow( i );
1002
   end;
1003
end;
1004
 
1005
procedure TSortGrid.SetFooterBevelStyle( Value: TCellBevelStyle );
1006
var
1007
   i: Integer;
1008
begin
1009
   if fFooterBevelStyle <> Value then
1010
   begin
1011
      fFooterBevelStyle := Value;
1012
      for i := RowCount - 1 downto RowCount - fFooterRows do
1013
         InvalidateRow( i );
1014
   end;
1015
end;
1016
 
1017
function TSortGrid.GetSelected( Row: LongInt ): Boolean;
1018
begin
1019
   Result := fSelectedRows.IndexOf( Pointer( Row ) ) > -1 ;
1020
end;
1021
 
1022
procedure TSortGrid.SetSelected( Row: LongInt; Select: Boolean );
1023
begin
1024
   SelectRow( Row, Select );
1025
end;
1026
 
1027
function TSortGrid.GetSelectedCount: LongInt;
1028
begin
1029
   Result := fSelectedRows.Count;
1030
end;
1031
 
1032
function TSortGrid.GetSelItems( Index: LongInt ): LongInt;
1033
begin
1034
   Result := LongInt( fSelectedRows.Items[ Index - 1 ] );
1035
end;
1036
 
1037
procedure TSortGrid.SetWordWrap( const Value: Boolean );
1038
begin
1039
   if Value <> fWordWrap then
1040
   begin
1041
      fWordWrap := Value;
1042
      Invalidate;
1043
   end;
1044
end;
1045
 
1046
{******************************************************************************}
1047
{** Private Members for TPrintOptions                                        **}
1048
{******************************************************************************}
1049
procedure TPrintOptions.SetDateFormat( Const Value: String );
1050
begin
1051
   fDateFormat := Value;
1052
end;
1053
 
1054
procedure TPrintOptions.SetFooterSize( Const Value: Cardinal );
1055
begin
1056
   fFooterSize := Value;
1057
end;
1058
 
1059
procedure TPrintOptions.SetHeaderSize( Const Value: Cardinal );
1060
begin
1061
   fHeaderSize := Value;
1062
end;
1063
 
1064
procedure TPrintOptions.SetLogo( Const Value: String );
1065
begin
1066
   fLogo := Value;
1067
end;
1068
 
1069
procedure TPrintOptions.SetMarginBottom( Const Value: Cardinal );
1070
begin
1071
   fMarginBottom := Value;
1072
end;
1073
 
1074
procedure TPrintOptions.SetMarginLeft( Const Value: Cardinal );
1075
begin
1076
   fMarginLeft := Value;
1077
end;
1078
 
1079
procedure TPrintOptions.SetMarginRight( Const Value: Cardinal );
1080
begin
1081
   fMarginRight := Value;
1082
end;
1083
 
1084
procedure TPrintOptions.SetMarginTop( Const Value: Cardinal );
1085
begin
1086
   fMarginTop := Value;
1087
end;
1088
 
1089
procedure TPrintOptions.SetOrientation( Const Value: TPrinterOrientation );
1090
begin
1091
   fOrientation := Value;
1092
end;
1093
 
1094
procedure TPrintOptions.SetPageFooter( Const Value: String );
1095
begin
1096
   fPageFooter := Value;
1097
end;
1098
 
1099
procedure TPrintOptions.SetTimeFormat( Const Value: String );
1100
begin
1101
   fTimeFormat := Value;
1102
end;
1103
 
1104
{******************************************************************************}
1105
{** Private Members for TSortGrid                                            **}
1106
{******************************************************************************}
1107
procedure TSortGrid.ToggleRow( aRow: LongInt );
1108
var
1109
  aCol:  Longint;
1110
  Index: Integer;
1111
begin
1112
  Index := fSelectedRows.IndexOf( Pointer( aRow ) );
1113
  if Index <> -1 then
1114
     fSelectedRows.Delete( Index )
1115
  else
1116
     fSelectedRows.Add( Pointer( aRow ) );
1117
  for aCol := FixedCols to Pred( ColCount ) do
1118
        InvalidateCell( aCol, aRow );
1119
end;
1120
 
1121
procedure TSortGrid.InvalidateRow( aRow: LongInt );
1122
var
1123
  aCol: LongInt;
1124
begin
1125
  for aCol := FixedCols to Pred( ColCount ) do
1126
    InvalidateCell( aCol, aRow );
1127
end;
1128
 
1129
procedure TSortGrid.SelectRow( aRow: LongInt; Select: Boolean );
1130
var
1131
  ListIndex: Integer;
1132
begin
1133
  ListIndex := fSelectedRows.IndexOf( Pointer( aRow ) );
1134
  if ( ListIndex = -1 ) and (Select) then
1135
     begin
1136
        fSelectedRows.Add( Pointer( aRow ) );
1137
        InvalidateRow( aRow );
1138
     end
1139
  else if ( ListIndex <> -1 ) and (NOT Select) then
1140
     begin
1141
                fSelectedRows.Delete( ListIndex );
1142
        InvalidateRow( aRow );
1143
     end;
1144
end;
1145
 
1146
procedure TSortGrid.SelectRows( aRow, bRow: LongInt; Select: Boolean );
1147
var
1148
  Index, StartRow, EndRow: LongInt;
1149
begin
1150
  if aRow > bRow then
1151
     begin
1152
        StartRow := bRow;
1153
        EndRow   := aRow;
1154
     end
1155
  else
1156
     begin
1157
        StartRow := aRow;
1158
        EndRow  :=  bRow;
1159
     end;
1160
  for Index := StartRow to EndRow do
1161
     SelectRow( Index, Select );
1162
end;
1163
 
1164
 
1165
{******************************************************************************}
1166
{** Protected Members for TSortGrid                                          **}
1167
{******************************************************************************}
1168
procedure TSortGrid.ListQuickSort( const aCol: LongInt; const SortOptions: TSortOptions );
1169
var
1170
   i:           Integer;
1171
   Item:       pSortedListEntry;
1172
   BufferGrid:  TStringGrid;
1173
begin
1174
   //Let everyone know we're sorting.
1175
   fSorting := True;
1176
   try
1177
      //Get rid of any old entries in the sorted list.
1178
      fSortedList.Reset;
1179
 
1180
      //Set the sort options for the list.
1181
      //"Compare" can only look at GlobalSortOptions.
1182
      GlobalSortOptions := SortOptions;
1183
      SetSortDirection( SortOptions.SortDirection ); // Line modified/added by gnes@zero.it
1184
      fSortColumn := aCol;
1185
 
1186
      //Insert the Row Number and Key (Str) into
1187
          for i := FixedRows to RowCount - 1 - gFooterSub do
1188
      begin
1189
          New( Item );
1190
          Item^.RowNum := i;
1191
          Item^.Str    := Cells[aCol, i];
1192
          fSortedList.Add( Item );
1193
      end;
1194
 
1195
      //Quick Sort the list by key string.
1196
      //Then the row numbers will indicate where
1197
      //each row should be placed.
1198
      //E.g. If list item 0 contains a RowNum of 4 then
1199
      //row 4 should be the first row (position 0).
1200
      fSortedList.Sort( Compare );
1201
 
1202
      BufferGrid := nil;
1203
      try
1204
         //Now rearrange the rows of the grid in sorted order.
1205
         //This is a fast but space inefficient way to do it.
1206
         //First, create a buffer grid and size it correctly.
1207
         BufferGrid := TStringGrid.Create( Self );
1208
 
1209
         BufferGrid.ColCount := ColCount;
1210
                 BufferGrid.RowCount := RowCount;
1211
         //Copy the rows to the buffer grid in sorted order.
1212
         for i := 0 to fSortedList.Count - 1 do
1213
         begin
1214
             Item := fSortedList.GetItem( i );
1215
             BufferGrid.Rows[i + FixedRows].Assign( Rows[Item^.RowNum] );
1216
         end;
1217
         //Now put the rows back into the original grid.
1218
         for i := FixedRows to RowCount - 1 - gFooterSub do
1219
             Rows[i].Assign( BufferGrid.Rows[i] );
1220
      finally
1221
         BufferGrid.Free;
1222
      end;
1223
 
1224
      //Now put the selection back on the right row.
1225
      for i := 0 to fSortedList.Count - 1 do
1226
      begin
1227
         Item := fSortedList.GetItem( i );
1228
         if Item^.RowNum = Row then
1229
         begin
1230
            MoveTo( Col, i + FixedRows );
1231
            Break;
1232
         end;
1233
          end;
1234
   finally
1235
      //Make sure we get this turned off.
1236
      fSorting   := False;
1237
      fSortState := ssSorted;   // Now the grid is sorted // Line modified/added by gnes@zero.it
1238
   end;
1239
end;
1240
 
1241
//This function tries to determine the best sort style
1242
//for a column.  If all the entries can be converted to
1243
//numbers, a numeric sort is returned.  If they can all
1244
//be converted to dates, a date sort is returned.  If time,
1245
//then a time sort is returned,
1246
//Otherwise, an alphabetic sort is returned.
1247
function TSortGrid.DetermineSortStyle( const aCol: LongInt ): TSortStyle;
1248
var
1249
   i: Integer;
1250
   DoNumeric, DoDateTime, DoTime: Boolean;
1251
   F: extended;
1252
   dt:TDateTime;
1253
   s: string;
1254
begin
1255
   DoNumeric  := True;
1256
   DoDateTime := True;
1257
   DoTime     := True;
1258
 
1259
   //Note: We only go through the rows once.
1260
   //This code depends on the fact that no
1261
   //entry can be both a date and number.
1262
   for i := FixedRows to RowCount - 1 - gFooterSub do
1263
   begin
1264
      if NOT DoNumeric and NOT doDateTime and NOT doTime then
1265
                 Break; //speed things up a little.
1266
          s := Cells[aCol, i];
1267
          if DoNumeric then
1268
                  DoNumeric := TryStrToFloat(s ,f);
1269
 
1270
          if DoTime then
1271
                  DoTime := TryStrToTime( s , dt );
1272
 
1273
          if DoDateTime then
1274
                  DoDateTime := TryStrToDateTime( s , dt );
1275
   end;
1276
 
1277
   if DoNumeric then
1278
      Result := ssNumeric
1279
   else if DoDateTime then
1280
      Result := ssDateTime
1281
   else if DoTime then
1282
      Result := ssTime
1283
   else
1284
      Result := ssAlphabetic;
1285
end;
1286
 
1287
procedure TSortGrid.InitializeFormatOptions( const aCol, aRow: LongInt; var FmtOpts: TFormatOptions );
1288
begin
1289
   // Setup good defaults for FormatOptions.
1290
   if aRow > RowCount - 1 - fFooterRows then
1291
   begin
1292
      Canvas.Font         := fFooterFont;
1293
      Canvas.Brush.Color  := fFooterColor;
1294
      FmtOpts.Bevel.Style := fFooterBevelStyle;
1295
   end else
1296
      FmtOpts.Bevel.Style := fBevelStyle;
1297
 
1298
   FmtOpts.HideText      := False;
1299
   FmtOpts.Font          := Canvas.Font;
1300
   FmtOpts.Brush         := Canvas.Brush;
1301
   FmtOpts.AlignmentHorz := AlignmentHorz;
1302
   FmtOpts.AlignmentVert := AlignmentVert;
1303
 
1304
   // Set defaults for the bevel colors.
1305
   case BevelStyle of
1306
      cbRaised:
1307
      begin
1308
         FmtOpts.Bevel.UpperLeftColor  := clBtnHighlight;
1309
         FmtOpts.Bevel.LowerRightColor := clBtnShadow;
1310
      end;
1311
      cbLowered:
1312
      begin
1313
         FmtOpts.Bevel.UpperLeftColor  := clBtnShadow;
1314
         FmtOpts.Bevel.LowerRightColor := clBtnHighlight;
1315
      end;
1316
      else
1317
         FmtOpts.Bevel.UpperLeftColor  := clWindow;
1318
         FmtOpts.Bevel.LowerRightColor := clWindow;
1319
   end;
1320
end;
1321
 
1322
procedure TSortGrid.DrawCell( aCol, aRow: LongInt; aRect: TRect; aState: TGridDrawState );
1323
var
1324
   xOffset, yOffset, w: Integer;
1325
   FmtOpts:  TFormatOptions;
1326
   NewState: TGridDrawState;
1327
begin
1328
   InitializeFormatOptions( aCol, aRow, FmtOpts );
1329
 
1330
   NewState := aState;
1331
   if (fSelectedRows.IndexOf( Pointer( aRow ) ) > -1) then
1332
      Include( NewState, gdSelected )
1333
   else
1334
      Exclude( NewState, gdSelected );
1335
   if not (gdFixed in NewState) and (aRow <= RowCount - 1 - fFooterRows) and (goRangeSelect in Options) then
1336
   begin
1337
      if (gdSelected in NewState) then
1338
      begin
1339
         FmtOpts.Brush.Color := clHighlight;
1340
         FmtOpts.Font.Color  := clHighlightText;
1341
      end else
1342
      begin
1343
         FmtOpts.Brush.Color := clWindow;
1344
         FmtOpts.Font.Color  := clWindowText;
1345
      end;
1346
   end;
1347
 
1348
   // Now do the OnGetCellFormat event if necessary.
1349
   if Assigned( fOnGetCellFormat ) then
1350
      fOnGetCellFormat( Self, aCol, aRow, aState, FmtOpts );
1351
 
1352
   if DefaultDrawing then
1353
   begin
1354
      // Calculate horizontal offset.
1355
      case FmtOpts.AlignmentHorz of
1356
         taRightJustify:
1357
            xOffset := aRect.Right - aRect.Left - Canvas.TextWidth( Cells[aCol, aRow] )- 2;
1358
         taCenter:
1359
            xOffset := (aRect.Right - aRect.Left - Canvas.TextWidth( Cells[aCol, aRow] )) div 2;
1360
         else
1361
            xOffset := 2;
1362
      end;
1363
 
1364
      // Calculate vertical offset.
1365
      case FmtOpts.AlignmentVert of
1366
          taBottomJustify:
1367
             yOffset := aRect.Bottom - aRect.Top - Canvas.TextHeight( Cells[aCol, aRow] )- 3;
1368
          taMiddle:
1369
             yOffset := (aRect.Bottom - aRect.Top - Canvas.TextHeight( Cells[aCol, aRow] )) div 2;
1370
          else
1371
             yOffset := 2;
1372
      end;
1373
 
1374
      // Now do the text drawing.
1375
      if NOT FmtOpts.HideText then
1376
         Canvas.TextRect( aRect, aRect.Left + xOffset, aRect.Top + yOffset, Cells[aCol, aRow] )
1377
      else
1378
         Canvas.TextRect( aRect, aRect.Left + xOffset, aRect.Top + yOffset, '' );
1379
 
1380
      // Draw a sort marker.
1381
      if (SortSymbol <> sgNone) and (aRow = 0) and (aCol = SortColumn) and (FixedRows > 0) then
1382
      begin
1383
         w := Canvas.TextWidth( Cells[aCol, aRow] );
1384
         DrawSortSymbol( aRect.Left + xOffset + w + SortSpacingHor, aRect.Top + yOffset + SortSpacingVert );
1385
      end;
1386
 
1387
      // Draw Bevel.
1388
      if (FmtOpts.Bevel.Style <> cbNone) and (aCol >= FixedCols) and (aRow >= FixedRows) then
1389
      begin
1390
         //Draw from bottom-most lines out to mimic behaviour of
1391
         //fixed cells when FixedXXXXLine is toggled.
1392
         with ARect do
1393
            begin
1394
               if goFixedVertLine in Options then
1395
               begin
1396
                  Canvas.Pen.Color := FmtOpts.Bevel.LowerRightColor;
1397
                  Canvas.PolyLine( [Point( Right - 1, Top ), Point( Right - 1, Bottom )] );
1398
               end;
1399
               if goFixedHorzLine in Options then
1400
               begin
1401
                  Canvas.Pen.Color := FmtOpts.Bevel.LowerRightColor;
1402
                  Canvas.PolyLine( [Point(Left, Bottom - 1), Point(Right, Bottom - 1)] );
1403
               end;
1404
               if goFixedVertLine in Options then
1405
               begin
1406
                  Canvas.Pen.Color := FmtOpts.Bevel.UpperLeftColor;
1407
                  Canvas.PolyLine( [Point( Left, Top ), Point( Left, Bottom )] );
1408
               end;
1409
               if goFixedHorzLine in Options then
1410
               begin
1411
                  Canvas.Pen.Color := FmtOpts.Bevel.UpperLeftColor;
1412
                  Canvas.PolyLine( [Point( Left, Top ), Point( Right, Top )] );
1413
            end;
1414
         end;
1415
      end;
1416
      if Assigned( OnDrawCell ) then
1417
         OnDrawCell( Self, aCol, aRow, aRect, NewState );
1418
   end else
1419
      inherited DrawCell( aCol, aRow, aRect, NewState );
1420
end;
1421
 
1422
procedure TSortGrid.DrawSortSymbol( x, y: Integer );
1423
var
1424
   MyCol: TColor;
1425
begin
1426
        if Assigned( GSortBM ) then
1427
   begin
1428
      if SortSymbol = sgCustom then
1429
         MyCol := GSortBM.Canvas.Pixels[0, 0]
1430
      else
1431
         MyCol := clAqua;
1432
                Canvas.BrushCopy( Rect(x, y, x + GSortBM.Width, y + GSortBM.Height ), GSortBM, Rect( 0, 0, GSortBM.Width, GSortBM.Height ), MyCol );
1433
        end;
1434
end;
1435
 
1436
procedure TSortGrid.SetGSortSymbol;
1437
var
1438
   pos: Integer;
1439
   RcStr: String;
1440
begin
1441
        GSortBM.Free;                                                           // Delete the old bitmap if present.
1442
        GSortBM := nil;
1443
        GSortBMWidth  := 0;
1444
   GSortBMHeight := 0;
1445
        if SortSymbol <> sgNone then           // Do we use a bitmap?
1446
   begin
1447
                GSortBM := TBitmap.Create;          // Yes, create a new bitmap.
1448
                if SortSymbol = sgCustom then
1449
      begin
1450
                        // Copy the custom Bitmap to the Sort Bitmap.
1451
         if SortDirection = sdAscending then
1452
              GSortBM.Assign( FSortBMA )
1453
         else
1454
            GSortBM.Assign( FSortBMD );
1455
      end else                                                                  // It's an internal bitmap symbol...
1456
      begin
1457
         pos := 0;
1458
         if SortSymbol <> sgArrow then
1459
            pos := 2;
1460
         if SortDirection <> sdAscending then
1461
            Inc( pos );
1462
                        RcStr := Copy( 'SORTUPSORTDNSORTAZSORTZA', pos * 6 + 1, 6 );
1463
                        // Load it from the resource.
1464
                        GSortBM.Handle := LoadBitmap( HInstance, pChar( RcStr ) );
1465
     end;
1466
     GSortBMWidth  := GSortBM.Width;
1467
     GSortBMHeight := GSortBM.Height;
1468
        end;
1469
end;
1470
 
1471
procedure TSortGrid.MouseUp( Button: TMouseButton; Shift: TShiftState; X, Y: Integer );
1472
var
1473
   Point:         TPoint;
1474
   aCol, aRow:    LongInt;
1475
   SortOptions:   TSortOptions;
1476
   CurrentCursor: TCursor;
1477
begin
1478
   //Make sure we're not sizing and have a header row.
1479
   if Focused and SortOnClick and (fGridState = gsNormal) and (FixedRows >= 1) and (Shift = []) then
1480
   begin
1481
      Point.x := X;
1482
      Point.y := Y;
1483
      MouseToCell( Point.x, Point.y, aCol, aRow );
1484
      //Make sure they clicked a fixed row.
1485
      if (aRow >= 0) and (aRow <= (FixedRows - 1)) then
1486
      begin
1487
         SortOptions.SortStyle := ssAutomatic;
1488
         if Button = mbRight then
1489
            SortOptions.SortDirection := sdDescending
1490
         else
1491
            SortOptions.SortDirection := sdAscending;
1492
 
1493
         { EWE: Set case sensitivity here }
1494
         SortOptions.SortCaseSensitive := fCaseSensitive;
1495
 
1496
         SortOptions.SortCompare := nil;
1497
         if Assigned( fOnClickSort ) then
1498
            fOnClickSort( Self, aCol, aRow, SortOptions );
1499
         CurrentCursor := Screen.Cursor;
1500
         try
1501
            Screen.Cursor := crHourglass;
1502
            SortByColumn( aCol, SortOptions );
1503
         finally
1504
            Screen.Cursor := CurrentCursor;
1505
         end;
1506
      end;
1507
   end;
1508
   inherited MouseUp( Button, Shift, X, Y );
1509
   fMouseIsDown := False;
1510
end;
1511
 
1512
procedure TSortGrid.ColWidthsChanged;
1513
begin
1514
   inherited ColWidthsChanged;
1515
   if Assigned( fOnColumnWidthsChanged ) then
1516
      fOnColumnWidthsChanged( Self );
1517
   UpdateScrollPage;
1518
end;
1519
 
1520
procedure TSortGrid.RowHeightsChanged;
1521
begin
1522
   inherited RowHeightsChanged;
1523
   if Assigned( fOnRowHeightsChanged ) then
1524
      fOnRowHeightsChanged( Self );
1525
   UpdateScrollPage;
1526
end;
1527
 
1528
procedure TSortGrid.SizeChanged( OldColCount, OldRowCount: LongInt );
1529
begin
1530
   inherited SizeChanged( OldColCount, OldRowCount );
1531
   if Assigned( fOnSizeChanged ) then
1532
      fOnSizeChanged( Self, OldColCount, OldRowCount );
1533
   UpdateScrollPage;
1534
end;
1535
 
1536
procedure TSortGrid.UpdateScrollPage;
1537
   function LMax( const A, B: LongInt ): LongInt;
1538
   begin
1539
      Result := B;
1540
      if A > B then Result := A;
1541
   end;
1542
var
1543
   SI: TScrollInfo;
1544
begin
1545
   {Make the scroll bar(s) proportional.}
1546
   {To do this correctly, I should sum colwidths and rowheights,
1547
   but I just approximate by basing the proportion on visible rows or cols
1548
   divided by row or col count...}
1549
   {Also, I can't really figure out Borland's scroll bar range and position
1550
   scheme.  Thus, sometimes when you click on the end of the scroll bar, you
1551
   still have to scroll farther with the arrows to actually get to the end
1552
   of the grid.  If anyone knows how to fix this, PLEASE let me know...}
1553
   if (ScrollBars = ssVertical) or (ScrollBars = ssBoth) then
1554
   begin
1555
      SI.cbSize := SizeOf( SI );
1556
      SI.fMask:=SIF_PAGE or SIF_POS or SIF_RANGE;
1557
      GetScrollInfo( Handle, SB_VERT, SI );
1558
      SI.fMask := SIF_PAGE;
1559
      if ProportionalScrollBars then
1560
      begin
1561
         SI.nPage := LMax(Round(((1.0*(VisibleRowCount+FixedRows))/RowCount)*(SI.nMax-SI.nMin+1)), 1)
1562
      end else
1563
         SI.nPage := 0;
1564
         SetScrollInfo( Handle, SB_VERT, SI, True );
1565
   end;
1566
   if (ScrollBars = ssHorizontal) or (ScrollBars = ssBoth) then
1567
   begin
1568
      SI.cbSize := SizeOf( SI );
1569
      SI.fMask := SIF_PAGE or SIF_POS or SIF_RANGE;
1570
      GetScrollInfo( Handle, SB_HORZ, SI );
1571
      SI.fMask := SIF_PAGE;
1572
      if ProportionalScrollBars then
1573
      begin
1574
         SI.nPage := LMax(Round(((1.0*(VisibleColCount+FixedCols))/ColCount)*(SI.nMax-SI.nMin+1)), 1)
1575
      end else
1576
         SI.nPage := 0;
1577
         SetScrollInfo( Handle, SB_HORZ, SI, True );
1578
   end;
1579
end;
1580
 
1581
procedure TSortGrid.KeyDown( var Key: Word; Shift: TShiftState );
1582
begin
1583
   inherited KeyDown( Key, Shift );
1584
   if ExtendedKeys and NOT EditorMode then
1585
   begin
1586
      if Shift = [ssCtrl] then
1587
      begin
1588
         case Key of
1589
            VK_INSERT: InsertRow( Row );
1590
            VK_DELETE: if RowCount > (FixedRows + 1) then
1591
                          DeleteRow( Row );
1592
         end;
1593
      end
1594
      else if Shift = [ssCtrl, ssShift] then
1595
      begin
1596
         case Key of
1597
            VK_INSERT: InsertColumn( Col );
1598
            VK_DELETE: if ColCount > (FixedCols + 1) then
1599
                          DeleteColumn( Col );
1600
         end;
1601
      end;
1602
   end;
1603
end;
1604
 
1605
procedure TSortGrid.SetEditText( aCol, aRow: LongInt; const Value: String );
1606
begin
1607
   try
1608
      if Value <> Cells[aCol, aRow] then
1609
         Modified := True;
1610
   finally
1611
      inherited SetEditText( aCol, aRow, Value );
1612
   end;
1613
end;
1614
 
1615
procedure TSortGrid.Click;
1616
begin
1617
   try
1618
      inherited Click;
1619
   finally
1620
      if fEntered then
1621
         ValidateCell;
1622
   end;
1623
end;
1624
 
1625
procedure TSortGrid.DoEnter;
1626
begin
1627
   try
1628
      inherited DoEnter;
1629
      fEntered := True;
1630
   finally
1631
      InitValidate;
1632
   end;
1633
end;
1634
 
1635
procedure TSortGrid.DoExit;
1636
begin
1637
   try
1638
      Click;
1639
   finally
1640
      inherited DoExit;
1641
      fEntered := False;
1642
   end;
1643
end;
1644
 
1645
procedure TSortGrid.InitValidate;
1646
begin
1647
   fOldCol := Col;
1648
   fOldRow := Row;
1649
   fOldCellText := Cells[ fOldCol, fOldRow ];
1650
   fOldModifiedValue := Modified;
1651
end;
1652
 
1653
procedure TSortGrid.TopLeftChanged;
1654
begin
1655
   inherited TopLeftChanged;
1656
   if fMouseIsDown then
1657
   begin
1658
      if TopRow > fLastTopRow then
1659
      begin
1660
         fLastMoveOn := TopRow + VisibleRowCount - 1;
1661
         SelectRow( TopRow + VisibleRowCount - 1, True );
1662
      end;
1663
   end;
1664
   fLastTopRow := TopRow;
1665
end;
1666
 
1667
procedure TSortGrid.MouseMove( Shift: TShiftState; X, Y: Integer );
1668
var
1669
  aCol, aRow: LongInt;
1670
begin
1671
  inherited MouseMove( Shift, X, Y );
1672
  if fMouseIsDown then
1673
    begin
1674
      MouseToCell( X, Y, aCol, aRow );
1675
      if ( aRow <> fLastMoveOn ) then
1676
        begin
1677
          if ( aRow >= fAnchor ) and ( aRow < fLastMoveOn ) then
1678
            begin
1679
              SelectRows( fLastMoveOn , aRow , False );
1680
              if aRow = fAnchor then
1681
                SelectRow( fAnchor , True );
1682
            end
1683
          else if ( aRow <= fAnchor ) and ( aRow > fLastMoveOn ) then
1684
            begin
1685
              SelectRows( fLastMoveOn, aRow , False );
1686
              if aRow = fAnchor then
1687
                SelectRow( fAnchor, True );
1688
            end
1689
          else if ( aRow < fAnchor ) and ( fLastMoveOn > fAnchor ) then
1690
            begin
1691
              SelectRows( fLastMoveOn, fAnchor + 1, False );
1692
              SelectRows( fAnchor, aRow, True );
1693
            end
1694
          else if ( aRow > fAnchor ) and ( fLastMoveOn < fAnchor ) then
1695
            begin
1696
              SelectRows( fLastMoveOn, fAnchor - 1, False );
1697
              SelectRows( fAnchor, aRow, True );
1698
            end
1699
          else
1700
            SelectRows( aRow, fAnchor, True );
1701
          fLastMoveOn := aRow;
1702
        end;
1703
    end;
1704
end;
1705
 
1706
procedure TSortGrid.MouseDown( Button: TMouseButton; Shift: TShiftState; X, Y: Integer );
1707
var
1708
   aRow, aCol: LongInt;
1709
begin
1710
   inherited MouseDown( Button, Shift, X, Y );
1711
   if (Button = mbLeft) and (goRangeSelect in Options) then
1712
   begin
1713
      MouseToCell( X, Y, aCol, aRow );
1714
      if aRow < FixedRows then
1715
         Exit;
1716
      fMouseIsDown := True;
1717
      fLastMoveOn  := aRow;
1718
 
1719
      if ssCtrl in Shift then
1720
      begin
1721
         if aRow > -1 then
1722
         begin
1723
            ToggleRow( aRow );
1724
            fAnchor := aRow;
1725
         end;
1726
      end else if ssShift in Shift then
1727
      begin
1728
         fSelectedRows.Clear;
1729
         SelectRows( fAnchor, aRow, True );
1730
      end else
1731
      begin
1732
         if fSelectedRows.Count > 0 then
1733
            fSelectedRows.Clear;
1734
         if aRow > -1 then
1735
         begin
1736
            fSelectedRows.Add( Pointer( aRow ) );
1737
            fAnchor := aRow;
1738
         end;
1739
         Refresh;
1740
      end;
1741
   end;
1742
end;
1743
 
1744
{******************************************************************************}
1745
{** Public Members for TPrintOptions                                         **}
1746
{******************************************************************************}
1747
constructor TPrintOptions.Create;
1748
begin
1749
   inherited Create;
1750
   PageFooter  := 'date|time|page';
1751
   DateFormat  := 'd-mmm-yyyy';
1752
   TimeFormat  := 'h:nn';
1753
   fCopies      := 1;
1754
   fLeftPadding := 2;
1755
   fPreviewPage := 1;
1756
end;
1757
 
1758
{******************************************************************************}
1759
{** Public Members for TSortGrid                                             **}
1760
{******************************************************************************}
1761
constructor TSortGrid.Create( AOwner: TComponent );
1762
begin
1763
   inherited Create( AOwner );
1764
   fSortedList              := TSortedList.Create;
1765
   fCaseSensitive           := False;  { dflt to no case sensitivity }
1766
   fAlignmentHorz           := taLeftJustify;
1767
   fAlignmentVert           := taTopJustify;
1768
   fBevelStyle              := cbNone;
1769
   fProportionalScrollBars  := True;
1770
   fExtendedKeys            := False;
1771
   fSorting                 := False;
1772
   fModified                := False;
1773
   fEntered                 := False;
1774
   fSortState               := ssUnsorted;     // Line modified/added by gnes@zero.it
1775
   fSortBMA                 := TBitmap.Create;
1776
   fSortBMD                 := TBitmap.Create;
1777
   GSortBM                  := nil;
1778
   fSortSymbol              := sgNone;
1779
   fSortSpacingHor          := 2;
1780
   fSortSpacingVert         := 0;
1781
   fSortColumn              := 1;
1782
   fSortDirection           := sdAscending;
1783
   fSortOnClick             := True;
1784
   fSortFooter              := False;
1785
   fFooterRows              := 0;
1786
   gFooterSub               := 0;
1787
   fFooterColor             := clAqua;
1788
   fFooterFont              := TFont.Create;
1789
   fFooterBevelStyle        := cbNone;
1790
   gASE                     := False;
1791
   fSelectedRows            := TList.Create;
1792
   fSelectedRows.Add( Pointer( FixedRows ) );
1793
   fAnchor                  := FixedRows;
1794
   fMouseIsDown             := False;
1795
   fLastTopRow              := TopRow;
1796
   fOldRowCol               := TOldRowColValueList.Create;
1797
   fPrintOptions            := TPrintOptions.Create;
1798
   fPrintOptions.HeaderSize := Font.Size + 2;
1799
   fPrintOptions.FooterSize := fFooterFont.Size - 1;
1800
   fOldFont                 := TFont.Create;
1801
   fOldBrush                := TBrush.Create;
1802
   fOldFont.Assign( Canvas.Font );
1803
   fOldBrush.Assign( Canvas.Brush );
1804
 
1805
   InitValidate;
1806
end;
1807
 
1808
destructor TSortGrid.Destroy;
1809
begin
1810
   fOldBrush.Free;
1811
   fOldFont.Free;
1812
   fPrintOptions.Free;
1813
   fOldRowCol.Reset;
1814
   fOldRowCol.Free;
1815
   fSelectedRows.Free;
1816
   fFooterFont.Free;
1817
   fSortBMA.Free;
1818
   fSortBMD.Free;
1819
   gSortBM.Free;  //    Delete the old bitmap if present.
1820
   fSortedList.Reset;
1821
   fSortedList.Free;
1822
   inherited Destroy;
1823
end;
1824
 
1825
procedure TSortGrid.ValidateCell;
1826
var
1827
   Value: String;
1828
   Valid: Boolean;
1829
begin
1830
   if fOldCellText <> Cells[fOldCol, fOldRow] then
1831
   begin
1832
      Value := Cells[fOldCol, fOldRow];
1833
      Valid := True;
1834
      if Assigned( fOnCellValidate ) then
1835
         fOnCellValidate( Self, fOldCol, fOldRow, Value, Valid );
1836
      //Since Value is also a VAR parameter, we always
1837
      //use it if it was changed in OnCellValidate.
1838
      if NOT Valid then
1839
      begin
1840
         if Value <> Cells[fOldCol, fOldRow] then
1841
            Cells[fOldCol, fOldRow] := Value
1842
         else
1843
             Cells[fOldCol, fOldRow] := fOldCellText;
1844
         Modified := fOldModifiedValue;
1845
      end else
1846
         if Value <> Cells[fOldCol, fOldRow] then
1847
            Cells[fOldCol, fOldRow] := Value;
1848
   end;
1849
   InitValidate;
1850
end;
1851
 
1852
//AutoSizes the aCol column.
1853
procedure TSortGrid.AutoSizeCol( const aCol: LongInt );
1854
var
1855
   MaxWidth, TextW, i: Integer;
1856
   FmtOpts:            TFormatOptions;
1857
begin
1858
   //Resize the column to display the largest value.
1859
   MaxWidth := 0;
1860
   Canvas.Font := Font;
1861
   for i := 0 to RowCount - 1 do
1862
   begin
1863
      InitializeFormatOptions( aCol, i, FmtOpts );
1864
      if Assigned( fOnGetCellFormat ) then
1865
         fOnGetCellFormat( Self, Col, i, GetCellDrawState( aCol, i ), FmtOpts );
1866
      Canvas.Font := FmtOpts.Font;
1867
      TextW := Canvas.TextWidth( Cells[aCol, i] );
1868
      if TextW > MaxWidth then
1869
         MaxWidth := TextW;
1870
   end;
1871
   ColWidths[aCol] := MaxWidth + Canvas.TextWidth( 'x' );
1872
end;
1873
 
1874
//AutoSizes ALL the variable columns and optionally the fixed columns.
1875
procedure TSortGrid.AutoSizeColumns( const DoFixedCols: Boolean; const Padding: Integer );
1876
var
1877
   i: Integer;
1878
begin
1879
   if DoFixedCols then
1880
      for i := 0 to FixedCols - 1 do
1881
      begin
1882
         AutoSizeCol(i);
1883
         if Padding <> 0 then
1884
            ColWidths[i] := ColWidths[i] + Padding;
1885
      end;
1886
   for i := FixedCols to ColCount - 1 do
1887
   begin
1888
      AutoSizeCol( i );
1889
      if Padding <> 0 then
1890
         ColWidths[i] := ColWidths[i] + Padding;
1891
   end;
1892
end;
1893
 
1894
//Sorts the variable rows using Column aCol as a key
1895
procedure TSortGrid.SortByColumn( const aCol: LongInt; SortOptions: TSortOptions );
1896
begin
1897
   //Don't sort while in edit mode.
1898
   if NOT EditorMode then
1899
   begin
1900
      //If there's only one row we don't need to do anything.
1901
      if RowCount > (FixedRows + 1) then
1902
      begin
1903
         //Now we do the Automatic sorting determination.
1904
         if SortOptions.SortStyle = ssAutomatic then
1905
            SortOptions.SortStyle := DetermineSortStyle( aCol );
1906
 
1907
         //Call the OnBeginSort event.
1908
         if Assigned( fOnBeginSort ) then
1909
            fOnBeginSort( Self, aCol, SortOptions );
1910
 
1911
         //Quick Sort column ACol.
1912
         ListQuickSort( aCol, SortOptions );
1913
 
1914
         //Call the OnEndSort event.
1915
         if Assigned( fOnEndSort ) then
1916
            fOnEndSort( Self, aCol );
1917
      end;
1918
   end;
1919
end;
1920
 
1921
procedure TSortGrid.InsertRow( aRow: LongInt );
1922
begin
1923
   RowCount := RowCount + 1;
1924
   fOldRowCol.MoveUp( aRow, 1 );
1925
   MoveRow( RowCount - 1, aRow );
1926
   Rows[aRow].Clear;
1927
   Row := aRow;
1928
   fSortState := ssUnsorted; // Line modified/added by gnes@zero.it
1929
   if Assigned( fOnRowInsert ) then
1930
      fOnRowInsert( Self, aRow );
1931
end;
1932
 
1933
function TSortGrid.InsertRows( aRow, rCount: Integer ): Boolean;
1934
var
1935
   i: Integer;
1936
begin
1937
        if CheckRange( aRow, aRow, True ) then
1938
   begin
1939
      for i := 0 to rCount - 1 do
1940
      begin
1941
                   RowCount := RowCount + 1;
1942
         fOldRowCol.MoveUp( aRow + i, 1 );
1943
         MoveRow( RowCount - 1, aRow );
1944
                   Rows[aRow].Clear();
1945
                   Row := aRow;
1946
                   if Assigned( OnRowInsert ) then
1947
            OnRowInsert( Self, aRow );
1948
           end;
1949
      Result := True;
1950
   end else
1951
      Result := False;
1952
end;
1953
 
1954
procedure TSortGrid.InsertColumn( aCol: LongInt );
1955
begin
1956
   ColCount := ColCount + 1;
1957
   fOldRowCol.MoveUp( aCol, 2 );
1958
   MoveColumn( ColCount - 1, aCol );
1959
   Cols[aCol].Clear;
1960
   Col := aCol;
1961
   if Assigned( fOnColumnInsert ) then
1962
      fOnColumnInsert( Self, aCol );
1963
end;
1964
 
1965
function TSortGrid.InsertCols( aCol, cCount: Integer ): Boolean;
1966
var
1967
   i: Integer;
1968
begin
1969
        if CheckRange( aCol, aCol, False ) then
1970
   begin
1971
     for i := 0 to cCount - 1 do
1972
     begin
1973
       ColCount := ColCount + 1;
1974
       fOldRowCol.MoveUp( aCol + i, 2 );
1975
                   MoveColumn( ColCount - 1, aCol );
1976
                   Cols[aCol].Clear();
1977
                   Col := aCol;
1978
                   if Assigned( OnColumnInsert ) then
1979
        OnColumnInsert( Self, aCol );
1980
           end;
1981
        Result := True;
1982
   end else
1983
      Result := False;
1984
end;
1985
 
1986
function TSortGrid.CheckRange( startcr, endcr: Integer; IsRow: Boolean): Boolean;
1987
var
1988
   aCount: Integer;
1989
begin
1990
   if IsRow = True then
1991
      aCount := RowCount
1992
   else
1993
      aCount := ColCount;
1994
 
1995
        if (startcr >= 0) and (startcr < aCount) and (endcr >= startcr) and (endcr < aCount) then
1996
      Result := True
1997
   else
1998
           Result := False;
1999
end;
2000
 
2001
//Clears the grid.
2002
function TSortGrid.Clear: Boolean;
2003
begin
2004
   Result := ClearRows( 0, RowCount - 1 );
2005
end;
2006
 
2007
function TSortGrid.ClearFrom( FromRow: LongInt ): Boolean;
2008
begin
2009
   Result := ClearRows( FromRow, RowCount - 1 );
2010
end;
2011
 
2012
function TSortGrid.ClearRows( sRow, eRow: Integer ): Boolean;
2013
var
2014
   i: Integer;
2015
begin
2016
   if CheckRange( sRow, eRow, True ) then
2017
   begin
2018
      for i := sRow to eRow do
2019
         Rows[i].Clear();
2020
           Result := True;
2021
      Modified       := False;
2022
      fSortDirection := sdAscending; // Line modified/added by gnes@zero.it
2023
      fSortState     := ssUnsorted;  // Line modified/added by gnes@zero.it
2024
   end else
2025
      Result := False;
2026
end;
2027
 
2028
function TSortGrid.ClearCols( sCol, eCol: Integer ): Boolean;
2029
var
2030
   i: Integer;
2031
begin
2032
        if CheckRange( sCol, eCol, False ) then
2033
   begin
2034
      i := sCol;
2035
      while i <= eCol do
2036
      begin
2037
         Cols[i].Clear();
2038
         Inc( i, 2 );
2039
      end;
2040
           Result := True;
2041
   end else
2042
      Result := False;
2043
end;
2044
 
2045
{ If goAlwaysShowEditor is enabled then RemoveRow
2046
         and MoveRow leave the caret past the last row or
2047
         in one of the fixed rows.  So its turned off before
2048
         the delete and then back on afterward.                          }
2049
procedure TSortGrid.SetResetASE( SetASE: Boolean );
2050
begin
2051
        if SetASE then
2052
   begin
2053
                if goAlwaysShowEditor in Options then
2054
      begin
2055
                        Options := Options - [goAlwaysShowEditor];
2056
                        GASE := True;
2057
                end;
2058
        end else
2059
   begin
2060
      if GASE then
2061
      begin
2062
              Options := Options + [goAlwaysShowEditor];
2063
                   GASE := False;
2064
           end;
2065
   end;
2066
end;
2067
 
2068
procedure TSortGrid.DeleteRow( aRow: LongInt );
2069
var
2070
   i: LongInt;
2071
begin
2072
   if Selected[ aRow ] then
2073
   begin
2074
      SelectRow( aRow, False );
2075
      for i := 0 to SelectedCount do
2076
         if LongInt( fSelectedRows.Items[ i ] ) > aRow then
2077
            fSelectedRows.Items[ i ] := Pointer( LongInt( fSelectedRows.Items[ i ] ) - 1 );
2078
   end;
2079
 
2080
   Rows[ aRow ].Clear;
2081
   {If goAlwaysShowEditor is enabled then DeleteRow
2082
    and MoveRow leave the caret past the last row or
2083
    in one of the fixed rows.  So I turn it off before
2084
    the delete and then back on after to get it
2085
    working correctly.}
2086
        SetResetASE( True );
2087
   fOldRowCol.RemRC( aRow, 1 );  // RCV04
2088
   fOldRowCol.MoveDown( aRow, 1 );  // RCV04
2089
   inherited DeleteRow( aRow );
2090
        SetResetASE( False );
2091
   if Assigned( fOnRowDelete ) then
2092
      fOnRowDelete( Self, aRow );
2093
 
2094
   if fFooterRows > RowCount - FixedRows then
2095
      FooterRows := RowCount - FixedRows;
2096
end;
2097
 
2098
function TSortGrid.RemoveRows( sRow, eRow: Integer ): Boolean;
2099
var
2100
   r: Integer;
2101
begin
2102
        if CheckRange( sRow, eRow, True ) then
2103
   begin
2104
      for r := eRow downto sRow do
2105
      begin
2106
         Rows[r].Clear();
2107
                SetResetASE( True );
2108
         DeleteRow( r );
2109
                SetResetASE( False );
2110
      end;
2111
      Result := True;
2112
   end else
2113
      Result := False;
2114
end;
2115
 
2116
procedure TSortGrid.DeleteColumn( aCol: LongInt );
2117
begin
2118
   Cols[ aCol ].Clear;
2119
   //See DeleteRow for comments...
2120
        SetResetASE( True );
2121
   fOldRowCol.RemRC( aCol, 2 );  // RCV04
2122
   fOldRowCol.MoveDown( aCol, 2 );  // RCV04
2123
   inherited DeleteColumn( aCol );
2124
        SetResetASE( False );
2125
   if Assigned( fOnColumnDelete ) then
2126
      fOnColumnDelete( Self, aCol );
2127
end;
2128
 
2129
function TSortGrid.RemoveCols( sCol, eCol: Integer ): Boolean;
2130
var
2131
   c: Integer;
2132
begin
2133
        if CheckRange( sCol, eCol, False ) then
2134
   begin
2135
      for c := eCol downto sCol do
2136
      begin
2137
                   Cols[ c ].Clear();
2138
                   SetResetASE( True );
2139
                   DeleteColumn( c );
2140
                   SetResetASE( False );
2141
      end;
2142
           Result := True;
2143
   end else
2144
      Result := False;
2145
end;
2146
 
2147
procedure TSortGrid.MoveRow( FromIndex, ToIndex: LongInt );
2148
begin
2149
   //See DeleteRow for comments...
2150
   SetResetASE( True );
2151
   inherited MoveRow( FromIndex, ToIndex );
2152
   SetResetASE( False );
2153
   fSortState := ssUnsorted; // Line modified/added by gnes@zero.it
2154
end;
2155
 
2156
procedure TSortGrid.MoveColumn( FromIndex, ToIndex: LongInt );
2157
begin
2158
   //See DeleteRow for comments...
2159
   SetResetASE( True );
2160
   inherited MoveColumn( FromIndex, ToIndex );
2161
   SetResetASE( False );
2162
end;
2163
 
2164
//The logic gets around a weird case where you swap with the last row.
2165
procedure TSortGrid.SwapRows( aRow1, aRow2: LongInt );
2166
begin
2167
   if aRow1 < aRow2 then
2168
   begin
2169
      MoveRow( aRow2, aRow1 );
2170
      MoveRow( aRow1 + 1, aRow2 );
2171
   end
2172
   else if aRow2 < aRow1 then
2173
   begin
2174
      MoveRow( aRow1, aRow2 );
2175
      MoveRow( aRow2 + 1, aRow1 );
2176
   end;
2177
end;
2178
 
2179
//The logic gets around a weird case where you swap with the last column.
2180
procedure TSortGrid.SwapColumns( aCol1, aCol2: LongInt );
2181
begin
2182
   if aCol1 < aCol2 then
2183
   begin
2184
      MoveColumn( aCol2, aCol1 );
2185
      MoveColumn( aCol1 + 1, aCol2 );
2186
   end
2187
   else if aCol2 < aCol1 then
2188
   begin
2189
      MoveColumn( aCol1, ACol2 );
2190
      MoveColumn( aCol2 + 1, ACol1 );
2191
   end;
2192
end;
2193
 
2194
//Moves the selected cell to (aCol, aRow) and makes it visible.
2195
procedure TSortGrid.MoveTo( aCol, aRow: LongInt );
2196
begin
2197
   if aCol < FixedCols then aCol := FixedCols;
2198
   if aRow < FixedRows then aRow := FixedRows;
2199
   if SelectCell( aCol, aRow ) then
2200
   begin
2201
      Col := aCol;
2202
      Row := aRow;
2203
      MoveColRow( aCol, aRow, True, True );
2204
   end;
2205
end;
2206
 
2207
//Finds a string in the grid.
2208
//It searches by column and returns the first instance it finds.
2209
function TSortGrid.IsCell( const Value: String; var aCol, aRow: LongInt ): Boolean;
2210
var
2211
   i, Place: LongInt;
2212
begin
2213
   Result := False;
2214
   for i := 0 to ColCount - 1 do
2215
   begin
2216
      Place := Cols[i].IndexOf( Value );
2217
      if Place >= 0 then
2218
      begin
2219
         aRow   := Place;
2220
         aCol   := i;
2221
         Result := True;
2222
         Break;
2223
      end;
2224
   end;
2225
end;
2226
 
2227
procedure TSortGrid.LoadFromFile( const FileName: String; const Delimiter: Char );
2228
var
2229
   r:             LongInt;
2230
   Lines, Fields: TStringList;
2231
begin
2232
   Lines  := TStringList.Create;
2233
   Fields := TStringList.Create;
2234
   try
2235
      Clear;
2236
 
2237
      Lines.LoadFromFile( FileName );
2238
      RowCount := Lines.Count;
2239
      ColCount := FixedCols + 1;
2240
      for r := 0 to Lines.Count - 1 do
2241
      begin
2242
         TokenizeGridString( Lines[r], Delimiter, Fields );
2243
         if Fields.Count > ColCount then
2244
            ColCount := Fields.Count;
2245
         Rows[r].Assign( Fields );
2246
      end;
2247
   finally
2248
      Fields.Free;
2249
      Lines.Free;
2250
   end;
2251
end;
2252
 
2253
procedure TSortGrid.SaveToFile( const FileName: String; const Delimiter: Char );
2254
var
2255
   r, c:   LongInt;
2256
   BufStr: String;
2257
   Lines:  TStringList;
2258
begin
2259
   Lines := TStringList.Create;
2260
   try
2261
      Lines.Clear;
2262
      for r := 0 to RowCount - 1 do
2263
      begin
2264
         BufStr := '';
2265
         for c := 0 to ColCount - 1 do
2266
         begin
2267
            BufStr := BufStr + Cells[c, r];
2268
            if c <> (ColCount - 1) then
2269
               BufStr := BufStr + Delimiter;
2270
         end;
2271
         Lines.Add( BufStr );
2272
      end;
2273
      Lines.SaveToFile( FileName );
2274
   finally
2275
      Lines.Free;
2276
   end;
2277
end;
2278
 
2279
function TSortGrid.CanUndoSort: Boolean;
2280
begin
2281
   //We can only undo a sort if we still have exactly the
2282
   //same number of rows that we did when we sorted.
2283
   Result := (fSortedList.Count = (RowCount - FixedRows));
2284
   if Result = False then
2285
      fSortedList.Reset;
2286
end;
2287
 
2288
procedure TSortGrid.UndoSort;
2289
var
2290
   BufferGrid: TStringGrid;
2291
   Item:       pSortedListEntry;
2292
   i:          Integer;
2293
begin
2294
   if CanUndoSort then
2295
   begin
2296
      BufferGrid := nil;
2297
      try
2298
         BufferGrid := TStringGrid.Create( Self );
2299
         BufferGrid.ColCount := ColCount;
2300
         BufferGrid.RowCount := RowCount;
2301
         //Copy the rows to the buffer grid in the current order.
2302
         for i := FixedRows to RowCount - 1 - gFooterSub do
2303
             BufferGrid.Rows[i].Assign( Rows[i] );
2304
         //Now put the rows back into the original grid in the old order.
2305
         for i := 0 to fSortedList.Count - 1 do
2306
         begin
2307
             Item := fSortedList.GetItem( i );
2308
             Rows[Item^.RowNum].Assign( BufferGrid.Rows[i + FixedRows] );
2309
         end;
2310
      finally
2311
         BufferGrid.Free;
2312
      end;
2313
 
2314
      //Now put the selection back on the right row.
2315
      Item := fSortedList.GetItem( Row - FixedRows );
2316
      MoveTo( Col, Item^.RowNum );
2317
      //Now reset the list.
2318
      fSortedList.Reset;
2319
   end;
2320
   fSortState := ssUnsorted;    // Line modified/added by gnes@zero.it
2321
end;
2322
 
2323
// Finds the first (sub)string in the grid.
2324
// It searches by row and by column starting from sRow and sCol to eCol and finally eRow.
2325
// Comparisons are made folowing the SortCaseSensitive property.
2326
// If found, returning the cell coordinates in sCol and sRow and return True.
2327
function TSortGrid.FindFirst( const aStr: String; var sCol, sRow: LongInt; eCol, eRow: LongInt ): Boolean;
2328
var
2329
   pStr: String;
2330
   r, c: Integer;
2331
begin
2332
   Result := False;
2333
        if CheckRange( sCol, eCol, false ) and CheckRange( sRow, eRow, true ) then
2334
   begin;
2335
      GFindString       := aStr;
2336
           GEndCol              := eCol;
2337
           GEndRow              := eRow;
2338
      for r := sRow to eRow do
2339
      begin
2340
         for c := sCol to eCol do
2341
         begin
2342
            if FCaseSensitive then
2343
               pStr := Cells[c, r]
2344
            else
2345
               pStr := UpperCase( Cells[c, r] );
2346
            if {$IfDef VER90}Pos{$Else}AnsiPos{$EndIf}( aStr, pStr ) > 0 then
2347
            begin
2348
               sCol := c;
2349
               GStartCol := c;
2350
               sRow := r;
2351
               GStartRow := r;
2352
               Result := True;
2353
               Exit;
2354
            end;
2355
         end;
2356
      end
2357
   end;
2358
end;
2359
 
2360
function TSortGrid.FindNext( var aCol, aRow: LongInt ): Boolean;
2361
var
2362
   pStr: String;
2363
   r, c: Integer;
2364
begin
2365
   Result := False;
2366
        for r := GStartRow to GEndRow do
2367
   begin
2368
                for c := GStartCol + 1 to GEndCol do
2369
      begin
2370
         if FCaseSensitive then
2371
            pStr := Cells[c, r]
2372
         else
2373
            pStr := UpperCase( Cells[c, r] );
2374
                        if {$IfDef VER90}Pos{$Else}AnsiPos{$EndIf}( GFindString, pStr ) > 0 then
2375
         begin
2376
                                aCol := c;
2377
                                aRow := r;
2378
            Result := True;
2379
            GStartCol := c;
2380
            GStartRow := r;
2381
            Exit;
2382
                        end;
2383
                end;
2384
      GStartCol := -1;
2385
        end;
2386
   GStartRow := RowCount; // Keep returning False
2387
end;
2388
 
2389
function TSortGrid.GetCellDrawState( const aCol, aRow: LongInt ): TGridDrawState;
2390
   function PointInGridRect( Col, Row: LongInt; const Rect: TGridRect ): Boolean;
2391
   begin
2392
     Result := (Col >= Rect.Left) and (Col <= Rect.Right) and (Row >= Rect.Top) and (Row <= Rect.Bottom);
2393
   end;
2394
var
2395
   DrawState: TGridDrawState;
2396
begin
2397
   DrawState := [];
2398
   if (aRow < FixedRows) and (aCol < FixedCols) then Include( DrawState, gdFixed );
2399
   if Focused and (aRow = Row) and (aCol = Col) then Include( DrawState, gdFocused );
2400
   if PointInGridRect( aCol, aCol, Selection ) then Include( DrawState, gdSelected );
2401
   Result := DrawState;
2402
end;
2403
 
2404
function TSortGrid.SelectCell( aCol, aRow: LongInt ): Boolean;
2405
begin
2406
   Result := inherited SelectCell( aCol, aRow );
2407
end;
2408
 
2409
procedure TSortGrid.KeyPress( var Key: Char );
2410
begin
2411
   //I have to do this here because KeyDown doesn't get called
2412
   //when the enter key is pressed in the inplace editor.
2413
   if Key = #13 then
2414
      ValidateCell;
2415
   inherited KeyPress( Key );
2416
end;
2417
 
2418
procedure TSortGrid.ClearSelection;
2419
begin
2420
   fSelectedRows.Clear;
2421
   fSelectedRows.Add( Pointer( Row ) );
2422
   Refresh;
2423
end;
2424
 
2425
// IsRC = 1...Rows IsRC = 2...Columns
2426
procedure TSortGrid.ShowRC( StartRC, EndRC: LongInt; IsRC: Integer ); // RCV04 priv
2427
var
2428
   rc, v: Integer;
2429
begin
2430
   for rc := StartRC to EndRC do
2431
   begin
2432
      if ( ((IsRc = 1) and (RowHeights[ rc ] = 0)) or ((IsRC = 2) and (ColWidths[ rc ] = 0)) ) then
2433
      begin
2434
         v := fOldRowCol.GetValue( rc, IsRC );
2435
         if v <> -1 then
2436
         begin
2437
            if IsRC = 1 then
2438
               RowHeights[ rc ] := v
2439
            else
2440
               ColWidths[ rc ] := v;
2441
            fOldRowCol.RemRC( rc, IsRC );
2442
         end;
2443
      end;
2444
   end;
2445
end;
2446
 
2447
procedure TSortGrid.HideRC( StartRC, EndRC: LongInt; IsRC: Integer ); // RCV04 priv
2448
var
2449
   rc: Integer;
2450
begin
2451
   for rc := StartRC to EndRC do
2452
   begin
2453
      if IsRC = 1 then
2454
      begin
2455
         fOldRowCol.SetValue( rc, RowHeights[ rc ], IsRC );
2456
         RowHeights[ rc ] := 0;
2457
      end else
2458
      begin
2459
         fOldRowCol.SetValue( rc, ColWidths[ rc ], IsRC );
2460
         ColWidths[ rc ] := 0;
2461
      end;
2462
   end;
2463
end;
2464
 
2465
procedure TSortGrid.ShowRows( StartRow, EndRow: LongInt ); // RCV04
2466
begin
2467
   ShowRC( StartRow, EndRow, 1 );
2468
end;
2469
 
2470
procedure TSortGrid.HideRows( StartRow, EndRow: LongInt ); // RCV04
2471
begin
2472
   HideRC( StartRow, EndRow, 1 );
2473
end;
2474
 
2475
procedure TSortGrid.AutoSizeRows( StartRow, EndRow: LongInt ); // RCV04
2476
begin
2477
   AutoSizeRowsInt( StartRow, EndRow, asAll );
2478
end;
2479
 
2480
procedure TSortGrid.AutoSizeVisibleRows( StartRow, EndRow: LongInt ); // RCV04
2481
begin
2482
   AutoSizeRowsInt( StartRow, EndRow, asVisible );
2483
end;
2484
 
2485
procedure TSortGrid.AutoSizeHiddenRows( StartRow, EndRow: LongInt ); // RCV04
2486
begin
2487
   AutoSizeRowsInt( StartRow, EndRow, asHidden );
2488
end;
2489
 
2490
// TAutoSize: asAll, asVisible, asHidden
2491
procedure TSortGrid.AutoSizeRowsInt( StartRow, EndRow: LongInt; How: TAutoSize ); // RCV04 priv
2492
var
2493
   r:    Integer;
2494
   Auto: Boolean;
2495
begin
2496
   for r := StartRow to EndRow do
2497
   begin
2498
      Auto := False;
2499
      if How = asAll then Auto := True;
2500
      if (How = asVisible) and (RowHeights[ r ] <> 0) then Auto := True;
2501
      if (How = asHidden) and (RowHeights[ r ] = 0) then Auto := True;
2502
      if Auto = True then AutoSizeRow( r );
2503
   end;
2504
end;
2505
 
2506
procedure TSortGrid.AutoSizeRow( aRow: LongInt ); // RCV04
2507
var
2508
   c, maxh, h, v: Integer;
2509
   R: TRect;  s: String;
2510
begin
2511
   maxh := DefaultRowHeight;
2512
   for c := 0 to ColCount - 1 do
2513
   begin
2514
      s := Cells[ c, aRow ];
2515
      R := CellRect( c, aRow );
2516
      DrawText( Canvas.Handle, pChar( s ), -1, R, DT_CALCRECT or DT_WORDBREAK );
2517
      h := R.Bottom - R.Top + 1;
2518
      if h < maxh then maxh := h;
2519
   end;
2520
   v := fOldRowCol.GetValue( aRow, 1 );
2521
   if v <> -1 then
2522
   begin
2523
      fOldRowCol.RemRC( aRow, 1 );
2524
      fOldRowCol.SetValue( aRow, maxh, 1 );
2525
   end else RowHeights[ aRow ] := maxh;
2526
end;
2527
 
2528
procedure TSortGrid.ShowCols( StartCol, EndCol: LongInt ); // RCV04
2529
begin
2530
   ShowRC( StartCol, EndCol, 2 );
2531
end;
2532
 
2533
procedure TSortGrid.HideCols( StartCol, EndCol: LongInt ); // RCV04
2534
begin
2535
   HideRC( StartCol, EndCol, 2 );
2536
end;
2537
 
2538
//{$IfDef VERD4+}
2539
procedure TSortGrid.Print; // RCV04
2540
begin
2541
   AutoSizeHiddenRows( 0, RowCount - 1 );
2542
   if Printer.Printers.Count = 0 then
2543
   begin
2544
      MessageDlg( 'No Printer is installed', mtError, [mbOK], 0 );
2545
      Exit;
2546
   end;
2547
   Printer.Title  := PrintOptions.fJobTitle;
2548
   Printer.Copies := PrintOptions.fCopies;
2549
   Printer.Orientation := PrintOptions.Orientation;
2550
   PrintOptions.ToRow := RowCount - 1;
2551
   Printer.BeginDoc;
2552
   DrawToCanvas( Printer.Canvas, pmPrint, PrintOptions.FromRow, PrintOptions.ToRow );
2553
   Printer.EndDoc;
2554
end;
2555
 
2556
procedure TSortGrid.PrintPreview; // RCV04
2557
var
2558
   Preview: TSortGridPreviewForm;
2559
begin
2560
   fPageCount := 0;
2561
   Preview := TSortGridPreviewForm.Create( Application );
2562
   Preview.Grid := Self;
2563
   fPrintImage := Preview.PrintImage;
2564
   DrawToCanvas( fPrintImage.Canvas, pmPreview, 1, RowCount - 1 );
2565
   Preview.PreviewImage.Picture.Bitmap.Assign( fPrintImage );
2566
   Preview.ShowModal;
2567
   Preview.Free;
2568
end;
2569
 
2570
procedure TSortGrid.UpdatePreview( aCanvas: TCanvas ); // RCV04
2571
begin
2572
   fPageCount := 0;
2573
   DrawToCanvas( aCanvas, pmPreview, 1, RowCount - 1 );
2574
end;
2575
 
2576
function TSortGrid.PageCount: Integer; // RCV04
2577
begin
2578
   fPageCount := 0;
2579
   DrawToCanvas( nil, pmPageCount, 1, RowCount - 1 );
2580
   Result := fPageCount;
2581
end;
2582
 
2583
procedure TSortGrid.DrawToCanvas( aCanvas: TCanvas; Mode: TPrintMode; FromRow, ToRow: LongInt ); // RCV04
2584
var
2585
   PageWidth, PageHeight, PageRow, PageCol, I, iRow, FromCol, ToCol, X, Y: Integer;
2586
   DoPaint, HasLogo:  Boolean;
2587
   Hheader, Hfooter:  Integer;
2588
   LogoPic, LogoPics: TBitmap;
2589
 
2590
   function ScaleX( I: Integer ): Integer;
2591
   begin
2592
      if Mode = pmPreview then
2593
         Result := I
2594
      else
2595
         Result := Round( I *(GetDeviceCaps( Printer.Handle, LOGPIXELSX ) / Screen.PixelsPerInch ) );
2596
   end;
2597
 
2598
   function ScaleY( I:Integer ): Integer;
2599
   begin
2600
      if Mode = pmPreview then
2601
         Result := I
2602
      else
2603
         Result := Round( I *(GetDeviceCaps( Printer.Handle, LOGPIXELSY ) / Screen.PixelsPerInch ) );
2604
   end;
2605
 
2606
   procedure DrawCells( iRow: Integer );
2607
   var
2608
      iCol, I: Integer;
2609
      R:       TRect;
2610
      drs:     String;
2611
      aState:  TGridDrawState;
2612
      FmtOpts: TFormatOptions;
2613
      xOffset: Cardinal;
2614
      yOffset: Cardinal;
2615
   begin
2616
      if DoPaint then
2617
      begin
2618
         Canvas.Font.Assign( fOldFont );
2619
         Canvas.Brush.Assign( fOldBrush );
2620
      end;
2621
      for iCol := FromCol to ToCol do
2622
      begin
2623
         if ColWidths[ iCol ] <> 0 then
2624
         begin
2625
            InitializeFormatOptions( iCol, iRow, FmtOpts );
2626
            if DoPaint then
2627
            begin
2628
               if (iRow >= FixedRows) and (iRow <= RowCount - 1 - fFooterRows) then
2629
                  Canvas.Brush.Color := Color;
2630
               if (iRow < FixedRows) or ((iCol < FixedCols) and (iRow <= RowCount - 1 - fFooterRows)) then
2631
                  Canvas.Brush.Color := FixedColor;
2632
            end;
2633
            // Now do the OnGetCellFormat event if necessary.
2634
            if Assigned( fOnGetCellFormat ) then
2635
               fOnGetCellFormat( Self, iCol, iRow, aState, FmtOpts );
2636
 
2637
            case FmtOpts.AlignmentHorz of
2638
               taRightJustify:
2639
                  xOffset := DT_RIGHT;
2640
               taCenter:
2641
                  xOffset := DT_CENTER;
2642
               else
2643
                  xOffset := DT_LEFT;
2644
            end;
2645
 
2646
            case FmtOpts.AlignmentVert of
2647
               taBottomJustify:
2648
                  yOffset := DT_BOTTOM;
2649
               taMiddle:
2650
                  yOffset := DT_VCENTER;
2651
               else
2652
                  yOffset := DT_TOP;
2653
            end;
2654
            if DoPaint then
2655
            begin
2656
               aCanvas.Brush.Assign( FmtOpts.Brush );
2657
               aCanvas.Font.Assign( FmtOpts.Font );
2658
            end;
2659
 
2660
            // X Offset
2661
            X := ScaleX( PrintOptions.Marginleft );
2662
            for I := FromCol to iCol - 1 do
2663
               Inc( X, ScaleX( ColWidths[ I ]+ 1) );
2664
            // Text Rect
2665
            R := Rect( X, Y, X + ScaleX( ColWidths[ iCol ] ), Y + ScaleY( RowHeights[ iRow ] ) );
2666
            // Draw on the Canvas
2667
            if DoPaint then
2668
            begin
2669
               aCanvas.Brush.Color := FmtOpts.Brush.Color;
2670
               aCanvas.FillRect( Rect( r.Left, r.Top, r.Right + ScaleX( 2 ), r.Bottom + ScaleY( 1 ) ) );
2671
               if PrintOptions.BorderStyle = bsSingle then
2672
               begin
2673
                  aCanvas.Brush.Style := bsClear;
2674
                  aCanvas.Rectangle( r.Left, r.Top, r.Right + ScaleX( 2 ), r.Bottom + ScaleY( 1 ) );
2675
               end;
2676
               drs := Cells[ iCol, iRow ];
2677
               R.Left := R.Left + ScaleX( PrintOptions.LeftPadding );
2678
               if ( FWordWrap and (iCol < FixedCols ) and (iRow < FixedRows) ) then
2679
                  DrawText( aCanvas.Handle, pChar( drs ), -1, R, DT_SINGLELINE or xOffset or yOffset )
2680
               else
2681
                  DrawText( aCanvas.Handle, pChar( drs ), -1, R, DT_WORDBREAK or xOffset );
2682
            end;
2683
         end;
2684
      end;
2685
      Inc( Y, ScaleY( RowHeights[ iRow ] ) );
2686
   end;
2687
 
2688
   procedure DrawTitle; // Draw Header and Footer
2689
   var
2690
      S, fstr: String;
2691
      flist:   TStringList;
2692
      i:       Integer;
2693
      tmpfont: TFont; // I have no idea why you can't use gettextwidth when acanvas = printer.canvas, it returns wrong value
2694
   begin
2695
      tmpfont := nil;
2696
      if DoPaint then
2697
      begin
2698
        aCanvas.Font.Size := fPrintOptions.HeaderSize;
2699
        tmpfont := Font;
2700
        Canvas.Font := aCanvas.Font;
2701
      end;
2702
      // Title
2703
      Y := ScaleY( PrintOptions.MarginTop );
2704
      S := PrintOptions.PageTitle;
2705
      HHeader := Canvas.TextHeight( S );
2706
      if HasLogo then if LogoPic.Height > HHeader then HHeader := LogoPic.Height;
2707
      if DoPaint then
2708
      begin
2709
         if HasLogo then
2710
            aCanvas.Draw( ScaleX( PrintOptions.MarginLeft ), Y, LogoPics );
2711
         aCanvas.TextOut( (PageWidth div 2) - (ScaleX( Canvas.TextWidth( S ) div 2 )), Y, S );
2712
      end;
2713
      Y := Y + ScaleY( HHeader );
2714
      // Page nr
2715
      S := 'Page ' + IntToStr( PageRow );
2716
      if (ToCol < ColCount - 1) or (PageCol > 1) then
2717
         S := S + '-' + IntToStr( PageCol );
2718
      fstr := PrintOptions.PageFooter ;
2719
      HFooter := Canvas.TextHeight( fstr );
2720
      if fstr <> '' then if DoPaint then
2721
      begin
2722
         aCanvas.Font.Size := fPrintOptions.FooterSize ;
2723
         Canvas.font := aCanvas.Font;
2724
         HFooter := Canvas.TextHeight( fstr );
2725
         fList := TStringList.Create;
2726
         fList.Text := StringReplace( fstr, '|' , #$0D#$0A, [rfreplaceall] );
2727
         while flist.count < 3 do
2728
            fList.Append( '' );
2729
         for i := 0 to 2 do
2730
         begin
2731
            fList[ i ] := StringReplace( fList[ i ], 'date', formatdatetime( PrintOptions.Dateformat, now ), [] );
2732
            fList[ i ] := StringReplace( fList[ i ], 'time', formatdatetime( PrintOptions.Timeformat, now ), [] );
2733
            fList[ i ] := StringReplace( fList[ i ], 'page', s, [] );
2734
         end;
2735
         // Paint left footer
2736
         if fList[ 0 ] <> '' then
2737
            aCanvas.TextOut( ScaleX( Integer( PrintOptions.MarginLeft ) + Canvas.TextWidth( fList[ 0 ] ) ), PageHeight - ScaleY( Integer( PrintOptions.MarginBottom )+ Canvas.TextHeight( fList[ 0 ] )), fList[ 0 ] );
2738
         // Paint center Footer
2739
         if fList[ 1 ] <> '' then
2740
            aCanvas.TextOut( (PageWidth div 2)-(ScaleX( Canvas.TextWidth( fList[ 1 ] ) ) div 2), PageHeight - ScaleY( Integer( PrintOptions.MarginBottom )+ Canvas.TextHeight(fList[ 1 ] ) ), fList[ 1 ] );
2741
         // Paint right Footer
2742
         if fList[ 2 ] <> '' then
2743
            aCanvas.TextOut( PageWidth - ScaleX( Integer( PrintOptions.MarginRight ) + Canvas.TextWidth( fList[ 2 ])+ 10 ), PageHeight - ScaleY( Integer( PrintOptions.MarginBottom )+ Canvas.TextHeight( fList[ 2 ])), fList[ 2 ] );
2744
          fList.Free;
2745
      end;
2746
 
2747
      if DoPaint then
2748
      begin
2749
         aCanvas.Font.Size := Font.Size;
2750
         Canvas.Font := tmpfont;
2751
      end;
2752
      Y := Y + ScaleY( PrintOptions.PageTitleMargin );
2753
      DrawCells( 0 );
2754
   end;
2755
 
2756
 
2757
begin
2758
   Canvas.Font.Assign( fOldFont );
2759
   Canvas.Brush.Assign( fOldBrush );
2760
   // Page size
2761
   PageWidth  := Printer.PageWidth;
2762
   PageHeight := Printer.PageHeight;
2763
   if Mode = pmPreview then
2764
   begin
2765
      PageWidth  := PageWidth div ((GetDeviceCaps( Printer.Handle, LOGPIXELSX ) div Screen.PixelsPerInch) );
2766
      PageHeight := PageHeight div ((GetDeviceCaps( Printer.Handle, LOGPIXELSY ) div Screen.PixelsPerInch) );
2767
      fPrintImage.Width   := PageWidth;
2768
      fPrintImage.Height  := PageHeight;
2769
      aCanvas.Brush.Color := Color;
2770
      aCanvas.FillRect( Rect( 0, 0, PageWidth, PageHeight ) );
2771
   end;
2772
   HasLogo := False;
2773
   if PrintOptions.Logo <> '' then if FileExists( PrintOptions.Logo ) then
2774
   begin
2775
      LogoPic := TBitmap.Create;
2776
      Logopic.LoadFromFile( PrintOptions.Logo );
2777
      Haslogo := True;
2778
      Logopics := TBitmap.Create;
2779
      Logopics.Width := ScaleX( Logopic.Width );
2780
      Logopics.Height := ScaleY( Logopic.Height );
2781
      Logopic.PixelFormat := pf24bit;
2782
      Logopics.PixelFormat := pf24bit;
2783
      SmoothResize( LogoPic, LogoPics );
2784
   end;
2785
 
2786
   if Mode <> pmPageCount then
2787
   begin
2788
      aCanvas.Font := Font;
2789
      aCanvas.Font.Color := clBlack;
2790
   end;
2791
   PageCol :=  0;
2792
   FromCol := -1;
2793
   ToCol   := -1;
2794
   // Scan cols
2795
   repeat
2796
      // Scan missing cols
2797
      if FromCol = ToCol then
2798
         Inc( FromCol )
2799
      else
2800
         FromCol := ToCol + 1;
2801
      Inc( ToCol );
2802
      // Get Cols with width that fits page
2803
      X := PrintOptions.MarginLeft;
2804
      for I := FromCol to ColCount - 1 do
2805
      begin
2806
         Inc( X, ScaleX( ColWidths[ I ]+ 1 ) );
2807
         if X <= (PageWidth - Integer( PrintOptions.MarginRight )) then
2808
            ToCol := I;
2809
      end;
2810
      PageRow := 1;
2811
      Inc( PageCol );
2812
      // Mode = PageCount
2813
      Inc( fPageCount );
2814
      // Preview mode
2815
      DoPaint := (((Mode = pmPreview) and (fPageCount = PrintOptions.PreviewPage)) or (Mode = pmPrint));
2816
      // Header & Footer
2817
      DrawTitle;
2818
      // Contents
2819
      iRow := FromRow;
2820
      repeat
2821
         if (Y + ScaleY( RowHeights[ iRow ] ) ) <= (PageHeight - ScaleY( Integer( PrintOptions.MarginBottom ) + 20 + HFooter ) ) then
2822
         begin // Draw contents to canvas
2823
            if RowHeights[ iRow ] <> 0 then
2824
               DrawCells( iRow );
2825
            Inc( iRow );
2826
         end else // New page
2827
         begin
2828
            if (DoPaint = True) and (Mode = pmPreview) then
2829
               Exit;
2830
            if Mode = pmPrint then
2831
               Printer.NewPage;
2832
            Inc( fPageCount ); // Pagecount
2833
            DoPaint := (((Mode = pmPreview) and (fPageCount = PrintOptions.PreviewPage)) or (Mode = pmPrint));
2834
            Inc( PageRow );
2835
            DrawTitle;
2836
         end;
2837
         if (iRow = ToRow + 1) and (ToCol < ColCount - 1) and (Y <= PageHeight - ScaleY( 20 )) then
2838
         begin
2839
            if (DoPaint = True) and (Mode = pmPreview) then
2840
               Exit;
2841
            if Mode = pmPrint then
2842
               Printer.NewPage;
2843
            DrawTitle;
2844
         end;
2845
      until iRow = ToRow + 1;
2846
   until ToCol = ColCount - 1;
2847
   if HasLogo then
2848
   begin
2849
      LogoPic.Free;
2850
      LogoPics.Free;
2851
   end;
2852
end;
2853
 
2854
procedure TSortGrid.SmoothResize( var Src, Dst: TBitmap ); // RCV04
2855
var
2856
   x, y, xP, yP,
2857
   yP2, xP2:        Integer;
2858
   Read, Read2:    pByteArray;
2859
   t, z, z2, iz2:   Integer;
2860
   pc:             pBytearray;
2861
   w1, w2, w3, w4:  Integer;
2862
   Col1r, col1g, col1b, Col2r, Col2g, Col2b: Byte;
2863
begin
2864
  xP2 := ((src.Width- 1)shl 15)div Dst.Width;
2865
  yP2 := ((src.Height- 1)shl 15)div Dst.Height;
2866
  yP := 0;
2867
  for y := 0 to Dst.Height- 1 do
2868
  begin
2869
    xP := 0;
2870
    Read := src.ScanLine[ yP shr 15 ];
2871
    if yP shr 16 < src.Height- 1 then
2872
      Read2 := src.ScanLine [ yP shr 15 + 1 ]
2873
    else
2874
      Read2 := src.ScanLine [ yP shr 15 ];
2875
    pc := Dst.scanline[ y ];
2876
    z2 := yP and $7FFF;
2877
    iz2 := $8000 - z2;
2878
    for x := 0 to Dst.Width- 1 do
2879
    begin
2880
      t := xP shr 15;
2881
      Col1r := Read[ t * 3 ];
2882
      Col1g := Read[ t * 3 + 1 ];
2883
      Col1b := Read[ t * 3 + 2 ];
2884
      Col2r := Read2[ t * 3 ];
2885
      Col2g := Read2[ t * 3 + 1 ];
2886
      Col2b := Read2[ t * 3 + 2 ];
2887
      z := xP and $7FFF;
2888
      w2 := (z * iz2) shr 15;
2889
      w1 := iz2 - w2;
2890
      w4 := (z * z2) shr 15;
2891
      w3 := z2 - w4;
2892
      pc[ x * 3 + 2 ]:= (Col1b * w1 + Read[ (t + 1)* 3 + 2]* w2 + Col2b * w3 + Read2[ (t + 1)* 3 + 2]* w4) shr 15;
2893
      pc[ x * 3 + 1 ] := (Col1g * w1 + Read[(t + 1)* 3 + 1]* w2 + Col2g * w3 + Read2[ (t + 1)* 3 + 1 ]* w4) shr 15;
2894
      pc[ x * 3 ] := (Col1r * w1 + Read2[ (t + 1)* 3 ]* w2 + Col2r * w3 + Read2[ (t + 1)* 3 ]* w4) shr 15;
2895
      Inc( xP, xP2 );
2896
    end;
2897
    Inc( yP, yP2 );
2898
  end;
2899
end;
2900
//{$EndIf}
2901
 
2902
//procedure Register;
2903
//begin
2904
//   RegisterComponents( 'Delphi Zip', [TSortGrid] );
2905
//end;
2906
 
2907
End.
2908