tvplanit: Add FlexDatastore example (using an Access database) with instructions in readme.

git-svn-id: https://svn.code.sf.net/p/lazarus-ccr/svn@5030 8e941d3f-bd1b-0410-a28a-d453659cc2b4
This commit is contained in:
wp_xxyyzz
2016-07-25 16:55:32 +00:00
parent f12d13a062
commit 9333e53cb4
11 changed files with 2429 additions and 10 deletions

View File

@ -0,0 +1,88 @@
<?xml version="1.0" encoding="UTF-8"?>
<CONFIG>
<ProjectOptions>
<Version Value="9"/>
<PathDelim Value="\"/>
<General>
<SessionStorage Value="InProjectDir"/>
<MainUnit Value="0"/>
<Title Value="project1"/>
<ResourceType Value="res"/>
<UseXPManifest Value="True"/>
</General>
<VersionInfo>
<StringTable ProductVersion=""/>
</VersionInfo>
<BuildModes Count="1">
<Item1 Name="Default" Default="True"/>
</BuildModes>
<PublishOptions>
<Version Value="2"/>
</PublishOptions>
<RunParams>
<local>
<FormatVersion Value="1"/>
</local>
</RunParams>
<RequiredPackages Count="4">
<Item1>
<PackageName Value="SQLDBLaz"/>
</Item1>
<Item2>
<PackageName Value="FCL"/>
</Item2>
<Item3>
<PackageName Value="laz_visualplanit"/>
</Item3>
<Item4>
<PackageName Value="LCL"/>
</Item4>
</RequiredPackages>
<Units Count="2">
<Unit0>
<Filename Value="project1.lpr"/>
<IsPartOfProject Value="True"/>
</Unit0>
<Unit1>
<Filename Value="unit1.pas"/>
<IsPartOfProject Value="True"/>
<ComponentName Value="Form1"/>
<HasResources Value="True"/>
<ResourceBaseClass Value="Form"/>
<UnitName Value="Unit1"/>
</Unit1>
</Units>
</ProjectOptions>
<CompilerOptions>
<Version Value="11"/>
<PathDelim Value="\"/>
<Target>
<Filename Value="project1"/>
</Target>
<SearchPaths>
<IncludeFiles Value="$(ProjOutDir);dbase"/>
<OtherUnitFiles Value="dbase"/>
<UnitOutputDirectory Value="lib\$(TargetCPU)-$(TargetOS)"/>
</SearchPaths>
<Linking>
<Options>
<Win32>
<GraphicApplication Value="True"/>
</Win32>
</Options>
</Linking>
</CompilerOptions>
<Debugging>
<Exceptions Count="3">
<Item1>
<Name Value="EAbort"/>
</Item1>
<Item2>
<Name Value="ECodetoolError"/>
</Item2>
<Item3>
<Name Value="EFOpenError"/>
</Item3>
</Exceptions>
</Debugging>
</CONFIG>

View File

@ -0,0 +1,20 @@
program project1;
{$mode objfpc}{$H+}
uses
{$IFDEF UNIX}{$IFDEF UseCThreads}
cthreads,
{$ENDIF}{$ENDIF}
Interfaces, // this includes the LCL widgetset
Forms, Unit1, laz_visualplanit;
{$R *.res}
begin
RequireDerivedFormResource := True;
Application.Initialize;
Application.CreateForm(TForm1, Form1);
Application.Run;
end.

View File

