Files
lazarus-ccr/components/flashfiler/sourcelaz/explorer/dgtable.pas
2016-12-07 13:31:59 +00:00

1965 lines
66 KiB
ObjectPascal

{*********************************************************}
{* FlashFiler: Table Browser *}
{*********************************************************}
(* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.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 TurboPower FlashFiler
*
* The Initial Developer of the Original Code is
* TurboPower Software
*
* Portions created by the Initial Developer are Copyright (C) 1996-2002
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
*
* ***** END LICENSE BLOCK ***** *)
{$I ffdefine.inc}
unit dgtable;
interface
uses
Windows,
Messages,
SysUtils,
Classes,
Graphics,
Controls,
Forms,
Dialogs,
Db,
StdCtrls,
Grids,
DBGrids,
DBCtrls,
ExtCtrls,
Buttons,
Menus,
ComCtrls,
ffdb,
ffdbbase,
fflllgcy,
ffllbase,
ffclreng,
ffllprot,
fflllog,
ffutil,
ffclbase,
Mask,
dgSetRng,
uEntity,
uConsts;
type
TdlgTable = class(TForm)
dsTableBrowser: TDataSource;
navTableBrowser: TDBNavigator;
barStatus: TStatusBar;
MainMenu1: TMainMenu;
mnuTable: TMenuItem;
N1: TMenuItem;
mnuTableClose: TMenuItem;
mnuView: TMenuItem;
mnuViewRefresh: TMenuItem;
N2: TMenuItem;
mnuViewShowRecordCount: TMenuItem;
mnuViewShowFilter: TMenuItem;
mnuTableResetCol: TMenuItem;
mnuOptions: TMenuItem;
mnuOptionsDebug: TMenuItem;
mnuOptionsTimeout: TMenuItem;
N3: TMenuItem;
paClient: TPanel;
grdTableBrowser: TDBGrid;
pcBlobfields: TPageControl;
splGridAndPageControl: TSplitter;
pnlIndex: TPanel;
lblIndex: TLabel;
cboIndex: TComboBox;
lblFind: TLabel;
edtFind: TEdit;
btnFindNear: TButton;
pnlFilter: TPanel;
lblFilter: TLabel;
btnSetFilter: TButton;
pnlRange: TPanel;
laRangeStartDesc: TLabel;
btnSetClearRange: TButton;
tsMemoTemplate: TTabSheet;
tsGraphicTemplate: TTabSheet;
tsByteArrayTemplate: TTabSheet;
cbStretch: TCheckBox;
btnLoadGraphic: TButton;
Image: TImage;
tsGenericBlobTemplate: TTabSheet;
meGeneric: TMemo;
mnuViewShowRange: TMenuItem;
mnuViewShowBLOBFields: TMenuItem;
Label2: TLabel;
btnClearBA: TButton;
OpenDialog: TOpenDialog;
SaveDialog: TSaveDialog;
btnLoadGeneric: TButton;
btnSaveGeneric: TButton;
btnClearGeneric: TButton;
btnSaveGraphic: TButton;
btnClearGraphic: TButton;
Label3: TLabel;
meByteArray: TMaskEdit;
N4: TMenuItem;
mnuTablePrintPreview: TMenuItem;
mnuTableDesignReport: TMenuItem;
dbMemo: TDBMemo;
btnLoadMemo: TButton;
btnSaveMemo: TButton;
btnClearMemo: TButton;
laRangeEndDesc: TLabel;
btnEditRange: TButton;
laRangeStart: TLabel;
laRangeEnd: TLabel;
cbWordwrap: TCheckBox;
mnuTableCopyToTable: TMenuItem;
N5: TMenuItem;
mnuTableDeleteRecords: TMenuItem;
cboFilter: TComboBox;
procedure FormCreate(Sender: TObject);
procedure FormShow(Sender: TObject);
procedure cboIndexChange(Sender: TObject);
procedure btnFindClick(Sender: TObject);
procedure mnuTableCloseClick(Sender: TObject);
procedure FormClose(Sender: TObject; var Action: TCloseAction);
procedure mnuViewRefreshClick(Sender: TObject);
procedure mnuViewShowFilterClick(Sender: TObject);
procedure btnFilterClick(Sender: TObject);
procedure FormDestroy(Sender: TObject);
procedure btnFindNearClick(Sender: TObject);
procedure btnSetFilterClick(Sender: TObject);
procedure edtFindEnter(Sender: TObject);
procedure cboFilterEnter(Sender: TObject);
procedure mnuViewShowRecordCountClick(Sender: TObject);
procedure mnuTableResetColClick(Sender: TObject);
procedure grdTableBrowserKeyDown(Sender: TObject; var Key: Word;
Shift: TShiftState);
procedure mnuOptionsDebugClick(Sender: TObject);
procedure mnuOptionsTimeoutClick(Sender: TObject);
procedure FormKeyDown(Sender: TObject; var Key: Word;
Shift: TShiftState);
procedure cbStretchClick(Sender: TObject);
procedure btnClearBAClick(Sender: TObject);
procedure pcBlobfieldsChange(Sender: TObject);
procedure mnuViewShowBLOBFieldsClick(Sender: TObject);
procedure btnLoadMemoClick(Sender: TObject);
procedure btnSaveMemoClick(Sender: TObject);
procedure btnLoadGenericClick(Sender: TObject);
procedure btnSaveGenericClick(Sender: TObject);
procedure btnClearMemoClick(Sender: TObject);
procedure btnLoadGraphicClick(Sender: TObject);
procedure btnSaveGraphicClick(Sender: TObject);
procedure btnClearGraphicClick(Sender: TObject);
procedure btnClearGenericClick(Sender: TObject);
procedure meByteArrayKeyPress(Sender: TObject; var Key: Char);
procedure mnuTablePrintPreviewClick(Sender: TObject);
procedure btnSetClearRangeClick(Sender: TObject);
procedure mnuTableDesignReportClick(Sender: TObject);
procedure tsMemoTemplateResize(Sender: TObject);
procedure tsGraphicTemplateResize(Sender: TObject);
procedure tsGenericBlobTemplateResize(Sender: TObject);
procedure tsByteArrayTemplateResize(Sender: TObject);
procedure btnEditRangeClick(Sender: TObject);
procedure mnuViewShowRangeClick(Sender: TObject);
procedure FormResize(Sender: TObject);
procedure meByteArrayChange(Sender: TObject);
procedure cbWordwrapClick(Sender: TObject);
procedure mnuTableCopyToTableClick(Sender: TObject);
procedure mnuTableDeleteRecordsClick(Sender: TObject); {!!.07}
private
procedure FTableAfterPost(DataSet: TDataSet); {!!.07}
procedure FTableAfterScroll(DataSet: TDataSet);
procedure FTableAfterCancel(DataSet: TDataSet);
procedure FTableBeforeEdit(DataSet: TDataSet);
procedure FTableBeforeInsert(DataSet: TDataSet);
procedure ViewActiveBlobField;
procedure SetRange;
protected
FClient : TffClient;
FDatabaseName : TffName;
FEngine : TffRemoteServerEngine;
FLog : TffBaseLog;
FProtocol : TffProtocolType;
FReadOnly : boolean;
FServerName : TffNetAddress;
FSession : TFfSession;
FTable : TFfTable;
FTableName : TffName;
FUserName : TffName;
FPassword : TffName;
FTransport : TffLegacyTransport;
FTableItem : TffeTableItem;
dtShown : boolean;
{-Set to True if the form was actually displayed. Lets the form know
it should save user preferences. }
InRange : boolean;
{ true if SetRange has been performed }
FRangeValues : TffRangeValues;
{ the start and end values for the active range }
BeforeInitDone : Boolean;
{ to keep UpdateDisplay from being called repeatedly }
BAKeyPressDetected : Boolean;
{ to avoid going to Edit mode when changing ByteArray edit programmatically }
AddedComponentCount : Integer;
{ used to avoid duplicate names in dynamically added components }
FDynEnabledComponents, {!!.11}
FDynReadOnlyComponents: TList;
{ used to easily enable and disable the dynamically added components }
procedure SavePreferences;
procedure LoadPreferences;
procedure WMGetMinMaxInfo(var Message : TWMGetMinMaxInfo);
message WM_GETMINMAXINFO;
function HasBlobOrByteArrayField : Boolean; {!!.07}
procedure GenerateRangeDisplayStrings; {!!.07}
protected { access methods }
procedure SetReadOnly(const Value : Boolean);
public
procedure CloseDuringShow(var Message : TMessage); message ffm_Close;
procedure UpdateDisplay; {!!.01}
procedure UpdateDefaultTimeout; {!!.11}
property Protocol : TffProtocolType
read FProtocol write FProtocol;
property ServerName : TffNetAddress
read FServerName write FServerName;
property DatabaseName : TffName
read FDatabaseName write FDatabaseName;
property Log : TffBaseLog
read FLog write FLog;
property Password : TffName
read FPassword write FPassword;
property TableName : TffName
read FTableName write FTableName;
property ReadOnly : boolean
read FReadOnly write SetReadOnly;
property UserName : TffName
read FUserName write FUserName;
property TableItem : TffeTableItem
read FTableItem write FTableItem;
end;
var
dlgTable: TdlgTable;
implementation
uses
dgCpyTbl, {!!.10}
typinfo, {!!.07}
jpeg, {!!.07}
uReportEngineInterface, {!!.07}
{$IFDEF DCC6ORLater}
variants, {!!.07}
{$ENDIF}
FFLLComm,
FFLLComp,
FFLLEng,
uConfig;
{$R *.DFM}
const
MaxFilterComboItems = 10; {!!.11}
procedure TdlgTable.FormCreate(Sender: TObject);
begin
FClient := nil;
FDatabaseName := '';
FEngine := nil;
FLog := nil;
FProtocol := ptRegistry;
FReadOnly := False;
FServerName := '';
FSession := nil;
FTable := nil;
FTableName := '';
FTransport := nil;
FPassword := '';
FUserName := '';
InRange := False;
BeforeInitDone := True;
BAKeyPressDetected := False;
AddedComponentCount := 0;
FDynEnabledComponents := TList.Create; {!!.11}
FDynReadOnlyComponents := TList.Create; {!!.11}
end;
{--------}
procedure TdlgTable.SetReadOnly(const Value : Boolean);
var
i : Integer;
bm: TBookmark;
FieldsTags: TList;
begin
FReadOnly := Value;
grdTableBrowser.ReadOnly := FReadOnly;
{Begin !!.11}
{ only update the buttons after they are created,
and table when it's opened. }
if not dtShown then
Exit;
bm := FTable.GetBookmark;
FieldsTags := TList.Create;
try
{ save blob-support pointers }
for i := 0 to Pred(FTable.FieldCount) do
FieldsTags.Add(Pointer(FTable.Fields[i].Tag));
FTable.Close;
FTable.ReadOnly := ReadOnly;
FTable.Open;
for i := 0 to Pred(FTable.FieldCount) do
FTable.Fields[i].Tag := Integer(FieldsTags[i]);
FTable.GotoBookmark(bm);
finally
FTable.FreeBookmark(bm);
FieldsTags.Free;
end;
for i := 0 to Pred(ComponentCount) do
if (Components[i] is TButton) and
(((Components[i] as TButton).Caption='Load from file...') or
((Components[i] as TButton).Caption='Save to file...') or
((Components[i] as TButton).Caption='Clear')) then
(Components[i] as TButton).Enabled := not FReadOnly;
{End !!.11}
end;
{--------}
procedure TdlgTable.FormShow(Sender: TObject);
var
aServerName : string;
aAddress : string;
I : Integer;
OldPass, OldUser : string;
{$IFNDEF DCC5OrLater}
function IsPublishedProp(Source : TObject; const PropName : string) : Boolean;
var
P: PPropInfo;
begin
P := GetPropInfo(Source.ClassInfo, PropName);
Result := P <> nil;
end;
{--------}
function GetStrProp(Source : TObject; const PropName : string) : string;
var
P: PPropInfo;
begin
P := GetPropInfo(Source.ClassInfo, PropName);
if Assigned(P) then begin
Result := TypInfo.GetStrProp(Source, P);
end else
Result := '';
end;
{--------}
function SetStrProp(Source : TObject; const PropName, Value : string) : string;
var
P: PPropInfo;
begin
P := GetPropInfo(Source.ClassInfo, PropName);
if Assigned(P) then
TypInfo.SetStrProp(Source, P, Value);
end;
{--------}
procedure SetMethodProp(Source : TObject; const PropName : string; Value : TMethod);
var
P: PPropInfo;
begin
P := GetPropInfo(Source.ClassInfo, PropName);
if Assigned(P) then
TypInfo.SetMethodProp(Source, P, Value);
end;
{--------}
function GetMethodProp(Source : TObject; const PropName : string) : TMethod;
var
P: PPropInfo;
begin
P := GetPropInfo(Source.ClassInfo, PropName);
if Assigned(P) then
Result := TypInfo.GetMethodProp(Source, P);
end;
{$ENDIF}
{Begin !!.07}
function CopyComponent(Source : TComponent) : TComponent;
var
PropStream : TMemoryStream;
OldText, OldName : String;
begin
Result := Nil;
if assigned(Source) then
begin
PropStream := TMemoryStream.Create;
try
//prevent doubled component names
OldName := Source.Name;
Source.Name := OldName + IntToStr(AddedComponentCount);
Inc(AddedComponentCount);
//Save the "stored" properties to memory
PropStream.WriteComponent(Source);
Source.Name := OldName;
//e.g. TEdit will change it's content if renamed
if IsPublishedProp(Source,'Text') then
OldText := GetStrProp(Source,'Text')
else
//Some Captions may face the same problem
if IsPublishedProp(Source,'Caption') then
OldText := GetStrProp(Source,'Caption');
Result := TComponentClass(Source.ClassType).Create(Source.Owner);
PropStream.Position := 0;
PropStream.ReadComponent(Result);
// Result.Name := OldName + IntToStr(AddedComponentCount);
//Handle Components with a "Text" or "Caption" -property;
//e.g. TEdit, TLabel
if IsPublishedProp(Source,'Text') then
begin
SetStrProp(Source,'Text',OldText);
SetStrProp(Result,'Text',OldText);
end
else
if IsPublishedProp(Source,'Caption') then
begin
SetStrProp(Source,'Caption',OldText);
SetStrProp(Result,'Caption',OldText);
end;
finally
PropStream.Free;
end;
end;
end;
{ generates a new tabsheet and hooks up
components on the new tabsheet to the field }
procedure CreateNewBlobTabSheet(SheetToCopy : TTabSheet; OnResizeProc : TNotifyEvent; FieldIndex : Integer);
var
NewSheet : TTabSheet;
Idx : Integer;
NewComponent : TComponent;
begin
NewSheet := TTabSheet.Create(pcBlobFields);
NewSheet.PageControl := pcBlobFields;
NewSheet.Caption := FTable.Fields[FieldIndex].FieldName;
{$IFDEF DCC4OrLater}
NewSheet.OnResize := OnResizeProc;
{$ENDIF}
for Idx := 0 to SheetToCopy.ControlCount-1 do begin
NewComponent := CopyComponent(SheetToCopy.Controls[Idx]);
TControl(NewComponent).Parent := NewSheet;
if IsPublishedProp(NewComponent, 'DataField') then
SetStrProp(NewComponent, 'DataField', FTable.Fields[FieldIndex].FieldName);
if (IsPublishedProp(NewComponent, 'OnClick')) then
SetMethodProp(NewComponent, 'OnClick', GetMethodProp(SheetToCopy.Controls[Idx], 'OnClick'));
if (IsPublishedProp(NewComponent, 'OnKeyPress')) then
SetMethodProp(NewComponent, 'OnKeyPress', GetMethodProp(SheetToCopy.Controls[Idx], 'OnKeyPress'));
if (IsPublishedProp(NewComponent, 'OnChange')) then
SetMethodProp(NewComponent, 'OnChange', GetMethodProp(SheetToCopy.Controls[Idx], 'OnChange'));
// if NewComponent. IS TCheckBox
// SetStrProp(NewComponent, 'OnClick', FTable.Fields.Fields[FieldIndex].FieldName);
{ save pointer to the control displaying the field }
if (NewComponent IS TImage) or { graphictemplate }
(NewComponent IS TMaskEdit) or { bytearraytemplate }
(NewComponent IS TMemo) or { generictemplate }
(NewComponent IS TdbMemo) then { memotemplate }
FTable.Fields[FieldIndex].Tag := Integer(NewComponent);
end;
end;
{End !!.07}
begin
dtShown := False;
try
{ Set up the connection. }
FTransport := TffLegacyTransport.Create(nil);
with FTransport do begin
Mode := fftmSend;
Protocol := FProtocol;
EventLog := FLog;
if Assigned(FLog) then begin
EventLogEnabled := True;
EventLogOptions := [fftpLogErrors];
end;
ServerName := FServerName;
end;
FEngine := TffRemoteServerEngine.Create(nil);
FEngine.Transport := FTransport;
FClient := TffClient.Create(nil);
FClient.ServerEngine := FEngine;
FClient.AutoClientName := True;
FClient.TimeOut := Config.DefaultTimeout; {!!.11}
FSession := TffSession.Create(nil);
FSession.ClientName := FClient.ClientName;
FSession.AutoSessionName := True;
OldPass := ffclPassword;
OldUser := ffclUserName;
try
if FPassword <> '' then begin
ffclPassword := FPassword;
ffclUserName := FUserName;
end;
FSession.Open;
finally
ffclPassword := OldPass;
ffclUserName := OldUser;
end;
FTable := TffTable.Create(nil);
FTable.SessionName := FSession.SessionName;
FTable.DatabaseName := FDatabaseName;
FTable.TableName := FTableName;
FTable.AfterPost := FTableAfterPost; {!!.07}
FTable.AfterDelete := FTableAfterPost; {!!.07}
FTable.AfterScroll := FTableAfterScroll; {!!.07}
FTable.AfterCancel := FTableAfterCancel; {!!.07}
FTable.BeforeEdit := FTableBeforeEdit;
FTable.BeforeInsert := FTableBeforeInsert;
FTable.ReadOnly := ReadOnly; {!!.11}
FTable.Open;
{ Set up the indexes }
cboIndex.Items.Clear;
with FTable.IndexDefs do begin
Clear;
Update;
for I := 0 to Count - 1 do
cboIndex.Items.Add(Items[I].Name);
end;
cboIndex.ItemIndex := 0;
FTable.IndexName := cboIndex.Items[cboIndex.ItemIndex];
{ Update the find controls }
cboIndexChange(nil);
FFSeparateAddress(FTransport.ServerName, aServerName, aAddress);
Self.Caption := format('%s : %s : %s',
[aServerName, FDatabaseName, FTableName]);
dsTableBrowser.DataSet := FTable;
{Begin !!.07}
{ check if there are any BLOB fields in the table
and populate the pagecontrol with appropriate controls if so }
{ make the templates invisible }
for I := 0 to pcBlobFields.PageCount-1 do
pcBlobFields.Pages[I].TabVisible := False;
{ generate new tabsheets for blobfields }
for I := 0 to FTable.Dictionary.FieldCount-1 do begin
case FTable.Dictionary.FieldType[I] of
fftBLOBMemo,
fftBLOBFmtMemo : CreateNewBlobTabSheet(tsMemoTemplate, tsMemoTemplateResize, I);
fftBLOBGraphic : CreateNewBlobTabSheet(tsGraphicTemplate, tsGraphicTemplateResize, I);
fftByteArray : CreateNewBlobTabSheet(tsByteArrayTemplate, tsByteArrayTemplateResize, I);
fftBLOB,
fftBLOBOLEObj,
fftBLOBDBSOLEObj,
fftBLOBTypedBin,
fftBLOBFile : CreateNewBlobTabSheet(tsGenericBlobTemplate, tsGenericBlobTemplateResize, I);
end;
end;
{End !!.07}
LoadPreferences;
BeforeInitDone := False;
UpdateDisplay;
ViewActiveBlobField; {!!.07}
{ make sure no column exceeds screen width } {!!.07}
for I := 0 to grdTableBrowser.Columns.Count-1 do begin
if grdTableBrowser.Columns[i].Width>(Width DIV 5)*4 then
grdTableBrowser.Columns[i].Width := (Width DIV 5)*4;
end;
dtShown := True;
{ update newly created dynamic components }
ReadOnly := FReadOnly; {!!.11}
{ large font support... }
if (Screen.PixelsPerInch/PixelsPerInch)>1.001 then begin
Height := Round(Height * (Screen.PixelsPerInch/PixelsPerInch));
Width := Round(Width * (Screen.PixelsPerInch/PixelsPerInch));
barStatus.Height := Round(barStatus.Height * (Screen.PixelsPerInch/PixelsPerInch));
end;
{ report menuitems }
mnuTablePrintPreview.Enabled := ReportEngineDLLLoaded;
mnuTableDesignReport.Enabled := ReportEngineDLLLoaded;
except
on E:Exception do begin
showMessage(E.message);
PostMessage(Handle, ffm_Close, 0, longInt(Sender));
end;
end;
end;
{--------}
procedure TdlgTable.cboIndexChange(Sender: TObject);
var
BaseSection : string;
Index : Integer;
begin
BaseSection := ClassName + '.' + Self.Caption;
with FTable do
if IndexName <> cboIndex.Items[cboIndex.ItemIndex] then begin
IndexName := cboIndex.Items[cboIndex.ItemIndex];
end;
lblFind.Visible := cboIndex.ItemIndex > 0;
edtFind.Visible := cboIndex.ItemIndex > 0;
btnFindNear.Visible := cboIndex.ItemIndex > 0;
btnSetClearRange.Enabled := cboIndex.ItemIndex > 0;
btnEditRange.Enabled := cboIndex.ItemIndex > 0;
{ clear range - btnSetClearRangeClick flips InRange }
InRange := True;
btnSetClearRangeClick(Self);
for Index := Low(FRangeValues.Field) to FTable.IndexFieldCount do begin
FRangeValues.Field[Index].StartNull := FFEConfigGetBoolean(BaseSection, FTable.IndexName+'_RangeStartNull'+IntToStr(Index), True);
FRangeValues.Field[Index].EndNull := FFEConfigGetBoolean(BaseSection, FTable.IndexName+'_RangeEndNull'+IntToStr(Index), True);
FRangeValues.Field[Index].StartValue := FFEConfigGetString(BaseSection, FTable.IndexName+'_RangeStartValue'+IntToStr(Index), '');
FRangeValues.Field[Index].EndValue := FFEConfigGetString(BaseSection, FTable.IndexName+'_RangeEndValue'+IntToStr(Index), '');;
end;
FRangeValues.RangeStartKeyExclusive := FFEConfigGetBoolean(BaseSection, FTable.IndexName+'_RangeStartKeyExclusive', False);
FRangeValues.RangeEndKeyExclusive := FFEConfigGetBoolean(BaseSection, FTable.IndexName+'_RangeEndKeyExclusive', False);
GenerateRangeDisplayStrings;
end;
{--------}
procedure TdlgTable.btnFindClick(Sender: TObject);
begin
try
FTable.FindNearest([edtFind.Text]);
except
on E: EffDatabaseError do begin
if E.ErrorCode = 8706 then
ShowMessage(format('%s not found.', [edtFind.Text]))
else
ShowMessage(E.Message);
end;
end;
end;
{--------}
procedure TdlgTable.mnuTableCloseClick(Sender: TObject);
begin
Close;
end;
{--------}
procedure TdlgTable.FormClose(Sender: TObject; var Action: TCloseAction);
begin
if dtShown then
SavePreferences;
Action := caFree;
end;
{--------}
procedure TdlgTable.mnuViewRefreshClick(Sender: TObject);
begin
FTable.Refresh;
UpdateDisplay;
end;
{--------}
procedure TdlgTable.UpdateDisplay;
begin
if BeforeInitDone then
Exit;
if mnuViewShowRecordCount.Checked then
barStatus.Panels[0].Text := 'Records: ' + FFCommaizeChL(FTable.RecordCount, ThousandSeparator)
else
barStatus.Panels[0].Text := '';
if FTable.Filtered then
barStatus.Panels[1].Text := 'Filter: <ACTIVE>'
else
barStatus.Panels[1].Text := 'Filter: <Inactive>';
if InRange then begin
barStatus.Panels[2].Text := 'Range: <ACTIVE>';
laRangeStart.Font.Style := [fsBold];
laRangeEnd.Font.Style := [fsBold];
laRangeStartDesc.Font.Style := [fsBold];
laRangeEndDesc.Font.Style := [fsBold];
end
else begin
barStatus.Panels[2].Text := 'Range: <Inactive>';
laRangeStart.Font.Style := [];
laRangeEnd.Font.Style := [];
laRangeStartDesc.Font.Style := [];
laRangeEndDesc.Font.Style := [];
end;
with navTableBrowser do begin
VisibleButtons := [nbFirst, nbLast, nbPrior, nbNext, nbRefresh];
if (not FTable.ReadOnly) and (not FReadOnly) then
VisibleButtons := VisibleButtons + [nbInsert, nbDelete, nbEdit, nbPost, nbCancel];
end;
end;
{--------}
procedure TdlgTable.mnuViewShowFilterClick(Sender: TObject);
begin
mnuViewShowFilter.Checked := not mnuViewShowFilter.Checked;
pnlFilter.Visible := mnuViewShowFilter.Checked;
{ make sure to reset statusbar etc if status changes }
if FTable.Filtered then
btnSetFilterClick(Self);
// edtFilter.Text := ''; why remove? makes sense to keep the text, the user might need it again!
end;
{--------}
procedure TdlgTable.btnFilterClick(Sender: TObject);
begin
if FTable.Filtered then begin
FTable.Filtered := False;
btnSetFilter.Caption := 'S&et Filter'; {!!.03}
end else begin
FTable.Filter := cboFilter.Text;
FTable.Filtered := True;
btnSetFilter.Caption := 'Cl&ear Filter'; {!!.03}
end;
end;
{--------}
procedure TdlgTable.FormDestroy(Sender: TObject);
begin
{Begin !!.05 !!.10}
try
FTable.Close;
finally
FTable.Free;
end;
try
FSession.Active := False;
finally
FSession.Free;
end;
try
FClient.Close;
finally
FClient.Free;
end;
try
FEngine.Shutdown;
finally
FEngine.Free;
end;
try
FTransport.Shutdown;
finally
FTransport.Free;
end;
{End !!.05}
FDynEnabledComponents.Free; {!!.11}
FDynReadOnlyComponents.Free; {!!.11}
end;
{--------}
procedure TdlgTable.CloseDuringShow(var Message : TMessage);
begin
Close;
end;
{--------}
procedure TdlgTable.WMGetMinMaxInfo(var Message : TWMGetMinMaxInfo);
var
MinMax : PMinMaxInfo;
begin
inherited;
MinMax := Message.MinMaxInfo;
MinMax^.ptMinTrackSize.x := 590;
end;
{--------}
procedure TdlgTable.btnFindNearClick(Sender: TObject);
begin
try
FTable.FindNearest([edtFind.Text]);
except
on E: EffDatabaseError do begin
if E.ErrorCode = 8706 then
ShowMessage(format('%s not found.', [edtFind.Text]))
else
ShowMessage(E.Message);
end;
end;
end;
{--------}
procedure TdlgTable.btnSetFilterClick(Sender: TObject);
{Begin !!.05}
var
SavCursor : TCursor;
begin
SavCursor := Screen.Cursor;
Screen.Cursor := crHourGlass;
try
if FTable.Filtered then begin
FTable.Filtered := False;
btnSetFilter.Caption := 'S&et Filter'; {!!.03}
end else begin
FTable.Filter := cboFilter.Text;
FTable.Filtered := True;
btnSetFilter.Caption := 'Cl&ear Filter'; {!!.03}
{Begin !!.11}
{ update history list in combobox }
if FTable.Filter<>'' then begin
{ does filter exist in the list? }
if cboFilter.Items.IndexOf(FTable.Filter)>=0 then
{ if so remove it; no doubles needed }
cboFilter.Items.Delete(cboFilter.Items.IndexOf(FTable.Filter));
{ make last filter string top of the history list }
cboFilter.Items.Insert(0, FTable.Filter);
cboFilter.ItemIndex := 0;
{ enforce maxcount }
while cboFilter.Items.Count>MaxFilterComboItems do
cboFilter.Items.Delete(MaxFilterComboItems);
end;
{End !!.11}
end;
UpdateDisplay;
finally
Screen.Cursor := SavCursor;
end;
{End !!.05}
end;
{--------}
procedure TdlgTable.edtFindEnter(Sender: TObject);
begin
btnSetFilter.Default := False;
btnFindNear.Default := True;
end;
{--------}
procedure TdlgTable.cboFilterEnter(Sender: TObject);
begin
btnFindNear.Default := False;
btnSetFilter.Default := True;
end;
{--------}
procedure TdlgTable.SavePreferences;
var
BaseSection : string;
i : Integer; {!!.11}
begin
try
BaseSection := ClassName + '.' + Self.Caption;
FFEConfigSaveString(BaseSection, 'Last Filter', cboFilter.Text);
{Begin !!.11}
for i := 0 to Pred(cboFilter.Items.Count) do
FFEConfigSaveString(BaseSection, 'FilterHistory'+IntToStr(i), cboFilter.Items[i]);
{End !!.11}
FFEConfigSaveString(BaseSection, 'Last Find Nearest', edtFind.Text);
FFEConfigSaveInteger(BaseSection, 'Last Index', cboIndex.ItemIndex);
FFEConfigSaveBoolean(BaseSection, 'Show record count', mnuViewShowRecordCount.Checked);
FFEConfigSaveFormPrefs(BaseSection, Self);
FFEConfigSaveDBColumnPrefs(BaseSection + '.ColumnInfo', grdTableBrowser.Columns);
FFEConfigSaveInteger(BaseSection, 'Table Timeout', FTable.Timeout); {!!.07}
FFEConfigSaveInteger(BaseSection, 'PageControl size', pcBlobfields.Height); {!!.07}
FFEConfigSaveBoolean(BaseSection, 'Show blob fields', mnuViewShowBLOBFields.Checked); {!!.07}
FFEConfigSaveBoolean(BaseSection, 'Show range', mnuViewShowRange.Checked); {!!.07}
FFEConfigSaveBoolean(BaseSection, 'Show filter', mnuViewShowFilter.Checked); {!!.07}
except
on E:Exception do
ShowMessage('Error writing INI file: '+E.Message);
end;
end;
{--------}
procedure TdlgTable.LoadPreferences;
var
BaseSection : string;
Index : Integer;
s : String; {!!.11}
begin
BaseSection := ClassName + '.' + Self.Caption;
cboFilter.Text := FFEConfigGetString(BaseSection, 'Last Filter', '');
{Begin !!.11}
for Index := 0 to Pred(MaxFilterComboItems) do begin
s := FFEConfigGetString(BaseSection, 'FilterHistory'+IntToStr(Index), '');
if s<>'' then
cboFilter.Items.Add(s);
end;
{End !!.11}
Index := FFEConfigGetInteger(BaseSection, 'Last Index', 0);
if (Index < cboIndex.Items.Count) then begin
cboIndex.ItemIndex := Index;
FTable.IndexName := cboIndex.Items[cboIndex.ItemIndex];
{ Update the find controls }
cboIndexChange(nil);
end;
edtFind.Text := FFEConfigGetString(BaseSection, 'Last Find Nearest', '');
mnuViewShowRecordCount.Checked := FFEConfigGetBoolean(BaseSection, 'Show record count', True);
FFEConfigGetFormPrefs(BaseSection, Self);
FFEConfigGetDBColumnPrefs(BaseSection + '.ColumnInfo', grdTableBrowser.Columns);
FTable.Timeout := FFEConfigGetInteger(BaseSection, 'Table Timeout', -1); {!!.07}
pcBlobfields.Height := FFEConfigGetInteger(BaseSection, 'PageControl size', pcBlobfields.Height); {!!.07}
mnuViewShowBLOBFields.Checked := HasBlobOrByteArrayField and FFEConfigGetBoolean(BaseSection, 'Show blob fields', True); {!!.07}
if not HasBlobOrByteArrayField then
mnuViewShowBLOBFields.Enabled := False;
pcBlobfields.Visible := mnuViewShowBLOBFields.Checked and HasBlobOrByteArrayField;
splGridAndPageControl.Visible := mnuViewShowBLOBFields.Checked and HasBlobOrByteArrayField;
mnuViewShowRange.Checked := FFEConfigGetBoolean(BaseSection, 'Show range', True); {!!.07}
pnlRange.Visible := mnuViewShowRange.Checked;
mnuViewShowFilter.Checked := FFEConfigGetBoolean(BaseSection, 'Show filter', True); {!!.07}
pnlFilter.Visible := mnuViewShowFilter.Checked;
end;
{--------}
procedure TdlgTable.mnuViewShowRecordCountClick(Sender: TObject);
begin
mnuViewShowRecordCount.Checked := not mnuViewShowRecordCount.Checked;
UpdateDisplay;
end;
procedure TdlgTable.mnuTableResetColClick(Sender: TObject);
begin
grdTableBrowser.Columns.RebuildColumns;
end;
procedure TdlgTable.grdTableBrowserKeyDown(Sender: TObject; var Key: Word;
Shift: TShiftState);
var
DoPost : Boolean; {!!.11}
begin
{ Delete record? }
if ((key = VK_DELETE) and
(shift = []) and
(dsTableBrowser.State = dsBrowse)) and
(not grdTableBrowser.ReadOnly) then
if (MessageDlg('Delete record?', mtConfirmation, mbOKCancel, 0) <> idCancel) then
dsTableBrowser.DataSet.Delete;
{Begin !!.11}
{ set field to NULL? }
if ((key = Ord('0')) and
(shift = [ssCtrl]) and
(not grdTableBrowser.ReadOnly) and
(not FTable.IsEmpty)) then begin
DoPost := not (FTable.State in [dsInsert, dsEdit]);
if DoPost then
FTable.Edit;
grdTableBrowser.SelectedField.Clear;
if DoPost then
FTable.Post;
{ refresh; could be blobfield }
ViewActiveBlobField;
end;
{End !!.11}
end;
{Begin !!.02}
{--------}
procedure TdlgTable.mnuOptionsDebugClick(Sender: TObject);
begin
mnuOptionsDebug.Checked := not mnuOptionsDebug.Checked;
if mnuOptionsDebug.Checked then
FTransport.EventLogOptions := [fftpLogErrors, fftpLogRequests,
fftpLogReplies]
else
FTransport.EventLogOptions := [fftpLogErrors];
end;
{End !!.02}
{Begin !!.07}
procedure TdlgTable.FTableAfterPost(DataSet: TDataSet);
begin
if FTable.Database.InTransaction then
FTable.Database.Commit;
UpdateDisplay;
end;
{--------}
procedure TdlgTable.FTableAfterCancel(DataSet: TDataSet);
begin
if FTable.Database.InTransaction then
FTable.Database.Rollback;
FTable.Refresh;
ViewActiveBlobField;
end;
{--------}
procedure TdlgTable.FTableAfterScroll(DataSet: TDataSet);
begin
ViewActiveBlobField;
end;
{--------}
procedure TdlgTable.FTableBeforeEdit(DataSet: TDataSet);
begin
if not FTable.Database.InTransaction then
FTable.Database.StartTransaction;
end;
{--------}
procedure TdlgTable.FTableBeforeInsert(DataSet: TDataSet);
begin
if not FTable.Database.InTransaction then
FTable.Database.StartTransaction;
end;
{--------}
procedure TdlgTable.mnuOptionsTimeoutClick(Sender: TObject);
var
sTimeout : String;
res : Boolean;
begin
sTimeout := IntToStr(FTable.Timeout);
repeat
res := InputQuery('Table Timeout (ms)', 'Value:', sTimeout);
if res then
try
FTable.Timeout := StrToInt(sTimeout);
if FTable.Timeout<-1 then
raise EConvertError.Create('');
res := False;
except
on EConvertError do begin
MessageDlg('Value must be a number between -1 and '+IntToStr(MaxInt), mtError, [mbOK], 0);
end;
end;
until not res;
end;
{--------}
procedure TdlgTable.FormKeyDown(Sender: TObject; var Key: Word;
Shift: TShiftState);
begin
if (not (FTable.State IN [dsInsert, dsEdit])) and
(Key = VK_ESCAPE) then
Close;
end;
{--------}
procedure TdlgTable.ViewActiveBlobField;
const
JPEGHeader : array [0..10] of Char = (Chr($FF), Chr($D8), Chr($FF), Chr($E0),
Chr($0), Chr($10), 'J', 'F', 'I', 'F', Chr(0));
BMPHeader : array [0..1] of char = ('B', 'M');
WMFHeader : array [0..1] of char = ('B', 'M');
ICOHeader : array [0..1] of char = ('B', 'M');
HexChar : array [0..15] of char = '0123456789ABCDEF';
var
HeaderBuffer : array [0..10] of char;
Stream : TffBlobStream;
jpegImage : TJPEGImage;
i : Integer;
BlobBuffer : array [0..1024] of char;
ByteArrayBuffer : Pointer;
tempStr : String;
{ copied from TffEventLog.WriteBlock and transmogrified }
function GenerateHexLines(Buf : pointer; BufLen : TffMemSize) : String;
const
HexPos : array [0..15] of byte =
(1, 3, 5, 7, 10, 12, 14, 16, 19, 21, 23, 25, 28, 30, 32, 34);
var
B : PffByteArray absolute Buf;
ThisWidth,
i, j : integer;
Line : string[56];
Work : byte;
begin
Result := '';
if (BufLen = 0) or (Buf = nil) then
Exit
else begin
if (BufLen > 1024) then begin
BufLen := 1024;
end;
for i := 0 to ((BufLen-1) shr 4) do begin
FillChar(Line, 56, ' ');
Line[0] := #55;
Line[38] := '['; Line[55] := ']';
if (BufLen >= 16) then
ThisWidth := 16
else
ThisWidth := BufLen;
for j := 0 to ThisWidth-1 do begin
Work := B^[(i shl 4) + j];
Line[HexPos[j]] := HexChar[Work shr 4];
Line[HexPos[j]+1] := HexChar[Work and $F];
if (Work < 32) {or (Work >= $80)} then
Work := ord('.');
Line[39+j] := char(Work);
end;
Result := Result + Line + ffcCRLF;
dec(BufLen, ThisWidth);
end;
end;
end;
function ByteArrayToHexString(ByteArray : Pointer; ArrayLength : Integer) : String;
var
idx : Integer;
BArr : PffByteArray absolute ByteArray;
begin
Result := '';
for idx := 0 to ArrayLength-1 do begin
Result := Result + HexChar[BArr[idx] shr 4];
Result := Result + HexChar[BArr[idx] and $F];
end;
end;
begin
{ load non-db blob controls }
if mnuViewShowBLOBFields.Checked and
HasBlobOrByteArrayField then begin
for i := 0 to FTable.Dictionary.FieldCount-1 do begin
{ only load blob on active tabsheet }
if Assigned(Pointer(FTable.Fields[i].Tag)) and
(FTable.Fields[i].FieldName=pcBlobfields.ActivePage.Caption) then
case FTable.Dictionary.FieldType[i] of
fftBLOBGraphic : begin
try
Stream := TffBlobStream(FTable.CreateBlobStream(FTable.Fields[i], bmRead));
try
TImage(FTable.Fields[i].Tag).Picture.Bitmap.Assign(NIL);
TImage(FTable.Fields[i].Tag).Invalidate;
// if Stream.Size>0 then
{ data in stream? }
if (Stream.Read(HeaderBuffer, 11)=11) then
{ jpg? }
if CompareMem(@jpegHeader, @HeaderBuffer, 11) then begin
Stream.Position := 0;
jpegImage := TJPEGImage.Create;
try
jpegImage.LoadFromStream(stream);
TImage(FTable.Fields[i].Tag).Picture.Bitmap.Assign(jpegImage);
finally
jpegImage.Free;
end;
end
else
{bmp?}
if CompareMem(@BMPHeader, @HeaderBuffer, 2) or
CompareMem(@BMPHeader, @HeaderBuffer[8], 2) then begin
if CompareMem(@BMPHeader, @HeaderBuffer, 2) then
Stream.Position := 0
else
Stream.Position := 8;
TImage(FTable.Fields[i].Tag).Picture.Bitmap.LoadFromStream(stream);
end
else begin
{metafile?}
{ it's difficult to check for the metafile type. we just
attempt to load and let the TImage component find out. }
Stream.Position := 8;
try
TImage(FTable.Fields[i].Tag).Picture.Metafile.LoadFromStream(stream);
except
on EInvalidGraphic do begin
Stream.Position := 0;
try
TImage(FTable.Fields[i].Tag).Picture.Metafile.LoadFromStream(stream);
except
on EInvalidGraphic do begin
{icon?}
{ it's difficult to check for the icon type. we just
attempt to load and let the TImage component find out. }
Stream.Position := 8;
try
TImage(FTable.Fields[i].Tag).Picture.Icon.LoadFromStream(stream);
except
on EInvalidGraphic do begin
Stream.Position := 0;
try
TImage(FTable.Fields[i].Tag).Picture.Icon.LoadFromStream(stream);
except
on EInvalidGraphic do
else
raise;
end;
end
else
raise;
end;
end
else
raise;
end;
end
else
raise;
end;
end;
finally
Stream.Free;
end;
except
on E:Exception do begin
ShowMessage('Exception: '+E.Message+' decoding graphic field: '+FTable.Fields[i].FieldName);
end;
end;
end;
fftByteArray : begin
with TMaskEdit(FTable.Fields[i].Tag) do begin
Text := '';
MaxLength := FTable.Fields[i].Size*2;
SetLength(tempStr, MaxLength);
FillChar(tempStr[1], MaxLength, 'a');
EditMask := tempStr + ';0;_';
GetMem(ByteArrayBuffer, FTable.Fields[i].DataSize);
try
if FTable.Fields[i].GetData(ByteArrayBuffer) then
Text := ByteArrayToHexString(ByteArrayBuffer, FTable.Fields[i].DataSize);
finally
FreeMem(ByteArrayBuffer);
end;
end;
end;
fftBLOB,
fftBLOBOLEObj,
fftBLOBDBSOLEObj,
fftBLOBTypedBin,
fftBLOBFile : begin
try
Stream := TffBlobStream(FTable.CreateBlobStream(FTable.Fields[i], bmRead));
try
TMemo(FTable.Fields[i].Tag).Text := '';
Stream.Read(BlobBuffer, FFMinL(1024, Stream.Size));
TMemo(FTable.Fields[i].Tag).Text :=
GenerateHexLines(@BlobBuffer, FFMinL(1024, Stream.Size));
finally
Stream.Free;
end;
except
on E:Exception do begin
ShowMessage('Exception: '+E.Message+' when displaying blob field: '+FTable.Fields[i].FieldName);
end;
end;
end;
end;
end;
end;
end;
{--------}
function TdlgTable.HasBlobOrByteArrayField: Boolean;
var
i : Integer;
begin
Result := False;
for i := 0 to FTable.Dictionary.FieldCount-1 do
if FTable.Dictionary.FieldType[i] IN [fftBLOB..ffcLastBLOBType, fftByteArray] then begin
Result := True;
Exit;
end;
end;
{--------}
procedure TdlgTable.cbStretchClick(Sender: TObject);
var
i : Integer;
begin
for i := 0 to TCheckBox(Sender).Parent.ControlCount-1 do
if TCheckBox(Sender).Parent.Controls[i] IS TImage then begin
TImage(TCheckBox(Sender).Parent.Controls[i]).Stretch := TCheckBox(Sender).Checked;
Exit;
end;
end;
{--------}
procedure TdlgTable.btnClearBAClick(Sender: TObject);
var
fieldIdx,
controlIdx : Integer;
aEdit : TMaskEdit;
aField : TField;
begin
{ find edit control }
for controlIdx := 0 to TButton(Sender).Parent.ControlCount-1 do
if TButton(Sender).Parent.Controls[controlIdx] IS TMaskEdit then begin
aEdit := TMaskEdit(TButton(Sender).Parent.Controls[controlIdx]);
{ find correct field }
for fieldIdx := 0 to FTable.Dictionary.FieldCount-1 do begin
if Pointer(FTable.Fields[fieldIdx].Tag)=aEdit then begin
aField := FTable.Fields[fieldIdx];
if not (FTable.State in [dsInsert, dsEdit]) then
FTable.Edit;
aField.Clear;
aEdit.Text := '';
Exit;
end;
end;
end;
end;
{--------}
procedure TdlgTable.pcBlobfieldsChange(Sender: TObject);
begin
ViewActiveBlobField;
end;
{--------}
procedure TdlgTable.mnuViewShowBLOBFieldsClick(Sender: TObject);
begin
mnuViewShowBLOBFields.Checked := not mnuViewShowBLOBFields.Checked;
pcBlobfields.Visible := mnuViewShowBLOBFields.Checked;
splGridAndPageControl.Visible := mnuViewShowBLOBFields.Checked;
if mnuViewShowBLOBFields.Checked then
ViewActiveBlobField;
end;
{--------}
procedure TdlgTable.btnLoadMemoClick(Sender: TObject);
var
fieldIdx,
controlIdx : Integer;
adbMemo : TdbMemo;
aField : TField;
begin
if opendialog.Execute then
{ find dbmemo control }
for controlIdx := 0 to TButton(Sender).Parent.ControlCount-1 do
if TButton(Sender).Parent.Controls[controlIdx] IS TdbMemo then begin
adbMemo := TdbMemo(TButton(Sender).Parent.Controls[controlIdx]);
{ find correct field }
for fieldIdx := 0 to FTable.Dictionary.FieldCount-1 do begin
if Pointer(FTable.Fields[fieldIdx].Tag)=adbMemo then begin
aField := FTable.Fields[fieldIdx];
if not (FTable.State in [dsInsert, dsEdit]) then
FTable.Edit;
TMemoField(aField).LoadFromFile(opendialog.FileName);
Exit;
end;
end;
end;
end;
{--------}
procedure TdlgTable.btnSaveMemoClick(Sender: TObject);
var
fieldIdx,
controlIdx : Integer;
adbMemo : TdbMemo;
aField : TField;
begin
if savedialog.Execute then
{ find dbmemo control }
for controlIdx := 0 to TButton(Sender).Parent.ControlCount-1 do
if TButton(Sender).Parent.Controls[controlIdx] IS TdbMemo then begin
adbMemo := TdbMemo(TButton(Sender).Parent.Controls[controlIdx]);
{ find correct field }
for fieldIdx := 0 to FTable.Dictionary.FieldCount-1 do begin
if Pointer(FTable.Fields[fieldIdx].Tag)=adbMemo then begin
aField := FTable.Fields[fieldIdx];
TMemoField(aField).SaveToFile(savedialog.FileName);
Exit;
end;
end;
end;
end;
{--------}
procedure TdlgTable.btnLoadGenericClick(Sender: TObject);
var
fieldIdx,
controlIdx : Integer;
aMemo : TMemo;
aField : TField;
begin
if opendialog.Execute then
{ find memo control }
for controlIdx := 0 to TButton(Sender).Parent.ControlCount-1 do
if TButton(Sender).Parent.Controls[controlIdx] IS TMemo then begin
aMemo := TMemo(TButton(Sender).Parent.Controls[controlIdx]);
{ find correct field }
for fieldIdx := 0 to FTable.Dictionary.FieldCount-1 do begin
if Pointer(FTable.Fields[fieldIdx].Tag)=aMemo then begin
aField := FTable.Fields[fieldIdx];
if not (FTable.State in [dsInsert, dsEdit]) then
FTable.Edit;
TBlobField(aField).LoadFromFile(opendialog.FileName);
ViewActiveBlobField;
Exit;
end;
end;
end;
end;
{--------}
procedure TdlgTable.btnSaveGenericClick(Sender: TObject);
var
fieldIdx,
controlIdx : Integer;
aMemo : TMemo;
aField : TField;
begin
if savedialog.Execute then
{ find memo control }
for controlIdx := 0 to TButton(Sender).Parent.ControlCount-1 do
if TButton(Sender).Parent.Controls[controlIdx] IS TMemo then begin
aMemo := TMemo(TButton(Sender).Parent.Controls[controlIdx]);
{ find correct field }
for fieldIdx := 0 to FTable.Dictionary.FieldCount-1 do begin
if Pointer(FTable.Fields[fieldIdx].Tag)=aMemo then begin
aField := FTable.Fields[fieldIdx];
TBlobField(aField).SaveToFile(savedialog.FileName);
Exit;
end;
end;
end;
end;
{--------}
procedure TdlgTable.btnClearMemoClick(Sender: TObject);
var
fieldIdx,
controlIdx : Integer;
adbMemo : TdbMemo;
aField : TField;
begin
{ find dbmemo control }
for controlIdx := 0 to TButton(Sender).Parent.ControlCount-1 do
if TButton(Sender).Parent.Controls[controlIdx] IS TdbMemo then begin
adbMemo := TdbMemo(TButton(Sender).Parent.Controls[controlIdx]);
{ find correct field }
for fieldIdx := 0 to FTable.Dictionary.FieldCount-1 do begin
if Pointer(FTable.Fields[fieldIdx].Tag)=adbMemo then begin
aField := FTable.Fields[fieldIdx];
if not (FTable.State in [dsInsert, dsEdit]) then
FTable.Edit;
aField.Clear;
Exit;
end;
end;
end;
end;
{--------}
procedure TdlgTable.btnLoadGraphicClick(Sender: TObject);
var
fieldIdx,
controlIdx : Integer;
aImage : TImage;
aField : TField;
begin
if opendialog.Execute then
{ find Image control }
for controlIdx := 0 to TButton(Sender).Parent.ControlCount-1 do
if TButton(Sender).Parent.Controls[controlIdx] IS TImage then begin
aImage := TImage(TButton(Sender).Parent.Controls[controlIdx]);
{ find correct field }
for fieldIdx := 0 to FTable.Dictionary.FieldCount-1 do begin
if Pointer(FTable.Fields[fieldIdx].Tag)=aImage then begin
aField := FTable.Fields[fieldIdx];
if not (FTable.State in [dsInsert, dsEdit]) then
FTable.Edit;
TBlobField(aField).LoadFromFile(opendialog.FileName);
ViewActiveBlobField;
Exit;
end;
end;
end;
end;
{--------}
procedure TdlgTable.btnSaveGraphicClick(Sender: TObject);
var
fieldIdx,
controlIdx : Integer;
aImage : TImage;
aField : TField;
begin
if savedialog.Execute then
{ find Image control }
for controlIdx := 0 to TButton(Sender).Parent.ControlCount-1 do
if TButton(Sender).Parent.Controls[controlIdx] IS TImage then begin
aImage := TImage(TButton(Sender).Parent.Controls[controlIdx]);
{ find correct field }
for fieldIdx := 0 to FTable.Dictionary.FieldCount-1 do begin
if Pointer(FTable.Fields[fieldIdx].Tag)=aImage then begin
aField := FTable.Fields[fieldIdx];
TBlobField(aField).SaveToFile(savedialog.FileName);
Exit;
end;
end;
end;
end;
{--------}
procedure TdlgTable.btnClearGraphicClick(Sender: TObject);
var
fieldIdx,
controlIdx : Integer;
aImage : TImage;
aField : TField;
begin
{ find image control }
for controlIdx := 0 to TButton(Sender).Parent.ControlCount-1 do
if TButton(Sender).Parent.Controls[controlIdx] IS TImage then begin
aImage := TImage(TButton(Sender).Parent.Controls[controlIdx]);
{ find correct field }
for fieldIdx := 0 to FTable.Dictionary.FieldCount-1 do begin
if Pointer(FTable.Fields[fieldIdx].Tag)=aImage then begin
aField := FTable.Fields[fieldIdx];
if not (FTable.State in [dsInsert, dsEdit]) then
FTable.Edit;
TGraphicField(aField).Clear;
ViewActiveBlobField;
Exit;
end;
end;
end;
end;
{--------}
procedure TdlgTable.btnClearGenericClick(Sender: TObject);
var
fieldIdx,
controlIdx : Integer;
aMemo : TMemo;
aField : TField;
begin
{ find memo control }
for controlIdx := 0 to TButton(Sender).Parent.ControlCount-1 do
if TButton(Sender).Parent.Controls[controlIdx] IS TMemo then begin
aMemo := TMemo(TButton(Sender).Parent.Controls[controlIdx]);
{ find correct field }
for fieldIdx := 0 to FTable.Dictionary.FieldCount-1 do begin
if Pointer(FTable.Fields[fieldIdx].Tag)=aMemo then begin
aField := FTable.Fields[fieldIdx];
if not (FTable.State in [dsInsert, dsEdit]) then
FTable.Edit;
aField.Clear;
ViewActiveBlobField;
Exit;
end;
end;
end;
end;
procedure TdlgTable.meByteArrayKeyPress(Sender: TObject; var Key: Char);
begin
if not (Key IN [#8, #9, #27, '0'..'9', 'A'..'F', 'a'..'f']) then
Key := #0
else
BAKeyPressDetected := True;
end;
procedure TdlgTable.mnuTablePrintPreviewClick(Sender: TObject);
var
Filter,
DatabaseName,
IndexName : Array[0..1024] of Char;
i : Integer;
RangeStart,
RangeEnd : TRangeFieldValues;
begin
StrPCopy(DatabaseName, FDatabaseName);
if FTable.Filtered then begin
StrPCopy(Filter, FTable.Filter);
end
else
StrCopy(Filter, '');
StrPCopy(IndexName, FTable.IndexName);
{ initialize }
for i := 0 to ffcl_MaxIndexFlds-1 do begin
RangeStart[i] := NULL;
RangeEnd[i] := NULL;
end;
if InRange then begin
FTable.EditRangeStart;
for i := 0 to FTable.IndexFieldCount-1 do
RangeStart[i] := FTable.IndexFields[i].Value;
FTable.Cancel;
FTable.EditRangeEnd;
for i := 0 to FTable.IndexFieldCount-1 do
RangeEnd[i] := FTable.IndexFields[i].Value;
FTable.Cancel;
end;
SingleTableReport(FProtocol,
FServerName,
FUserName,
FPassword,
DatabaseName,
FTableName,
Filter,
IndexName,
RangeStart,
RangeEnd);
end;
procedure TdlgTable.mnuTableDesignReportClick(Sender: TObject);
var
DatabaseName : Array[0..1024] of Char;
begin
StrPCopy(DatabaseName, FDatabaseName);
DesignReport(FProtocol,
FServerName,
FUserName,
FPassword,
DatabaseName);
end;
{ magic resize numbers: 100 = width of buttons + 8 pixels of space on each side }
procedure TdlgTable.tsMemoTemplateResize(Sender: TObject);
var
controlIdx : Integer;
begin
for controlIdx := 0 to TTabSheet(Sender).ControlCount-1 do
if TTabSheet(Sender).Controls[controlIdx] IS TdbMemo then begin
TdbMemo(TTabSheet(Sender).Controls[controlIdx]).SetBounds(0, 0, TTabSheet(Sender).Width-116, TTabSheet(Sender).Height);
end
else
if TTabSheet(Sender).Controls[controlIdx] IS TButton then begin
TButton(TTabSheet(Sender).Controls[controlIdx]).Left := TTabSheet(Sender).Width-108;
end
else
if TTabSheet(Sender).Controls[controlIdx] IS TCheckBox then begin
TCheckBox(TTabSheet(Sender).Controls[controlIdx]).Left := TTabSheet(Sender).Width-108;
end;
end;
procedure TdlgTable.tsGraphicTemplateResize(Sender: TObject);
var
controlIdx : Integer;
begin
for controlIdx := 0 to TTabSheet(Sender).ControlCount-1 do
if TTabSheet(Sender).Controls[controlIdx] IS TImage then begin
TImage(TTabSheet(Sender).Controls[controlIdx]).SetBounds(0, 0, TTabSheet(Sender).Width-116, TTabSheet(Sender).Height);
end
else
if TTabSheet(Sender).Controls[controlIdx] IS TButton then begin
TButton(TTabSheet(Sender).Controls[controlIdx]).Left := TTabSheet(Sender).Width-108;
end
else
if TTabSheet(Sender).Controls[controlIdx] IS TCheckBox then begin
TCheckBox(TTabSheet(Sender).Controls[controlIdx]).Left := TTabSheet(Sender).Width-108;
end;
end;
procedure TdlgTable.tsGenericBlobTemplateResize(Sender: TObject);
var
controlIdx : Integer;
begin
for controlIdx := 0 to TTabSheet(Sender).ControlCount-1 do
if TTabSheet(Sender).Controls[controlIdx] IS TMemo then begin
TMemo(TTabSheet(Sender).Controls[controlIdx]).SetBounds(0, 0, TTabSheet(Sender).Width-116, TTabSheet(Sender).Height);
end
else
if TTabSheet(Sender).Controls[controlIdx] IS TButton then begin
TButton(TTabSheet(Sender).Controls[controlIdx]).Left := TTabSheet(Sender).Width-108;
end;
end;
procedure TdlgTable.tsByteArrayTemplateResize(Sender: TObject);
var
controlIdx : Integer;
begin
for controlIdx := 0 to TTabSheet(Sender).ControlCount-1 do
if TTabSheet(Sender).Controls[controlIdx] IS TMaskEdit then begin
TMaskEdit(TTabSheet(Sender).Controls[controlIdx]).Width := TTabSheet(Sender).Width-2*TMaskEdit(TTabSheet(Sender).Controls[controlIdx]).Left;
end
else
if TTabSheet(Sender).Controls[controlIdx] IS TLabel then begin
TLabel(TTabSheet(Sender).Controls[controlIdx]).Width := TTabSheet(Sender).Width-2*TLabel(TTabSheet(Sender).Controls[controlIdx]).Left;
end
else
{ this button is 75 pixels wide }
if TTabSheet(Sender).Controls[controlIdx] IS TButton then begin
if TButton(TTabSheet(Sender).Controls[controlIdx]).Caption='Clear' then
TButton(TTabSheet(Sender).Controls[controlIdx]).Left := TTabSheet(Sender).Width-83;
end;
end;
procedure TdlgTable.btnSetClearRangeClick(Sender: TObject);
var
NeedEdit : Boolean;
FieldIdx : Integer;
begin
if not InRange then begin
{ check wether we have a useable range (not all NULL) }
NeedEdit := True;
for FieldIdx := Low(FRangeValues.Field) to FTable.IndexFieldCount do
if (not FRangeValues.Field[FieldIdx].StartNull) or
(not FRangeValues.Field[FieldIdx].EndNull) then begin
NeedEdit := False;
Break;
end;
if NeedEdit then
btnEditRangeClick(Self)
else
SetRange;
end
else begin
btnSetClearRange.Caption := 'Set &Range';
FTable.CancelRange;
InRange := False;
UpdateDisplay;
end;
end;
procedure TdlgTable.btnEditRangeClick(Sender: TObject);
var
BaseSection : string;
Index : Integer;
begin
if SetRangeDlg(FTable, FRangeValues)=mrOK then begin
SetRange;
GenerateRangeDisplayStrings;
BaseSection := ClassName + '.' + Self.Caption;
for Index := Low(FRangeValues.Field) to FTable.IndexFieldCount do begin
FFEConfigSaveBoolean(BaseSection, FTable.IndexName+'_RangeStartNull'+IntToStr(Index), FRangeValues.Field[Index].StartNull);
FFEConfigSaveBoolean(BaseSection, FTable.IndexName+'_RangeEndNull'+IntToStr(Index), FRangeValues.Field[Index].EndNull);
FFEConfigSaveString(BaseSection, FTable.IndexName+'_RangeStartValue'+IntToStr(Index), FRangeValues.Field[Index].StartValue);
FFEConfigSaveString(BaseSection, FTable.IndexName+'_RangeEndValue'+IntToStr(Index), FRangeValues.Field[Index].EndValue);
end;
FFEConfigSaveBoolean(BaseSection, FTable.IndexName+'_RangeStartKeyExclusive', FRangeValues.RangeStartKeyExclusive);
FFEConfigSaveBoolean(BaseSection, FTable.IndexName+'_RangeEndKeyExclusive', FRangeValues.RangeEndKeyExclusive);
end;
end;
procedure TdlgTable.mnuViewShowRangeClick(Sender: TObject);
var
FilterFix : Boolean;
begin
{ necessary to get rangepanel to reappear below filterpanel }
FilterFix := pnlFilter.Visible and not pnlRange.Visible;
if FilterFix then
pnlFilter.Visible := False;
mnuViewShowRange.Checked := not mnuViewShowRange.Checked;
pnlRange.Visible := mnuViewShowRange.Checked;
{ remove range and update display etc }
if InRange then
btnSetClearRangeClick(Self);
if FilterFix then
pnlFilter.Visible := True;
end;
procedure TdlgTable.FormResize(Sender: TObject);
begin
btnFindNear.Left := ClientWidth - btnFindNear.Width - 8;
edtFind.Width := btnFindNear.Left - edtFind.Left - 8;
btnSetFilter.Left := ClientWidth - btnSetFilter.Width - 8;
cboFilter.Width := btnSetFilter.Left - cboFilter.Left - 8;
btnSetClearRange.Left := ClientWidth - btnSetClearRange.Width - 8;
laRangeStart.Width := btnSetClearRange.Left - laRangeStart.Left - 8;
btnEditRange.Left := ClientWidth - btnEditRange.Width - 8;
laRangeEnd.Width := btnEditRange.Left - laRangeEnd.Left - 8;
end;
procedure TdlgTable.GenerateRangeDisplayStrings;
var
HighestNonNullIdx,
FieldIdx : Integer;
FirstField : Boolean;
begin
HighestNonNullIdx := FTable.IndexFieldCount;
while (HighestNonNullIdx>1) and
FRangeValues.Field[HighestNonNullIdx].StartNull and
FRangeValues.Field[HighestNonNullIdx].EndNull do
Dec(HighestNonNullIdx);
laRangeStart.Caption := '[';
FirstField := True;
for FieldIdx := Low(FRangeValues.Field) to HighestNonNullIdx do begin
if not FirstField then laRangeStart.Caption := laRangeStart.Caption + ', ';
if FRangeValues.Field[FieldIdx].StartNull then
laRangeStart.Caption := laRangeStart.Caption + 'NULL'
else
if FRangeValues.Field[FieldIdx].StartValue<>'' then
laRangeStart.Caption := laRangeStart.Caption + FRangeValues.Field[FieldIdx].StartValue
else
laRangeStart.Caption := laRangeStart.Caption + '''''';
FirstField := False;
end;
laRangeStart.Caption := laRangeStart.Caption + ']';
if FRangeValues.RangeStartKeyExclusive then
laRangeStart.Caption := laRangeStart.Caption + ' - [KeyExclusive]';
laRangeEnd.Caption := '[';
FirstField := True;
for FieldIdx := Low(FRangeValues.Field) to HighestNonNullIdx do begin
if not FirstField then laRangeEnd.Caption := laRangeEnd.Caption + ', ';
if FRangeValues.Field[FieldIdx].EndNull then
laRangeEnd.Caption := laRangeEnd.Caption + 'NULL'
else
if FRangeValues.Field[FieldIdx].EndValue<>'' then
laRangeEnd.Caption := laRangeEnd.Caption + FRangeValues.Field[FieldIdx].EndValue
else
laRangeEnd.Caption := laRangeEnd.Caption + '''''';
FirstField := False;
end;
laRangeEnd.Caption := laRangeEnd.Caption + ']';
if FRangeValues.RangeEndKeyExclusive then
laRangeEnd.Caption := laRangeEnd.Caption + ' - [KeyExclusive]';
end;
procedure TdlgTable.SetRange;
var
HighestNonNullIdx,
FieldIdx : Integer;
begin
HighestNonNullIdx := 0;
FTable.SetRangeStart;
FTable.KeyExclusive := FRangeValues.RangeStartKeyExclusive;
for FieldIdx := Low(FRangeValues.Field) to FTable.IndexFieldCount do begin
if not FRangeValues.Field[FieldIdx].StartNull then begin
FTable.IndexFields[FieldIdx-1].AsString := FRangeValues.Field[FieldIdx].StartValue;
HighestNonNullIdx := FFMaxL(HighestNonNullIdx, FieldIdx);
end
else
if not FRangeValues.Field[FieldIdx].EndNull then
FTable.IndexFields[FieldIdx-1].Value := NULL;
end;
FTable.SetRangeEnd;
FTable.KeyExclusive := FRangeValues.RangeEndKeyExclusive;
for FieldIdx := Low(FRangeValues.Field) to FTable.IndexFieldCount do begin
if not FRangeValues.Field[FieldIdx].EndNull then begin
FTable.IndexFields[FieldIdx-1].AsString := FRangeValues.Field[FieldIdx].EndValue;
HighestNonNullIdx := FFMaxL(HighestNonNullIdx, FieldIdx);
end
else
if not FRangeValues.Field[FieldIdx].StartNull then
FTable.IndexFields[FieldIdx-1].Value := NULL;
end;
FTable.KeyFieldCount := HighestNonNullIdx;
FTable.ApplyRange;
InRange := True;
btnSetClearRange.Caption := 'Clear &Range';
UpdateDisplay;
end;
procedure TdlgTable.meByteArrayChange(Sender: TObject);
var
ByteArrayBuffer : Pointer;
fieldIdx,
controlIdx : Integer;
aEdit : TMaskEdit;
aField : TField;
procedure HexStringToByteArray(ByteArray : Pointer; ArrayLength : Integer; S : String);
var
idx : Integer;
BArr : PffByteArray absolute ByteArray;
begin
for idx := 0 to ArrayLength-1 do begin
if Odd(Length(S)) then
S := S + '0';
if Length(S)>1 then begin
try
BArr[idx] := StrToInt('$'+Copy(S, 1, 2));
except
on EConvertError do begin
MessageDlg('Invalid character encountered - use only hex digits 0..9, A..F!', mtError, [mbOK], 0);
Abort;
end;
end;
Delete(S, 1, 2);
end
else begin
BArr[idx] := 0;
BArr[idx] := 0;
end;
end;
end;
begin
if not BAKeyPressDetected then
Exit
else
BAKeyPressDetected := False;
FTable.Edit;
{ find edit control }
for controlIdx := 0 to TButton(Sender).Parent.ControlCount-1 do
if TButton(Sender).Parent.Controls[controlIdx] IS TMaskEdit then begin
aEdit := TMaskEdit(TButton(Sender).Parent.Controls[controlIdx]);
if aEdit.Text='' then
Exit;
{ find correct field }
for fieldIdx := 0 to FTable.Dictionary.FieldCount-1 do begin
if Pointer(FTable.Fields[fieldIdx].Tag)=aEdit then begin
aField := FTable.Fields[fieldIdx];
if not (FTable.State in [dsInsert, dsEdit]) then
FTable.Edit;
GetMem(ByteArrayBuffer, aField.Size);
try
HexStringToByteArray(ByteArrayBuffer, aField.Size, aEdit.Text);
aField.SetData(ByteArrayBuffer);
finally
FreeMem(ByteArrayBuffer);
end;
Exit;
end;
end;
end;
end;
procedure TdlgTable.cbWordwrapClick(Sender: TObject);
var
i : Integer;
begin
for i := 0 to TCheckBox(Sender).Parent.ControlCount-1 do
if TCheckBox(Sender).Parent.Controls[i] IS TdbMemo then begin
with TdbMemo(TCheckBox(Sender).Parent.Controls[i]) do begin
WordWrap := TCheckBox(Sender).Checked;
if WordWrap then
ScrollBars := ssVertical
else
ScrollBars := ssBoth;
end;
Exit;
end;
end;
procedure TdlgTable.mnuTableCopyToTableClick(Sender: TObject);
var
ExcludeIndex,
TableIndex: LongInt;
CopyBlobs : Boolean;
SaveTimeout : Integer;
begin
ExcludeIndex := TableItem.Database.IndexOf(TableItem);
if ShowCopyTableDlg(TableItem.Database, ExcludeIndex, FTable,
TableIndex, CopyBlobs, FTableItem) = mrOK then begin {!!.11}
with TableItem.Database.Tables[TableIndex] do begin
Screen.Cursor := crHourGlass;
{ the copy operation is used in the context of the table
that's being copied to. Use the timeout of the active
table, otherwise the user has no way of setting timeout. }
SaveTimeout := Table.Timeout;
Table.Timeout := FTable.Timeout;
try
Update;
CopyRecords(FTable, CopyBlobs);
finally
Screen.Cursor := crDefault;
Table.Timeout := SaveTimeout;
{ force the second table to close if it wasn't open before }
FSession.CloseInactiveTables; {!!.11}
end;
end;
end;
end;
procedure TdlgTable.mnuTableDeleteRecordsClick(Sender: TObject);
begin
if MessageDlg('Delete all records matching the current filter and range - are you sure?', mtConfirmation, [mbYes,mbNo], 0)= mrYes then begin
Screen.Cursor := crHourGlass;
try
Update;
FTable.DeleteRecords;
finally
Screen.Cursor := crDefault;
end;
end;
end;
{End !!.07}
procedure TdlgTable.UpdateDefaultTimeout;
begin
FClient.TimeOut := Config.DefaultTimeout; {!!.11}
end;
end.