forked from synopse/mORMot
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathmORMotUIQuery.pas
More file actions
345 lines (315 loc) · 12.4 KB
/
mORMotUIQuery.pas
File metadata and controls
345 lines (315 loc) · 12.4 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
/// Form handling queries to a User Interface Grid for mORMot
// - this unit is a part of the freeware Synopse mORMot framework,
// licensed under a MPL/GPL/LGPL tri-license; version 1.18
unit mORMotUIQuery;
(*
This file is part of Synopse mORMot framework.
Synopse mORMot framework. Copyright (c) Arnaud Bouchez
Synopse Informatique - https://synopse.info
*** BEGIN LICENSE BLOCK *****
Version: MPL 1.1/GPL 2.0/LGPL 2.1
The contents of this file are subject to the Mozilla Public License Version
1.1 (the "License"); you may not use this file except in compliance with
the License. You may obtain a copy of the License at
http://www.mozilla.org/MPL
Software distributed under the License is distributed on an "AS IS" basis,
WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
for the specific language governing rights and limitations under the License.
The Original Code is Synopse mORMot framework.
The Initial Developer of the Original Code is Arnaud Bouchez.
Portions created by the Initial Developer are Copyright (c)
the Initial Developer. All Rights Reserved.
Contributor(s):
Alternatively, the contents of this file may be used under the terms of
either the GNU General Public License Version 2 or later (the "GPL"), or
the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
in which case the provisions of the GPL or the LGPL are applicable instead
of those above. If you wish to allow use of your version of this file only
under the terms of either the GPL or the LGPL, and not to allow others to
use your version of this file under the terms of the MPL, indicate your
decision by deleting the provisions above and replace them with the notice
and other provisions required by the GPL or the LGPL. If you do not delete
the provisions above, a recipient may use your version of this file under
the terms of any one of the MPL, the GPL or the LGPL.
***** END LICENSE BLOCK *****
Version 1.5
- first implementation of the TQueryForm class: handle default and
custom queries
Version 1.9
- custom queries can now handle standard operators, following a specified set
- TSQLQueryEvent() usage has therefore been modified for custom queries
Version 1.15
- now use TMS component pack only if USETMSPACK global conditional is defined:
by default, will use only VCL components (i.e. TSynButton) for the form
- handle TModTime published property / sftModTime SQL field
- handle TCreateTime published property / sftCreateTime SQL field
Version 1.18
- renamed SQLite3UIQuery.pas to mORMotUIQuery.pas
*)
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
SynCommons, SynTaskDialog,
mORMot, mORMotUI, mORMotUILogin, mORMoti18n,
StdCtrls, ComCtrls;
type
/// this Form perform simple Visual queries to a Grid
// - mark or unmark items, depending of the input of the User on this form
// - use TSQLRest.QueryIsTrue() method for standard fields and parameters
// - use TSQLQueryCustom records previously registered to the TSQLRest class,
// by the TSQLRest.QueryAddCustom() method, to add some custom field search
// (e.g. to search into fields not available on the grid, or some data
// embedded inside a field - like .INI-like section entries)
// - in practice, the query is very fast (immediate for standard fields and
// parameters), but can demand some bandwith for custom field search (since
// data has to be retrieved from the server to search within)
TQueryForm = class(TVistaForm)
Label1: TLabel;
Where: TComboBox;
Label2: TLabel;
Operation: TComboBox;
Label3: TLabel;
Label4: TLabel;
MarkedOnly: TCheckBox;
procedure FormShow(Sender: TObject);
procedure WhereChange(Sender: TObject);
procedure BtnMarkClick(Sender: TObject);
protected
Table: TSQLTable;
TableClass: TSQLRecordClass;
TableToGrid: TSQLTableToGrid;
Client: TSQLRest;
FieldType: TSQLFieldType;
FieldIndex: integer;
Reference: TWinControl;
BtnMark: TSynButton;
BtnUnmark: TSynButton;
BtnCancel: TSynButton;
QueryOpEnumType: PEnumType;
/// override this if you want to select which enumerates values must
// appear in the "What to search" criteria
// - return nil by default, i.e. all enumerates must be added
// - can return a pointer to a set of enumerates to be shown
function EnumerateUsedBits(EnumType: PEnumType): pointer; virtual;
public
/// create the window instance
// - all parameters (especially TSQLRest instance to use for custom search)
// are retrieved via the supplied TSQLTableToGrid
// - caller must have used TSQLRest.QueryAddCustom() method to register
// some custom queries, if necessary
constructor Create(aOwner: TComponent; aTableToGrid: TSQLTableToGrid); reintroduce;
end;
implementation
{$R *.dfm}
resourcestring
sBtnMark = 'MARK if match';
sBtnUnMark = 'UNMARK if match';
constructor TQueryForm.Create(aOwner: TComponent; aTableToGrid: TSQLTableToGrid);
var i: integer;
begin
inherited Create(aOwner);
BtnMark := TSynButton.Create(Self);
with BtnMark do begin
Parent := self;
SetBounds(48,264,145,33);
Caption := sBtnMark;
ModalResult := mrOk;
TabOrder := 3;
OnClick := BtnMarkClick
end;
BtnUnMark := TSynButton.Create(Self);
with BtnUnMark do begin
Parent := self;
SetBounds(48,304,145,33);
Caption := sBtnUnMark;
ModalResult := mrOk;
TabOrder := 4;
OnClick := BtnMarkClick
end;
BtnCancel := TSynButton.CreateKind(self,cbCancel,200,304,89,33);
if aTableToGrid=nil then exit;
TableToGrid := aTableToGrid;
Table := aTableToGrid.Table;
Client := aTableToGrid.Client;
for i := 0 to Table.FieldCount-1 do
Where.Items.Add(Table.GetCaption(0,i));
if Assigned(Table.QueryTables) then begin
TableClass := TSQLRecordClass(Table.QueryTables[0]);
for i := 0 to high(Client.QueryCustom) do
with Client.QueryCustom[i] do
if Event(TableClass,0,sftUnknown,nil,i,nil) then
// if this custom query is available to this table
Where.Items.Add(EnumType^.GetCaption(EnumIndex));
end;
MarkedOnly.Enabled := TableToGrid.MarkAvailable;
QueryOpEnumType := PTypeInfo(TypeInfo(TSQLQueryOperator))^.EnumBaseType;
end;
procedure TQueryForm.FormShow(Sender: TObject);
begin
if Where.Items.Count>0 then begin
Where.ItemIndex := 0;
WhereChange(nil);
end else begin
BtnMark.Enabled := false;
BtnUnMark.Enabled := false;
end;
SetStyle(self);
end;
procedure TQueryForm.WhereChange(Sender: TObject);
var i, max: integer;
EnumType: PEnumType;
none: TSQLQueryOperator;
begin
Operation.Clear;
FieldIndex := Where.ItemIndex;
if (Table=nil) or (cardinal(FieldIndex)>=cardinal(Table.FieldCount)) then begin
// QueryCustom[] or no Field -> add specified Operator(s)
FieldType := sftUTF8Text;
Dec(FieldIndex,Table.FieldCount);
if cardinal(FieldIndex)<=cardinal(high(Client.QueryCustom)) then
for i := Ord(qoEqualTo) to QueryOpEnumType^.MaxValue do
if TSQLQueryOperator(i) in Client.QueryCustom[FieldIndex].Operators then
Operation.Items.AddObject(QueryOpEnumType^.GetCaption(i),pointer(i));
Operation.Enabled := Operation.Items.Count>0;
if not Operation.Enabled then begin
none := qoNone;
Operation.Items.Add(QueryOpEnumType^.GetCaption(none));
end;
Label2.Enabled := Operation.Enabled;
FieldIndex := -1; // mark custom field
end else begin
// add "basic" operations from standard TSQLTable Field
FieldType := Table.FieldType(FieldIndex,@EnumType);
Operation.Enabled := true;
Label2.Enabled := true;
if FieldType in [sftAnsiText,sftUTF8Text,sftObject,sftVariant] then
max := QueryOpEnumType^.MaxValue else // allow textual operations
max := ord(qoGreaterThanOrEqualTo); // numeric operations only
for i := ord(qoEqualTo) to max do
Operation.Items.AddObject(QueryOpEnumType^.GetCaption(i),pointer(i));
end;
Operation.ItemIndex := 0;
// create corresponding Reference field
FreeAndNil(Reference);
case FieldType of
sftDateTime, sftDateTimeMS, sftTimeLog, sftModTime, sftCreateTime,
sftUnixTime, sftUnixMSTime: begin
Reference := TDateTimePicker.Create(self);
Reference.Parent := self;
end;
sftEnumerate:
if EnumType<>nil then begin
Reference := TComboBox.Create(self);
with TComboBox(Reference) do begin
Parent := self;
Style := csDropDownList;
EnumType.AddCaptionStrings(Items,EnumerateUsedBits(EnumType));
ItemIndex := 0;
DropDownCount := 32;
end;
end;
end;
if Reference=nil then begin
// default reference
Reference := TEdit.Create(self);
Reference.Parent := self;
end;
Reference.SetBounds(48,200,169,21);
end;
procedure TQueryForm.BtnMarkClick(Sender: TObject);
var Row, i: integer;
SoundEx: TSynSoundEx;
Ope: integer;
Ref: RawUTF8;
R, V: PUTF8Char;
aEvent: TSQLQueryEvent;
AllRows, OK, ToBeMarked: boolean;
const CONVERT: array[qoSoundsLikeEnglish..qoSoundsLikeSpanish] of
TSynSoundExPronunciation = (sndxEnglish,sndxFrench,sndxSpanish);
begin
if Table=nil then exit;
ToBeMarked := (Sender=BtnMark); // other possibility is BtnUnmark -> false
AllRows := not (MarkedOnly.Enabled and MarkedOnly.Checked);
if Operation.Enabled then begin
// normal operator search
Ope := integer(Operation.Items.Objects[Operation.ItemIndex]);
if Reference.InheritsFrom(TEdit) then
Ref := StringToUTF8(TEdit(Reference).Text) else
if Reference.InheritsFrom(TComboBox) then begin
i := TComboBox(Reference).ItemIndex;
if i<0 then
Exit; // avoid out of range error
Int32ToUtf8(Integer(TComboBox(Reference).Items.Objects[i]),Ref);
end else
if Reference.InheritsFrom(TDateTimePicker) then
with TDateTimePicker(Reference) do
case FieldType of
sftDateTime, sftDateTimeMS:
Ref := DateTimeToIso8601(DateTime,false,'T',FieldType=sftDateTimeMS);
sftTimeLog, sftModTime, sftCreateTime:
Int64ToUtf8(TimeLogFromDateTime(DateTime),Ref);
sftUnixTime:
Int64ToUtf8(DateTimeToUnixTime(DateTime),Ref);
sftUnixMSTime:
Int64ToUtf8(DateTimeToUnixMSTime(DateTime),Ref);
end;
Ref := Trim(Ref);
if Ref='' then begin
ModalResult := mrNone;
exit;
end;
R := pointer(Ref);
case TSQLQueryOperator(Ope) of
qoContains, qoBeginWith: begin // expected to be already uppercase
Ref := UpperCase(Ref);
R := pointer(Ref);
end;
qoSoundsLikeEnglish..qoSoundsLikeSpanish: begin
Ref := UpperCase(Ref);
SoundEx.Prepare(pointer(Ref),CONVERT[TSQLQueryOperator(Ope)]);
R := pointer(@Soundex); // typecast of the prepared TSynSoundEx object
end;
end;
end else begin
// custom query with no Operator
if not Reference.InheritsFrom(TEdit) then
exit;
Ope := 0;
Ref := StringToUTF8(Trim(TEdit(Reference).Text));
R := pointer(Ref);
assert(FieldIndex<0);
end;
if FieldIndex<0 then begin
i := Where.ItemIndex-Table.FieldCount;
if cardinal(i)>cardinal(high(Client.QueryCustom)) then
exit;
with Client.QueryCustom[i] do begin
FieldType := TSQLFieldType(EnumIndex+64);
aEvent := Event;
end;
end else begin
aEvent := Client.QueryIsTrue;
end;
V := R; // we need Value<>nil
Screen.Cursor := crHourGlass; // immediate for standard query, but how knows?
try
for Row := 1 to Table.RowCount do
if AllRows or TableToGrid.Marked[Row] then begin
if FieldIndex>=0 then
V := Table.Get(Row,FieldIndex);
OK := aEvent(TableClass,Table.IDColumnHiddenValue(Row), FieldType, V, Ope, R);
if not AllRows and ToBeMarked then // BtnMark + MarkOnly.Checked -> reset
TableToGrid.Marked[Row] := OK else
if OK then
TableToGrid.Marked[Row] := ToBeMarked; // set/reset from BtnMark/BtnUnmark
end;
TableToGrid.DrawGrid.Invalidate; // refresh screen
finally
Screen.Cursor := crDefault;
end;
end;
function TQueryForm.EnumerateUsedBits(EnumType: PEnumType): pointer;
begin
result := nil; // no custom selection by default
end;
end.