@ -0,0 +1,104 @@
This demo shows how a TVpFlexDatastore can link to an Access database using
ODBC.
Step-by-step instructions for creating a new application
--------------------------------------------------------
- If a suitable Access database is not available from somewhere else
create an empty Access database containing the VisualPlanit tables and fields.
The easiest way to do this is by means of the CreateAccessDB application in
the folder "tools". Use extension .mdb to create an old Access 97/2000 file,
or use extension .accdb for a new Access 2007+ file.
- Create a new form.
- Add a TVpFlexDatastore, a TVpControlLink and the visual planner components
needed.
- Add an TODBConnection. Add a TSQLTransationSet
- Set these properties of the ODBCConnection:
- "Driver" ---> "Microsoft Access Driver (*.mdb, *.accdb)"
- "Params" ---> Add "DBQ=full/path/to/access/file"
Note: Make sure to use the full path in Params, otherwise the fieldmapper
in one of the next steps will not find the database.
- "Transaction --> instance of the SQLTransaction.
- Add four TSQLQuery components and set these properties
- "Database" ---> instance of the ODBCConnection
- "Options" --> add sqoAutoApplyUpdates, sqoAutoCommit and sqoKeepOpenOnCommit
- "UsePrimaryKeyAsKey" --> false (VERY IMPORTANT FOR ACCESS FILES!)
- Enter these SQL for the queries where <tablename> must be replaced by
Resources, Contacts, Events and Tasks.
SELECT * FROM <tablename>
- For the Resources query add this UpdateSQL:
UPDATE
Resources
SET
Description = :Description,
Notes = :Notes,
ResourceActive = :ResourceActive,
ImageIndex = :ImageIndex
WHERE
ResourceID = :ResourceID
- Similarly, add UpdateSQL instructions for the Events, Contacts, and Tasks tables.
Make sure to include all database fields (except for the AutoInc fields).
See the demo application.
- Add this text to the DeleteSQL property of the Resources SQLDataset
DELETE * FROM Resources
WHERE ResourceID = :ResourceID.
- This is the DeleteSQL needed for the Events dataset:
DELETE * FROM Events
WHERE RecordID = :RecordID
- Repeat accordingly with the Contacts and Rasks datasets.
- Add four TDatasource components. Link each one of them to a TSQLDataset.
- Link the datasource components to the matching Datasources of the
VpFlexDatastore.
- In OnCreate of the form set
VpFlexDatastore.Connected := true
ODBConnection.Connected := true
SQLTransaction.Active := true
- In OnDestroy set
ODBCConnection.Connected := false
- Write an event handler for the datastore's OnSetFilterCriteria. Copy the
code used in the demo. In case of date-filtering it is important to use
the dbf syntax DTOS(dateField).
- Double-click on the VpFlexDatastore in Form1 to open the field mapper.
- Select "Resources" in the combobox. Click a database field in the left listbox
and click its corresponding planner field in the right listbox. Click add to
store this mapping. Repeat with all database fields.
- Or, if all database fields have the same name as the corresponding planner
fields, simply click "Add all" to establish a mapping for all equally names
fields.
- Note: the sample database does not support the User-defined fields of the
planner. Therefore, these fields will be left without a matching database
field.
- Repeat with the Events, Contacts and Tasks tables.
- Close the field mapper.
- Done.

View File

@ -0,0 +1,82 @@
<?xml version="1.0" encoding="UTF-8"?>
<CONFIG>
<ProjectOptions>
<Version Value="9"/>
<PathDelim Value="\"/>
<General>
<SessionStorage Value="InProjectDir"/>
<MainUnit Value="0"/>
<Title Value="CreateAccessDB"/>
<ResourceType Value="res"/>
<UseXPManifest Value="True"/>
<Icon Value="0"/>
</General>
<VersionInfo>
<StringTable ProductVersion=""/>
</VersionInfo>
<BuildModes Count="1">
<Item1 Name="Default" Default="True"/>
</BuildModes>
<PublishOptions>
<Version Value="2"/>
</PublishOptions>
<RunParams>
<local>
<FormatVersion Value="1"/>
</local>
</RunParams>
<RequiredPackages Count="2">
<Item1>
<PackageName Value="SQLDBLaz"/>
</Item1>
<Item2>
<PackageName Value="LCL"/>
</Item2>
</RequiredPackages>
<Units Count="2">
<Unit0>
<Filename Value="CreateAccessDB.lpr"/>
<IsPartOfProject Value="True"/>
</Unit0>
<Unit1>
<Filename Value="..\..\..\odbcdatastore\camain.pas"/>
<IsPartOfProject Value="True"/>
<ComponentName Value="Form1"/>
<HasResources Value="True"/>
<ResourceBaseClass Value="Form"/>
<UnitName Value="caMain"/>
</Unit1>
</Units>
</ProjectOptions>
<CompilerOptions>
<Version Value="11"/>
<PathDelim Value="\"/>
<Target>
<Filename Value="CreateAccessDB"/>
</Target>
<SearchPaths>
<IncludeFiles Value="$(ProjOutDir)"/>
<UnitOutputDirectory Value="lib\$(TargetCPU)-$(TargetOS)"/>
</SearchPaths>
<Linking>
<Options>
<Win32>
<GraphicApplication Value="True"/>
</Win32>
</Options>
</Linking>
</CompilerOptions>
<Debugging>
<Exceptions Count="3">
<Item1>
<Name Value="EAbort"/>
</Item1>
<Item2>
<Name Value="ECodetoolError"/>
</Item2>
<Item3>
<Name Value="EFOpenError"/>
</Item3>
</Exceptions>
</Debugging>
</CONFIG>

