{*******************************************************} { } { Responsive Software http://www.responsive.co.nz } { } { Copyright (c) 2003-2006 Responsive Software Limited } { } {*******************************************************} unit Main; interface uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, ExtCtrls, Menus, ComCtrls, Base, BaseFrameUnit, Globals, Reports, ImgList, Entries, BalanceSheet, Ledger, Accounts, IncomeStatement, Cashbooks, Graph, POS, Items, SalesReportFrameUnit, Sales, Documents; const // no of frames on main form NoOfFramesOnMainForm = 13; type TMainForm = class(TBaseForm) MainMenu1: TMainMenu; Maintain1: TMenuItem; Help1: TMenuItem; TreeView: TTreeView; Help2: TMenuItem; About1: TMenuItem; File1: TMenuItem; Exit1: TMenuItem; Hidden1: TMenuItem; IdGenerator1: TMenuItem; WorkstationConfiguration1: TMenuItem; GlobalConfiguration1: TMenuItem; GenerateException1: TMenuItem; ExecuteTest1: TMenuItem; Configure1: TMenuItem; N1: TMenuItem; N2: TMenuItem; Register1: TMenuItem; N5: TMenuItem; EmailDatabase1: TMenuItem; Decompress1: TMenuItem; ReportsFrame: TReportsFrame; ViewQRPFile1: TMenuItem; Companies1: TMenuItem; Accounts1: TMenuItem; Entries1: TMenuItem; LedgerFrame: TLedgerFrame; EntriesFrame: TEntriesFrame; AccountsFrame: TAccountsFrame; ImageList1: TImageList; Notes1: TMenuItem; BalanceSheetFrame: TBalanceSheetFrame; IncomeStatementFrame: TIncomeStatementFrame; CashbooksFrame: TCashbooksFrame; Cashbooks1: TMenuItem; CashbookEntries1: TMenuItem; Workstations1: TMenuItem; GraphFrame: TGraphFrame; ExecuteTest21: TMenuItem; ExecuteTest31: TMenuItem; ExecuteTest41: TMenuItem; PrintListing1: TMenuItem; Users1: TMenuItem; N3: TMenuItem; Items1: TMenuItem; LookupCodes1: TMenuItem; Salespersons1: TMenuItem; PaymentTypes1: TMenuItem; POSFrame: TPOSFrame; ItemsFrame: TItemsFrame; SalesFrame: TSalesFrame; SalesReportFrame: TSalesReportFrame; Sales1: TMenuItem; SaleItems1: TMenuItem; PaymentItems1: TMenuItem; N4: TMenuItem; HTTP1: TMenuItem; Attachments1: TMenuItem; DocumentsFrame: TDocumentsFrame; PurgeLedger1: TMenuItem; FindUnbalancedEntry1: TMenuItem; procedure FormCreate(Sender: TObject); procedure TreeViewChange(Sender: TObject; Node: TTreeNode); procedure Help2Click(Sender: TObject); procedure About1Click(Sender: TObject); procedure Exit1Click(Sender: TObject); procedure IdGenerator1Click(Sender: TObject); procedure FormKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState); procedure FormClose(Sender: TObject; var Action: TCloseAction); procedure WorkstationConfiguration1Click(Sender: TObject); procedure GlobalConfiguration1Click(Sender: TObject); procedure GenerateException1Click(Sender: TObject); procedure ExecuteTest1Click(Sender: TObject); procedure Configure1Click(Sender: TObject); procedure Register1Click(Sender: TObject); procedure EmailDatabase1Click(Sender: TObject); procedure Decompress1Click(Sender: TObject); procedure ViewQRPFile1Click(Sender: TObject); procedure Companies1Click(Sender: TObject); procedure Accounts1Click(Sender: TObject); procedure Entries1Click(Sender: TObject); procedure Notes1Click(Sender: TObject); procedure Cashbooks1Click(Sender: TObject); procedure CashbookEntries1Click(Sender: TObject); procedure Workstations1Click(Sender: TObject); procedure FormCloseQuery(Sender: TObject; var CanClose: Boolean); procedure ExecuteTest21Click(Sender: TObject); procedure ExecuteTest31Click(Sender: TObject); procedure ExecuteTest41Click(Sender: TObject); procedure PrintListing1Click(Sender: TObject); procedure Users1Click(Sender: TObject); procedure Items1Click(Sender: TObject); procedure LookupCodes1Click(Sender: TObject); procedure Salespersons1Click(Sender: TObject); procedure PaymentTypes1Click(Sender: TObject); procedure Sales1Click(Sender: TObject); procedure SaleItems1Click(Sender: TObject); procedure PaymentItems1Click(Sender: TObject); procedure HTTP1Click(Sender: TObject); procedure Attachments1Click(Sender: TObject); procedure PurgeLedger1Click(Sender: TObject); procedure FindUnbalancedEntry1Click(Sender: TObject); private { Private declarations } FrameArray : array[1..NoOfFramesOnMainForm] of TBaseFrame; InitialMemoryAllocated : integer; procedure OnIdle(Sender : TObject; var Done : boolean); procedure OnException(Sender: TObject; E: Exception); public { Public declarations } procedure UpdateCaption; function CanClose : boolean; procedure HandleEscape; procedure HandleCtrlR; procedure HandleF6; procedure SwitchToNoCanCloseFrame; procedure OpenDataAwareComponents; procedure CloseDataAwareComponents; procedure UpdateAllComboBoxes (Full : boolean); function GetFrameIndexFromNodeText (Text : string) : integer; function GetNodeFromNodeText (Text : string) : TTreeNode; procedure DeleteNode (Text : string); procedure SwitchToFrame (NodeText : string); function GetFrame (NodeText : string) : TBaseFrame; end; const // this array contains node texts mapped to the frame indexes // to which they correspond // the text in this array must match the text of the nodes // in the tree view control // note also that these texts may be referenced elsewhere // at various places in the code NodeTexts : array[1..NoOfFramesOnMainForm] of string = ( 'Ledger', 'Entries', 'Accounts', 'Cashbooks', 'POS', 'Items', 'Sales', 'Reports', 'Sales ', 'Balance', 'Income', 'Graph', 'Documents' ); var MainForm: TMainForm; implementation uses GeneralUtilities, Utilities, DatabaseObjects, DatabaseManager, Config, Register, Splash, Progress, CommunicationsManager, FTP, ServerTest; {$R *.dfm} procedure TMainForm.FormCreate(Sender: TObject); var i : integer; begin // set the name of the OnIdle event handler ie. the // procedure which gets called when nothing else is happening Application.OnIdle := OnIdle; // set the name of the OnException event handler Application.OnException := OnException; // set up easier reference to frames FrameArray[1] := LedgerFrame; FrameArray[2] := EntriesFrame; FrameArray[3] := AccountsFrame; FrameArray[4] := CashbooksFrame; FrameArray[5] := POSFrame; FrameArray[6] := ItemsFrame; FrameArray[7] := SalesFrame; FrameArray[8] := ReportsFrame; FrameArray[9] := SalesReportFrame; FrameArray[10] := BalanceSheetFrame; FrameArray[11] := IncomeStatementFrame; FrameArray[12] := GraphFrame; FrameArray[13] := DocumentsFrame; if not GlobalConfiguration.Accounts then begin FrameArray[1] := nil; LedgerFrame.Visible := false; FrameArray[2] := nil; EntriesFrame.Visible := false; FrameArray[3] := nil; AccountsFrame.Visible := false; FrameArray[4] := nil; CashbooksFrame.Visible := false; FrameArray[10] := nil; BalanceSheetFrame.Visible := false; FrameArray[11] := nil; IncomeStatementFrame.Visible := false; FrameArray[12] := nil; GraphFrame.Visible := false; end; if not GlobalConfiguration.POS then begin FrameArray[5] := nil; POSFrame.Visible := false; FrameArray[6] := nil; ItemsFrame.Visible := false; FrameArray[7] := nil; SalesFrame.Visible := false; FrameArray[9] := nil; SalesReportFrame.Visible := false; end; if not GlobalConfiguration.Documents then begin FrameArray[13] := nil; DocumentsFrame.Visible := false; end; LogMsgInDevMode('Before calling frame setup procedures'); // call setup methods for frames for i := Low(FrameArray) to High(FrameArray) do if FrameArray[i] <> nil then begin LogMsgInDevMode('Before ' + FrameArray[i].Name + '.Setup'); FrameArray[i].Setup; end; LogMsgInDevMode('After calling frame setup procedures'); // hide things which are not relevant for mode or registration if not DevelopmentMode then Hidden1.Visible := false; if ClientMode then begin EmailDatabase1.Visible := false; Register1.Visible := false; Workstations1.Visible := false; Users1.Visible := false; if not User.Administrator then Maintain1.Visible := false; end; if StandardMode then begin Users1.Visible := false; HTTP1.Visible := false; end; // include this line if maintenance menu is not to be shown // Maintain1.Visible := false; // fully expand tree view TreeView.FullExpand; if not GlobalConfiguration.Accounts then begin Companies1.Visible := false; Accounts1.Visible := false; Cashbooks1.Visible := false; PurgeLedger1.Visible := false; N3.Visible := false; DeleteNode('Ledger'); DeleteNode('Balance'); DeleteNode('Income'); DeleteNode('Graph'); end; if not GlobalConfiguration.POS then begin Items1.Visible := false; LookupCodes1.Visible := false; Salespersons1.Visible := false; PaymentTypes1.Visible := false; N3.Visible := false; DeleteNode('POS'); DeleteNode('Sales '); end; if not GlobalConfiguration.Documents then begin DeleteNode('Documents'); end; if not AllowPurgeLedger then PurgeLedger1.Visible := false; end; // process unhandled exceptions procedure TMainForm.OnException(Sender: TObject; E: Exception); begin MessageLog.Log(E.Message); Application.ShowException(E); end; // perform processing during idle time procedure TMainForm.OnIdle(Sender : TObject; var Done : boolean); begin if SplashForm.Visible and Visible then begin SplashForm.Hide; if WorkstationConfiguration.MaximiseOnStart then WindowState := wsMaximized; end; if InitialMemoryAllocated = 0 then begin LogMsgInDevMode('First call to OnIdle handler'); InitialMemoryAllocated := MemoryAllocated; end; UpdateCaption; CommunicationsManager.ProcessReceivedData; end; // update the caption if it has changed // also show memory allocated if under development procedure TMainForm.UpdateCaption; var OldCaption, NewCaption : string; begin OldCaption := Caption; NewCaption := ProgramName; if ModeString <> '' then NewCaption := NewCaption + ' ' + ModeString; if WorkstationConfiguration.CompanyId <> 0 then NewCaption := NewCaption + ' - ' + CompanyName(WorkstationConfiguration.CompanyId) + ' (' + CompanyAbbreviation(WorkstationConfiguration.CompanyId) + ')'; if DevelopmentMode then begin NewCaption := NewCaption + ' (Mem = ' + IntToStr(MemoryAllocated - InitialMemoryAllocated) + ')'; if Communicator <> nil then NewCaption := NewCaption + ' (Com = ' + Communicator.StatusString + ')'; end; if NewCaption <> OldCaption then Caption := NewCaption; end; procedure TMainForm.HandleEscape; var i : integer; begin // allow visible frame to handle escape key for i := Low(FrameArray) to High(FrameArray) do if FrameArray[i] <> nil then begin if FrameArray[i].Visible then begin FrameArray[i].HandleEscape; break; end; end; end; procedure TMainForm.HandleCtrlR; var i : integer; begin // allow visible frame to handle escape key for i := Low(FrameArray) to High(FrameArray) do if FrameArray[i] <> nil then begin if FrameArray[i].Visible then begin FrameArray[i].HandleCtrlR; break; end; end; end; procedure TMainForm.HandleF6; var i : integer; begin // allow visible frame to handle escape key for i := Low(FrameArray) to High(FrameArray) do if FrameArray[i] <> nil then begin if FrameArray[i].Visible then begin FrameArray[i].HandleF6; break; end; end; end; procedure TMainForm.OpenDataAwareComponents; var i : integer; begin // tell each frame to open data aware components for i := Low(FrameArray) to High(FrameArray) do if FrameArray[i] <> nil then FrameArray[i].OpenDataAwareComponents; end; procedure TMainForm.CloseDataAwareComponents; var i : integer; begin // tell each frame to close data aware components for i := Low(FrameArray) to High(FrameArray) do if FrameArray[i] <> nil then FrameArray[i].CloseDataAwareComponents; end; procedure TMainForm.UpdateAllComboBoxes (Full : boolean); var i : integer; begin // update combo boxes on each frame for i := Low(FrameArray) to High(FrameArray) do if FrameArray[i] <> nil then FrameArray[i].UpdateComboBoxes(Full); end; function TMainForm.CanClose : boolean; var i : integer; ReturnValue : boolean; begin ReturnValue := true; // check all frames to see if we can close // and quit application for i := Low(FrameArray) to High(FrameArray) do if FrameArray[i] <> nil then begin if not FrameArray[i].CanClose then begin ReturnValue := false; break; end; end; Result := ReturnValue; end; procedure TMainForm.SwitchToNoCanCloseFrame; var i : integer; TreeNode : TTreeNode; Switched : boolean; begin Switched := false; for i := Low(FrameArray) to High(FrameArray) do if FrameArray[i] <> nil then begin if (not Switched) and (not FrameArray[i].CanClose) then begin FrameArray[i].Visible := true; TreeNode := GetNodeFromNodeText(NodeTexts[i]); if TreeNode <> nil then TreeView.Selected := TreeNode; Switched := true; end else FrameArray[i].Visible := false; end; end; function TMainForm.GetFrameIndexFromNodeText (Text : string) : integer; var i : integer; begin Result := 0; for i := Low(NodeTexts) to High(NodeTexts) do if NodeTexts[i] = Text then begin Result := i; Exit; end; end; function TMainForm.GetNodeFromNodeText (Text : string) : TTreeNode; var i : integer; begin Result := nil; for i := 0 to TreeView.Items.Count - 1 do if TreeView.Items[i].Text = Text then begin Result := TreeView.Items[i]; Exit; end; end; procedure TMainForm.DeleteNode (Text : string); var TreeNode : TTreeNode; begin TreeNode := GetNodeFromNodeText(Text); if TreeNode <> nil then TreeNode.Delete; end; procedure TMainForm.SwitchToFrame (NodeText : string); var i : integer; TreeNode : TTreeNode; Switched : boolean; begin Switched := false; for i := Low(FrameArray) to High(FrameArray) do if FrameArray[i] <> nil then begin if (not Switched) and (NodeTexts[i] = NodeText) then begin FrameArray[i].Visible := true; TreeNode := GetNodeFromNodeText(NodeTexts[i]); if TreeNode <> nil then TreeView.Selected := TreeNode; Switched := true; end else FrameArray[i].Visible := false; end; end; function TMainForm.GetFrame (NodeText : string) : TBaseFrame; var i : integer; begin Result := nil; for i := Low(FrameArray) to High(FrameArray) do if NodeTexts[i] = NodeText then begin Result := FrameArray[i]; Exit; end; end; procedure TMainForm.FormCloseQuery(Sender: TObject; var CanClose: Boolean); begin if ClientMode and (not DevelopmentMode) and (MessageDlg('Are you sure you wish to quit?', mtConfirmation, [mbYes,mbNo], 0) = mrNo) then CanClose := false else begin FTPForm.DestroyNMFTP; CanClose := true; end; end; procedure TMainForm.TreeViewChange(Sender: TObject; Node: TTreeNode); var FrameIndex : integer; i : integer; begin FrameIndex := GetFrameIndexFromNodeText(Node.Text); for i := Low(FrameArray) to High(FrameArray) do begin if FrameArray[i] <> nil then begin if i = FrameIndex then FrameArray[i].Visible := true else FrameArray[i].Visible := false; end; end; end; procedure TMainForm.Help2Click(Sender: TObject); begin MessageDlg(HelpText,mtInformation,[mbOk],0); end; procedure TMainForm.About1Click(Sender: TObject); var IPAddressesStr : string; ExpiryStr : string; begin CombineStrings(IPAddresses,IPAddressesStr,','); if GlobalConfiguration.Unlimited then ExpiryStr := '' else ExpiryStr := Chr(VK_RETURN) + 'Software expires on ' + FormatDateTime('d mmmm yyyy',GlobalConfiguration.ExpiryDate); if ClientMode then MessageDlg('Program: ' + Application.Title + ' ' + ModeString + Chr(VK_RETURN) + 'Version: ' + ProgramVersion + Chr(VK_RETURN) + 'User: ' + ClientUserName + Chr(VK_RETURN) + 'Computer: ' + ComputerName + Chr(VK_RETURN) + 'IP Address(es): ' + IPAddressesStr + Chr(VK_RETURN) + 'Server: ' + ServerIPAddress + Chr(VK_RETURN) + 'Port: ' + IntToStr(ServerPortNumber) + Chr(VK_RETURN) + Chr(VK_RETURN) + 'Copyright (c) 2000-' + CurrentYearStr + ' ' + DevelopmentCompanyName + Chr(VK_RETURN) + ExpiryStr, mtInformation,[mbOk],0) else MessageDlg('Program: ' + Application.Title + ' ' + ModeString + Chr(VK_RETURN) + 'Version: ' + ProgramVersion + Chr(VK_RETURN) + 'User: ' + Globals.UserName + Chr(VK_RETURN) + 'Computer: ' + ComputerName + Chr(VK_RETURN) + 'Database Name: ' + BDEDatabaseName + Chr(VK_RETURN) + 'Database Directory: ' + DatabaseDirectory + Chr(VK_RETURN) + 'IP Address(es): ' + IPAddressesStr + Chr(VK_RETURN) + 'Port: ' + IntToStr(GlobalConfiguration.PortNumber) + Chr(VK_RETURN) + Chr(VK_RETURN) + 'Copyright (c) 2000-' + CurrentYearStr + ' ' + DevelopmentCompanyName + Chr(VK_RETURN) + ExpiryStr, mtInformation,[mbOk],0); end; procedure TMainForm.IdGenerator1Click(Sender: TObject); begin Maintain(TIdGenerator,true); end; procedure TMainForm.Exit1Click(Sender: TObject); begin Close; end; procedure TMainForm.FormKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState); begin if Key = VK_ESCAPE then begin // try to quit but if not able to then // pass escape key to visible frame if CanClose then Close else HandleEscape; Key := 0; end else if (Key = Ord('R')) and (ssCtrl in Shift) then begin HandleCtrlR; Key := 0; end else if (Key = VK_F6) then begin HandleF6; Key := 0; end; end; procedure TMainForm.FormClose(Sender: TObject; var Action: TCloseAction); begin if not CanClose then begin SwitchToNoCanCloseFrame; MessageDlg('Unable to exit while edit is in progress', mtInformation,[mbOk],0); Action := caNone; end else MessageLog.Log('Memory ' + IntToStr(MemoryAllocated - InitialMemoryAllocated)); end; procedure TMainForm.WorkstationConfiguration1Click(Sender: TObject); begin Maintain(TWorkstationConfiguration,false); // don't send workstation message as other workstations don't need to know // if local configuration has changed LoadWorkstationConfiguration; end; procedure TMainForm.GlobalConfiguration1Click(Sender: TObject); begin Maintain(TGlobalConfiguration,false); // send message to all workstations that global configuration has changed LoadGlobalConfiguration; UpdateGlobalConfigurationOnLoggedOnWorkstations; end; procedure TMainForm.GenerateException1Click(Sender: TObject); begin raise Exception.Create('This is an exception'); end; procedure TMainForm.Configure1Click(Sender: TObject); begin ConfigForm.Configure; end; procedure TMainForm.Register1Click(Sender: TObject); begin RegisterForm.Register; end; procedure TMainForm.ExecuteTest1Click(Sender: TObject); var Entry : TEntry; begin Entry := TEntry(Find(TEntry)); if Entry <> nil then ShowMessage(IntToStr(Entry.Id)); Entry.Free; end; procedure TMainForm.ExecuteTest21Click(Sender: TObject); begin SendLargeDataToAllWorkstations; end; procedure TMainForm.ExecuteTest31Click(Sender: TObject); {var i : integer; CombinedEntry : TCombinedEntry; Entry : TEntry; Account : TAccount; const NumberOfEntries = 1000000;} begin { ProgressForm.SetCaption('Adding lots of entries'); ProgressForm.Show; // add lots of account entries for i := 0 to NumberOfEntries do begin CombinedEntry := TCombinedEntry.Create; CombinedEntry.Date := Date + i mod 365; // create debit entry Account := TAccount(Globals.Accounts[(i*2) mod Globals.Accounts.Count]); Entry := TEntry.Create; Entry.AccountId := Account.Id; Entry.Description := 'Test Entry ' + IntToStr(i); if Account.Debit then Entry.Amount := 1234567 else Entry.Amount := -1234567; CombinedEntry.Entries.Add(Entry); // create credit entry Account := TAccount(Globals.Accounts[(i*2+1) mod Globals.Accounts.Count]); Entry := TEntry.Create; Entry.AccountId := Account.Id; Entry.Description := 'Test Entry ' + IntToStr(i); if Account.Credit then Entry.Amount := 1234567 else Entry.Amount := -1234567; CombinedEntry.Entries.Add(Entry); CombinedEntry.UpdateDatabase; CombinedEntry.Free; ProgressForm.SetPosition(i * 100 div NumberOfEntries); end; ProgressForm.Hide;} end; procedure TMainForm.EmailDatabase1Click(Sender: TObject); begin SendDatabase; end; procedure TMainForm.Decompress1Click(Sender: TObject); begin DecompressDatabase; end; procedure TMainForm.ViewQRPFile1Click(Sender: TObject); begin ViewQRPFile; end; procedure TMainForm.Companies1Click(Sender: TObject); begin Maintain(TCompany,false); end; procedure TMainForm.Accounts1Click(Sender: TObject); begin MaintainAccounts; EntriesFrame.UpdateComboBoxes(false); AccountsFrame.UpdateComboBoxes(false); AccountsFrame.UpdateDisplay; CashbooksFrame.UpdateComboBoxes(false); CashbooksFrame.UpdateDisplay; BalanceSheetFrame.UpdateDisplay; IncomeStatementFrame.UpdateDisplay; end; procedure TMainForm.Entries1Click(Sender: TObject); begin Maintain(TEntry,false); end; procedure TMainForm.Notes1Click(Sender: TObject); begin Maintain(TNote,false); end; procedure TMainForm.Cashbooks1Click(Sender: TObject); begin Maintain(TCashbook,false); CashbooksFrame.UpdateComboBoxes(false); CashbooksFrame.UpdateDisplay; end; procedure TMainForm.CashbookEntries1Click(Sender: TObject); begin Maintain(TCashbookEntry,false); end; procedure TMainForm.Workstations1Click(Sender: TObject); begin Maintain(TWorkstationConfiguration,false); // don't send workstation message as other workstations don't need to know // if local configuration has changed LoadWorkstationConfiguration; end; procedure TMainForm.ExecuteTest41Click(Sender: TObject); begin if not ClientMode then ShowMessage('Must be running as client to do this test') else if TestServer then ShowMessage('Server test succeeded') else ShowMessage('Server test failed'); end; procedure TMainForm.PrintListing1Click(Sender: TObject); begin TEntry.PrintAllOnListing('ORDER BY Entry."Date" DESC'); end; procedure TMainForm.Users1Click(Sender: TObject); begin Maintain(TUser,false); end; procedure TMainForm.Items1Click(Sender: TObject); begin Maintain(TItem,false); end; procedure TMainForm.LookupCodes1Click(Sender: TObject); begin Maintain(TLookupCode,true); end; procedure TMainForm.Salespersons1Click(Sender: TObject); begin Maintain(TSalesperson,false); end; procedure TMainForm.PaymentTypes1Click(Sender: TObject); begin Maintain(TPaymentType,false); end; procedure TMainForm.Sales1Click(Sender: TObject); begin Maintain(TSale,false); end; procedure TMainForm.SaleItems1Click(Sender: TObject); begin Maintain(TSaleItem,false); end; procedure TMainForm.PaymentItems1Click(Sender: TObject); begin Maintain(TPaymentItem,false); end; procedure TMainForm.HTTP1Click(Sender: TObject); begin OpenWebpage(ServerIPAddress + ':' + IntToStr(GlobalConfiguration.HTTPPortNumber)); end; procedure TMainForm.Attachments1Click(Sender: TObject); begin Maintain(TAttachment,false); end; procedure TMainForm.PurgeLedger1Click(Sender: TObject); var PurgeDate : TDateTime; begin // prompt for date before which to purge data PurgeDate := Date; if not PromptDate(PurgeDate) then Exit; // check that they have a current backup if MessageDlg('Do you have a current backup of the database?', mtConfirmation, [mbYes,mbNo], 0) = mrNo then begin ShowMessage('Please make a backup first.'); Exit; end else ShowMessage('EXCELLENT! Now please read the following prompts carefully to ensure that you do not make a mistake.'); // check that all other users are logged out if MessageDlg('Are all other users logged out?', mtConfirmation, [mbYes,mbNo], 0) = mrNo then begin ShowMessage('Please ensure all other users are logged out first.'); Exit; end; // check that the date is correct if MessageDlg('WARNING: You are about to permanently delete from the database all ledger entries dated on or before ' + FormatDateTime('d mmmm yyyy',PurgeDate) + '.' + Chr(VK_RETURN) + Chr(VK_RETURN) + 'Are you absolutely sure you wish to do this?', mtConfirmation, [mbYes,mbNo], 0) = mrNo then Exit; // final warning if MessageDlg('FINAL WARNING: You are about to permanently delete data from the database.' + Chr(VK_RETURN) + Chr(VK_RETURN) + 'THIS IS YOUR LAST CHANCE TO CHANGE YOUR MIND.' + Chr(VK_RETURN) + Chr(VK_RETURN) + 'Would you like to change your mind?', mtConfirmation, [mbYes,mbNo], 0) = mrYes then Exit; // do purge if MessageDlg('PURGE DATA NOW?', mtConfirmation, [mbYes,mbNo], 0) = mrNo then Exit; Screen.Cursor := crHourGlass; try PurgeDatabase(PurgeDate); finally Screen.Cursor := crDefault; end; end; procedure TMainForm.FindUnbalancedEntry1Click(Sender: TObject); begin FindUnbalancedEntry; end; end.