View File

@ -0,0 +1,21 @@
program CreateAccessDB;
{$mode objfpc}{$H+}
uses
{$IFDEF UNIX}{$IFDEF UseCThreads}
cthreads,
{$ENDIF}{$ENDIF}
Interfaces, // this includes the LCL widgetset
Forms, caMain
{ you can add units after this };
{$R *.res}
begin
RequireDerivedFormResource := True;
Application.Initialize;
Application.CreateForm(TForm1, Form1);
Application.Run;
end.

View File

@ -0,0 +1,104 @@
object Form1: TForm1
Left = 262
Height = 177
Top = 155
Width = 314
Caption = 'Access database creator'
ClientHeight = 177
ClientWidth = 314
LCLVersion = '1.7'
object FileNameEdit: TFileNameEdit
Left = 16
Height = 23
Top = 16
Width = 280
FileName = '.\data.mdb'
Filter = 'Access database files (*.mdb; *.accdb)|*.mdb;*.accdb'
FilterIndex = 0
HideDirectories = False
ButtonWidth = 23
NumGlyphs = 1
MaxLength = 0
TabOrder = 0
Text = '.\data.mdb'
end
object CbCreateVPFields: TCheckBox
Left = 16
Height = 19
Top = 80
Width = 140
Caption = 'Add VisualPlanIt tables'
Checked = True
State = cbChecked
TabOrder = 1
end
object StatusBar1: TStatusBar
Left = 0
Height = 23
Top = 154
Width = 314
Panels = <>
end
object Label1: TLabel
Left = 16
Height = 30
Top = 44
Width = 285
Caption = 'Use extension .mdb for old Access 97/2000 file format,'#13#10'.accdb for new Access 2007+ file format.'
ParentColor = False
end
object Panel1: TPanel
Left = 0
Height = 44
Top = 110
Width = 314
Align = alBottom
Caption = 'Panel1'
ClientHeight = 44
ClientWidth = 314
TabOrder = 3
object BtnCreateDB: TButton
Left = 120
Height = 25
Top = 10
Width = 91
Caption = 'Create DB'
OnClick = BtnCreateDBClick
TabOrder = 0
end
object BtnClose: TButton
Left = 221
Height = 25
Top = 10
Width = 75
Caption = 'Close'
OnClick = BtnCloseClick
TabOrder = 1
end
object Bevel1: TBevel
Left = 9
Height = 3
Top = 1
Width = 296
Align = alTop
BorderSpacing.Left = 8
BorderSpacing.Right = 8
Shape = bsTopLine
end
end
object ODBCConnection1: TODBCConnection
Connected = False
LoginPrompt = False
KeepConnection = False
Transaction = SQLTransaction1
Options = []
left = 104
end
object SQLTransaction1: TSQLTransaction
Active = False
Action = caCommit
Database = ODBCConnection1
Options = []
left = 216
end
end

View File

@ -0,0 +1,307 @@
unit caMain;
{$mode objfpc}{$H+}
interface
uses
Classes, SysUtils, odbcconn, sqldb, FileUtil, Forms, Controls, Graphics,
Dialogs, StdCtrls, EditBtn, ComCtrls, ExtCtrls;
type
{ TForm1 }
TForm1 = class(TForm)
Bevel1: TBevel;
BtnCreateDB: TButton;
BtnClose: TButton;
CbCreateVPFields: TCheckBox;
FileNameEdit: TFileNameEdit;
Label1: TLabel;
ODBCConnection1: TODBCConnection;
Panel1: TPanel;
SQLTransaction1: TSQLTransaction;
StatusBar1: TStatusBar;
procedure BtnCreateDBClick(Sender: TObject);
procedure BtnCloseClick(Sender: TObject);
private
function CreateAccessDatabase(DatabaseFile: string): boolean;
procedure CreateContactsTable;
procedure CreateEventsTable;
procedure CreateResourceTable;
procedure CreateTasksTable;
procedure StatusMsg(const AText: String);
public
{ public declarations }
end;
var
Form1: TForm1;
implementation
{$R *.lfm}
uses
LCLType, LazFileUtils;
Const
ODBC_ADD_DSN = 1;
ODBC_CONFIG_DSN = 2;
ODBC_REMOVE_DSN = 3;
ODBC_ADD_SYS_DSN = 4;
ODBC_CONFIG_SYS_DSN = 5;
ODBC_REMOVE_SYS_DSN = 6;
ODBC_REMOVE_DEFAULT_DSN = 7;
function SQLConfigDataSource(hwndParent: Integer; fRequest: Integer;
lpszDriverString: PChar; lpszAttributes: PChar): Integer; stdcall; external 'odbccp32.dll';
function SQLInstallerError(iError: integer; pfErrorCode: PInteger;
lpszErrorMsg: string; cbErrorMsgMax: integer; pcbErrorMsg: PInteger): integer; stdcall; external 'odbccp32.dll';
{ TForm1 }
procedure TForm1.BtnCreateDBClick(Sender: TObject);
var
fn: String;
begin
if FileNameEdit.FileName = '' then
exit;
fn := ExpandFileNameUTF8(FilenameEdit.FileName);
if FileExistsUTF8(fn) then
DeleteFileUTF8(fn);
// Create empty database file
CreateAccessDatabase(fn);
StatusMsg('Database file created');
if CbCreateVPFields.Checked then begin
//connection
ODBCConnection1.Driver := 'Microsoft Access Driver (*.mdb, *.accdb)';
ODBCConnection1.Params.Add('DBQ=' + fn);
ODBCConnection1.Params.Add('Locale Identifier=1031');
ODBCConnection1.Params.Add('ExtendedAnsiSQL=1');
ODBCConnection1.Params.Add('CHARSET=ansi');
ODBCConnection1.Connected := True;
ODBCConnection1.KeepConnection := True;
//transaction
SQLTransaction1.DataBase := ODBCConnection1;
SQLTransaction1.Action := caCommit;
SQLTransaction1.Active := True;
// Create tables
CreateResourceTable;
CreateContactsTable;
CreateEventsTable;
CreateTasksTable;
SQLTransaction1.Active := false;
ODBCConnection1.Connected := false;
Statusbar1.SimpleText := 'All tables created.';
end;
end;
procedure TForm1.BtnCloseClick(Sender: TObject);
begin
Close;
end;
function TForm1.CreateAccessDatabase(DatabaseFile: string): boolean;
var
dbType: string;
driver: string;
ErrorCode, ResizeErrorMessage: integer;
ErrorMessage: PChar;
retCode: integer;
begin
driver := 'Microsoft Access Driver (*.mdb, *.accdb)';
{ With this driver,
CREATE_DB/CREATE_DBV12 will create an .accdb format database;
CREATE_DBV4 will create an mdb
http://stackoverflow.com/questions/9205633/how-do-i-specify-the-odbc-access-driver-format-when-creating-the-database
}
case Lowercase(ExtractFileExt(DatabaseFile)) of
'', '.', '.mdb':
dbType := 'CREATE_DBV4="' + DatabaseFile + '"';
'.accdb':
dbtype := 'CREATE_DBV12="' + DatabaseFile + '"';
else
raise Exception.CreateFmt('File format "%s" not supported.', [ExtractFileExt(DatabaseFile)]);
end;
// DBPChar := 'CREATE_DBV4="' + DatabaseFile + '"';
retCode := SQLConfigDataSource(Hwnd(nil), ODBC_ADD_DSN, PChar(driver), PChar(dbType));
if retCode <> 0 then
begin
//try alternate driver
driver := 'Microsoft Access Driver (*.mdb)';
dbType := 'CREATE_DB="' + DatabaseFile + '"';
retCode := SQLConfigDataSource(Hwnd(nil), ODBC_ADD_DSN, PChar(driver), PChar(dbType));
end;
if retCode = 0 then
result := true
else
begin
result := false;
ErrorCode := 0;
ResizeErrorMessage := 0;
// todo: verify how the DLL is called - use pointers?; has not been tested.
GetMem(ErrorMessage, 512);
try
SQLInstallerError(1, @ErrorCode, ErrorMessage, SizeOf(ErrorMessage), @ResizeErrorMessage);
finally
FreeMem(ErrorMessage);
end;
raise Exception.CreateFmt('Error creating Access database: %s', [ErrorMessage]);
end;
end;
procedure TForm1.CreateContactsTable;
begin
ODBCConnection1.ExecuteDirect(
'CREATE TABLE Contacts ('+
'RecordID COUNTER, ' +
'ResourceID INTEGER,' +
'FirstName VARCHAR(50) ,'+
'LastName VARCHAR(50) , '+
'Birthdate DATE, '+
'Anniversary DATE, '+
'Title VARCHAR(50) ,'+
'Company VARCHAR(50) ,'+
'Job_Position VARCHAR(30), '+
'Address VARCHAR(100), '+
'City VARCHAR(50), '+
'State VARCHAR(25), '+
'Zip VARCHAR(10), '+
'Country VARCHAR(25), '+
'Notes VARCHAR, '+
'Phone1 VARCHAR(25), '+
'Phone2 VARCHAR(25), '+
'Phone3 VARCHAR(25), '+
'Phone4 VARCHAR(25), '+
'Phone5 VARCHAR(25), '+
'PhoneType1 INTEGER, '+
'PhoneType2 INTEGER, '+
'PhoneType3 INTEGER, '+
'PhoneType4 INTEGER, '+
'PhoneType5 INTEGER, '+
'Category INTEGER, '+
'EMail VARCHAR(100), '+
'Custom1 VARCHAR(100), '+
'Custom2 VARCHAR(100),'+
'Custom3 VARCHAR(100), '+
'Custom4 VARCHAR(100) )'
);
ODBCConnection1.ExecuteDirect(
'CREATE UNIQUE INDEX piCRecordID ON Contacts(RecordID) WITH PRIMARY');
ODBCConnection1.ExecuteDirect(
'CREATE INDEX siCResourceID ON Contacts(ResourceID)');
ODBCConnection1.ExecuteDirect(
'CREATE INDEX siCName ON Contacts(LastName, FirstName)' );
ODBCConnection1.ExecuteDirect(
'CREATE INDEX siCCompany ON Contacts(Company)');
StatusMsg('Table "Contacts" created.');
end;
procedure TForm1.CreateEventsTable;
begin
ODBCConnection1.ExecuteDirect(
'CREATE TABLE Events ('+
'RecordID COUNTER, ' +
'ResourceID INTEGER, '+
'StartTime DATETIME, '+
'EndTime DATETIME, '+
'Description VARCHAR(255), '+
'Location VARCHAR(255), '+
'Notes VARCHAR, ' +
'Category INTEGER, '+
'AllDayEvent LOGICAL, '+
'DingPath VARCHAR(255), '+
'AlarmSet LOGICAL, '+
'AlarmAdvance INTEGER, '+
'AlarmAdvanceType INTEGER, '+
'SnoozeTime DATETIME, '+
'RepeatCode INTEGER, '+
'RepeatRangeEnd DATETIME, '+
'CustomInterval INTEGER)'
);
ODBCConnection1.ExecuteDirect(
'CREATE UNIQUE INDEX piERecordID ON Events(RecordID) WITH PRIMARY');
ODBCConnection1.ExecuteDirect(
'CREATE INDEX EResourceID ON Events(ResourceID)');
ODBCConnection1.ExecuteDirect(
'CREATE INDEX EStartTime ON Events(StartTime)');
ODBCConnection1.ExecuteDirect(
'CREATE INDEX EEndTime ON Events(EndTime)');
StatusMsg('Table "Events" created.');
end;
procedure TForm1.CreateResourceTable;
begin
ODBCConnection1.ExecuteDirect(
'CREATE TABLE Resources ( '+
'ResourceID COUNTER, ' +
'Description VARCHAR(255), '+
'Notes VARCHAR, '+ // 1024 --> -
'ImageIndex INTEGER, '+
'ResourceActive LOGICAL, '+ // BOOL --> LOGICAL
'UserField0 VARCHAR(100), '+
'UserField1 VARCHAR(100), '+
'UserField2 VARCHAR(100), '+
'UserField3 VARCHAR(100), '+
'UserField4 VARCHAR(100), '+
'UserField5 VARCHAR(100), '+
'UserField6 VARCHAR(100), '+
'UserField7 VARCHAR(100), '+
'UserField8 VARCHAR(100), '+
'UserField9 VARCHAR(100) )'
);
ODBCConnection1.ExecuteDirect(
'CREATE UNIQUE INDEX piRResourceID ON Resources(ResourceID) WITH PRIMARY'
);
StatusMsg('Table "Resources" created.');
end;
procedure TForm1.CreateTasksTable;
begin
ODBCConnection1.ExecuteDirect(
'CREATE TABLE Tasks ('+
'RecordID COUNTER, ' +
'ResourceID INTEGER, '+
'Complete LOGICAL, '+
'Description VARCHAR(255), '+
'Details VARCHAR, '+
'CreatedOn DATETIME, '+
'Priority INTEGER, '+
'Category INTEGER, '+
'CompletedOn DATETIME, '+
'DueDate DATETIME)'
);
ODBCConnection1.ExecuteDirect(
'CREATE UNIQUE INDEX piTRecordID ON Tasks(RecordID) WITH PRIMARY'
);
ODBCConnection1.ExecuteDirect(
'CREATE INDEX siTDueDate ON Tasks(DueDate)'
);
ODBCConnection1.ExecuteDirect(
'CREATE INDEX siTCompletedOn ON Tasks(CompletedOn)'
);
StatusMsg('Table "Tasks" created.');
end;
procedure TForm1.StatusMsg(const AText: String);
begin
Statusbar1.SimpleText := AText;
Application.ProcessMessages;
end;
end.

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,202 @@
unit Unit1;
{$mode objfpc}{$H+}
interface
uses
Classes, SysUtils, FileUtil, Forms, Controls, Graphics, Dialogs, ExtCtrls,
StdCtrls, ComCtrls, DBGrids, DbCtrls, VpBaseDS, VpDayView, VpWeekView,
VpTaskList, VpContactGrid, VpMonthView, VpResEditDlg, VpContactButtons, dbf,
db, sqldb, odbcconn, VpData, VpFlxDS;
type
{ TForm1 }
TForm1 = class(TForm)
BtnNewRes: TButton;
BtnEditRes: TButton;
Button1: TButton;
DsAllResources: TDataSource;
DsAllContacts: TDataSource;
DsAllEvents: TDataSource;
DsAllTasks: TDataSource;
Grid: TDBGrid;
DBNavigator: TDBNavigator;
DsTasks: TDataSource;
DsEvents: TDataSource;
DsContacts: TDataSource;
DsResources: TDataSource;
ODBCConnection1: TODBCConnection;
PageControl1: TPageControl;
Panel1: TPanel;
Panel2: TPanel;
Splitter1: TSplitter;
Splitter2: TSplitter;
Splitter3: TSplitter;
QryResources: TSQLQuery;
QryContacts: TSQLQuery;
QryEvents: TSQLQuery;
QryTasks: TSQLQuery;
QryAllResources: TSQLQuery;
QryAllContacts: TSQLQuery;
QryAllEvents: TSQLQuery;
QryAllTasks: TSQLQuery;
SQLTransaction1: TSQLTransaction;
TabControl1: TTabControl;
TabSheet1: TTabSheet;
TabSheet2: TTabSheet;
TabSheet3: TTabSheet;
VpContactButtonBar1: TVpContactButtonBar;
VpContactGrid1: TVpContactGrid;
VpControlLink1: TVpControlLink;
VpDayView1: TVpDayView;
VpFlexDataStore1: TVpFlexDataStore;
VpMonthView1: TVpMonthView;
VpResourceCombo1: TVpResourceCombo;
VpResourceEditDialog1: TVpResourceEditDialog;
VpTaskList1: TVpTaskList;
VpWeekView1: TVpWeekView;
procedure BtnNewResClick(Sender: TObject);
procedure BtnEditResClick(Sender: TObject);
procedure Button1Click(Sender: TObject);
procedure FormCreate(Sender: TObject);
procedure FormDestroy(Sender: TObject);
procedure PageControl1Change(Sender: TObject);
procedure TabControl1Change(Sender: TObject);
procedure VpFlexDataStore1SetFilterCriteria(aTable: TDataset;
aUseDateTime: Boolean; aResourceID: Integer; aStartDateTime,
aEndDateTime: TDateTime);
private
{ private declarations }
public
{ public declarations }
end;
var
Form1: TForm1;
implementation
{$R *.lfm}
uses
dbf_Common, LazFileUtils;
const
DB_DIR = 'data';
{ TForm1 }
// Adds a new resource
procedure TForm1.BtnNewResClick(Sender: TObject);
begin
VpResourceEditDialog1.AddNewResource;
end;
// Edits the currently selected resource
procedure TForm1.BtnEditResClick(Sender: TObject);
begin
// Open the resource editor dialog, everything is done here.
VpResourceEditDialog1.Execute;
end;
procedure TForm1.Button1Click(Sender: TObject);
begin
VpFlexDatastore1.Load;
end;
// Setting up the database connection and the datastore. Preselect a resource
// in the resource combo.
procedure TForm1.FormCreate(Sender: TObject);
begin
try
// Connection
ODBCConnection1.Driver := 'Microsoft Access Driver (*.mdb, *.accdb)';
ODBCConnection1.Params.Add('DBQ=.\data.mdb');
ODBCConnection1.Connected := true;
ODBCConnection1.KeepConnection := true;
// Transaction
SQLTransaction1.DataBase := ODBCConnection1;
// SQLTransaction1.Action := caCommit;
SQLTransaction1.Active := True;
// Connect the datastore. This opens the datasets and loads them into the store.
VpFlexDatastore1.Connected := true;
// Pre-select the first resource item
if VpFlexDatastore1.Resources.Count > 0 then
VpFlexDatastore1.Resource := VpFlexDatastore1.Resources.Items[0];
// Open the additional datasets displayed in the grid
QryAllResources.Open;
QryAllContacts.Open;
QryAllEvents.Open;
QryAllTasks.Open;
PageControl1.ActivePageIndex := 0;
except
on E:Exception do
begin
MessageDlg('ERROR', mtError, [mbOK], 0);
Close;
end;
end;
end;
procedure TForm1.FormDestroy(Sender: TObject);
begin
ODBCConnection1.Connected := false;
end;
procedure TForm1.PageControl1Change(Sender: TObject);
begin
if PageControl1.PageIndex = 2 then TabControl1Change(nil);
end;
procedure TForm1.TabControl1Change(Sender: TObject);
var
i: Integer;
begin
case TabControl1.TabIndex of
0: Grid.Datasource := DsAllResources;
1: Grid.Datasource := DsAllContacts;
2: Grid.Datasource := DsAllEvents;
3: Grid.Datasource := DsAllTasks;
end;
DBNavigator.Datasource := Grid.Datasource;
for i:=0 to Grid.Columns.Count-1 do
Grid.Columns[i].Width := 100;;
end;
{ This event handler is used by the planner to filter those records from the
specified table which belong to the requested resource ID and are within
the requested time interval.
Note that SQLDB uses the DBF syntax for filtering dates, i.e.
- Convert DateTime field values to strings using DTOS()
- Date parameters must be formatted as yyyymmdd and quoted.
See: http://forum.lazarus.freepascal.org/index.php?topic=23077.0 }
procedure TForm1.VpFlexDataStore1SetFilterCriteria(ATable: TDataset;
AUseDateTime: Boolean; AResourceID: Integer; AStartDateTime,
AEndDateTime: TDateTime);
begin
if AUseDateTime then
ATable.Filter := Format(
'(ResourceID = %d) AND (' +
'((DTOS(StartTime) >= "%s") and (DTOS(EndTime) <= "%s")) OR ' +
'((RepeatCode > 0) and (DTOS(RepeatRangeEnd) >= "%s")) )', [
AResourceID,
FormatDateTime('yyyymmdd', AStartDateTime),
FormatDateTime('yyyymmdd', AEndDateTime),
FormatDateTime('yyyymmdd', AStartDateTime)
])
else
ATable.Filter := Format('ResourceID = %d', [AResourceID]);
ATable.Filtered := true;
end;
end.

View File

@ -797,8 +797,8 @@ end;
procedure TVpResource.SetDescription(const Value: string);
begin
if Value <> FDescription then begin
if Assigned (Owner) then begin
if Owner.FindResourceByName (Value) <> nil then
if Assigned(Owner) then begin
if Owner.FindResourceByName(Value) <> nil then
raise EDuplicateResource.Create;
end;

View File

@ -1110,6 +1110,7 @@ procedure TVpFlexDataStore.PostEvents;
var
J: Integer;
Event: TVpEvent;
F: TField;
{FieldName}
FN: string;
begin
@ -1125,6 +1126,7 @@ begin
// FN := GetFieldName(FEventMappings, 'ResourceID');
FN := GetFieldName(FResourceMappings, 'ResourceID');
if (FN <> '') and FResourceDataSrc.DataSet.Locate(FN, Resource.ResourceID, [])
then begin
SetFilterCriteria(FEventsDataSrc.DataSet, False, Resource.ResourceID, 0, 0);
@ -1153,8 +1155,11 @@ begin
try
{ if a particular descendant datastore uses autoincrementing }
{ RecordID fields, then don't overwrite them here. }
if Event.RecordID <> -1 then
EventsTable.FieldByName(FN).AsInteger := Event.RecordID;
if (Event.RecordID <> -1) then begin
F := EventsTable.FieldByName(FN);
if not F.ReadOnly then
F.AsInteger := Event.RecordID;
end;
FN := GetFieldName(FEventMappings, 'StartTime');
if FN <> '' then
@ -1289,6 +1294,7 @@ begin
if Event.RecordID = -1 then
Event.RecordID := EventsTable.FieldByName('RecordID').AsInteger;
*)
Event.Changed := false;
end;
end;
@ -1307,6 +1313,7 @@ procedure TVpFlexDataStore.PostContacts;
var
I: Integer;
Contact: TVpContact;
F: TField;
{FieldName}
FN : string;
begin
@ -1344,8 +1351,11 @@ begin
{ field set the RecordID to -1 by default. If the RecordID is }
{ -1 then this is a new record and we shouldn't overwrite }
{ RecordID with a bogus value }
if Contact.RecordID > -1 then
ContactsTable.FieldByName(FN).AsInteger := Contact.RecordID;
if Contact.RecordID > -1 then begin
F := ContactsTable.FieldByName(FN);
if not F.ReadOnly then
F.AsInteger := Contact.RecordID;
end;
FN := GetFieldName(FContactMappings, 'ResourceID');
if FN <> '' then
@ -1540,6 +1550,7 @@ procedure TVpFlexDataStore.PostTasks;
var
I: Integer;
Task: TVpTask;
F: TField;
{FieldName}
FN: string;
begin
@ -1588,8 +1599,11 @@ begin
{ field set the RecordID to -1 by default. If the RecordID is }
{ -1 then this is a new record and we shouldn't overwrite }
{ RecordID with a bogus value }
if Task.RecordID > -1 then
FieldByName(FN).AsInteger := Task.RecordID;
if Task.RecordID > -1 then begin
F := FieldByName(FN);
if not F.ReadOnly then
F.AsInteger := Task.RecordID;
end;
FN := GetFieldName(FTaskMappings, 'ResourceID');
if FN <> '' then
@ -1699,6 +1713,7 @@ var
Res: TVpResource;
{FieldName}
FN: string;
isactive: Boolean;
begin
Loading := true;
try
@ -1740,7 +1755,7 @@ begin
Append;
try
if Res.ResourceID > -1 then
if (Res.ResourceID > -1) and not FieldByName(FN).ReadOnly then
FieldByName(FN).AsInteger := Res.ResourceID;
FN := GetFieldName(FResourceMappings, 'Description');
@ -1797,7 +1812,9 @@ begin
if FN <> '' then
FieldByName(FN).AsString := Res.UserField9;
isactive := Active;
Post;
isactive := Active;
except
Cancel;
raise EDBPostError.Create;