{**********************************************************************
 ***               TUI - JIMMY EDIT/INPUT VIEWS                     ***
 **********************************************************************}
{$I compflgs}
unit TUIJimmy;

INTERFACE

uses
	drivers, tui, tuiedit, tuilist, views,dialogs,{text}
	objects,
	jimmys;

type
	{extra checks for updating - eg if another jimmy has been stored that
	hooks onto this one, it must send a jimmystoredinfo around the views, and
	each jimmyeditbox checks to see if it should reload the necessary
	pointers}
	{Also does jimmy.storeself on cmStoreJimmy, sent by cmOK, etc buttons.}
	PJimmyEditBox = ^TJimmyEditBox;
	TJimmyEditBox = object(TEditBox)
		JImmy : PJimmy;
		AcceptorView : PView; {if a store button pressed}
		constructor Init(Bounds : TRect; NTitle : STring; NCallingView : PView; NJimmy : PJimmy);
		destructor Done; virtual; {disposes of jimmy}
		procedure HandleEvent(var Event : TEvent); virtual;
	end;

	{-- pass record number in getdata/setdata ---}
	PJimmyINputGroup = ^TJimmyInputGroup;
	TJimmyInputGroup = object(TInputGroup)
		Jimmy : PJimmy;
		srType : word; {jimmy srtype}
		ViewOnly : boolean; {marks if this instantiation was locked (ie disabled)}
		constructor Init(Bounds : TRect; NsrType : word);
		destructor Done; virtual;
		procedure HandleEvent(var Event : TEvent); virtual;
		procedure GetData(var Rec); virtual;
		procedure SetData(Var Rec); virtual;
		function DataSize : word; virtual;
		procedure SetViewOnly(const On : boolean);
		procedure MakeInitParam(var InitParam : TJimmyInitParam); virtual;
		procedure SetForWho; virtual; {*MUST* be overriden}
		function JimmyValid(TestJimmy : PJimmy) : boolean; virtual;
	end;

	{--- pass hktype and srtype, gets from list ---------}
	{getdata/setdata are blanked to outsiders - setdata assumes time
	to load}
	PAttachedJimmyINput = ^TAttachedJimmyInput;
	TAttachedJimmyInput = object(TJimmyInputGroup)
		EditBox : PJimmyEditBox;
		hkType : word; {which hooktype of editbox's jimmy this is attached to}
		htType : word; {which of the forwho's is the editbox's jimmy?  Probably makes hktype redundant}
		constructor Init(Bounds : TRect; NsrType : word; NhkType,NhtType : word; NEditBox : PJimmyEditBox);
		procedure GetData(var Rec); virtual;
		procedure SetData(Var Rec); virtual;
		function DataSize : word; virtual;
		procedure InsertEditFields; virtual;
		procedure MakeInitParam(var InitParam : TJimmyInitParam); virtual;
		procedure SetForWho; virtual; {*MUST* be overriden}
	end;

	{================= INPUT/EDIT VIEWS ========================}
	{used by OK buttons once a jimmy has been edited & stored, in order to
	send messages around the views to check for any updates required}
type
	PJimmyStoredInfo = ^TJimmyStoredInfo;
	TJimmyStoredInfo = record
		OldJimmy : PJimmy; {ie disk jimmy - for unhooking/hooking}
		Jimmy : PJimmy;
	end;

	{for checking if jimmys are being edited/eg if history list already
		being edited}
	PIsJImmyEditedInfo = ^TIsJImmyEditedInfo;
	TIsJimmyEditedInfo = record
		JimmyID : longint;
		lsType : word; {Set to 0 for edit boxes}
	end;

	{Saves Jimmy depending on towho lines etc}
	PJimmyStoreButton = ^TJimmyStoreButton;
	TJimmyStoreButton = object(TOurButton)
		constructor Init(X,Y : byte; ATitle: TTitleStr; ACommand: Word; AFlags: Word; Jimmy : PJimmy);
		procedure Press; virtual; {print}
	end;

	{Does as above but assumes default & OK button for easy insert}
	PJimmyOKButton = ^TJimmyOKButton;
	TJimmyOKButton = object(TJimmyStoreButton)
		constructor Init(const X,Y : byte; const JImmy : PJimmy);
{		procedure Press; virtual;{}
	end;

	{Does a safety check for allowdeletion if it's been stored}
	PJimmyCancelButton = ^TJimmyCancelButton;
	TJimmyCancelButton = object(TOurButton)
		constructor Init(const X,Y : byte; const Jimmy : PJimmy);
		procedure Press; virtual;
	end;


	{Saves and runs Jimmy's print routine}
	PJimmyPrintButton = ^TJimmyPrintButton;
	TJimmyPrintButton = object(TOurButton)

		constructor Init(X,Y : byte; Jimmy : PJimmy);
		procedure Press; virtual; {print}

	end;

IMPLEMENTATION

uses
		kamsetup, {terminal num}
		files,
		tuimsgs,
		help,
		app,
		jimhooks,
		{$IFNDEF SIngleUser} muser, {$ENDIF} {multi user - lock msg}
		minilib,
		tasks,
		 global;




{********************************************************
 ***                                                  ***
 ***                 JIMMY INPUT GROUP                ***
 ***                                                  ***
 ********************************************************}
constructor TJimmyInputGroup.Init;
var InitParam : TJimmyInitParam;
begin
	inherited init(bounds);
	srType := NsrType;
	MakeInitParam(InitParam);
	Jimmy := PJimmy(Create(srType, @InitParam));
	ViewOnly := False;
end;

destructor TJimmyInputGroup.Done;
begin
	if Jimmy<>nil then begin
		if Jimmy^.LockTerminal = TerminalNo then Jimmy^.DecLock;
		dispose(Jimmy, done);
	end;

	inherited Done;
end;

procedure TjimmyInputGroup.HandleEvent;
var StoredJimmy,EditJimmy : PJimmy;
		Control : word;
begin
	inherited HandleEvent(Event);

	if Jimmy<>nil then begin

		{--- edit item specified -----}
		if (Event.What = evKeyBoard) and (Event.KeyCode = kbChange) and
				GetState(sfFocused) and (Jimmy^.RecNo<>-1) then begin

			if not ViewOnly then begin
				{first release the lock for this view, and set this view to viewonly}
				EventMask := EventMask and not evBroadCast;
				Jimmy^.DecLock;
				EventMask := EventMask or evBroadCast;
				SetViewOnly(On);
			end;

			EditJimmy := GetJimmy(Jimmy^.REcNo);

			if Owner^.GetState(sfModal) then
				EditJimmy^.Edit(@Self, @Self) {make modal}
			else
				EditJimmy^.Edit(@Self, nil); {no need to set acceptor link as jimmystored will do updating}

			ClearEvent(Event);
		end;

		{message been sent to locate a view that is editing a jimmy}
{		if (not GetState(sfDisabled)) and
			 (Event.What=evBroadCast) and (Event.Command=cmIsJImmyEdited) and
				(PISJimmyEditedInfo(Event.InfoPtr)^.lsType=0) and
				(PIsJimmyEditedInfo(Event.InfoPtr)^.JimmyID = PJimmy(JImmy)^.REcNo) and
				(PJImmy(JImmy)^.RecNo<>-1) then
					ClearEvent(Event); {this sets infoptr to self}

		if (Event.What = evBroadCast) then begin

			case Event.Command of
			{---- Instruction to store jimmy ------------}
				cmStoreJimmy : if not ViewOnly then begin

					EventMask := EventMask and not evBRoadcast; {disable to prevent picking up messages}

					TInputGroup.GetData(Jimmy^);{get data field by field}

					SetForWho; {if it's new, set the attached jimmy's forwho}

					if Jimmy^.Blank then begin
						Jimmy^.RecNo := -1; {set to -1 so ptr for parent is -1}
					end else begin
						Jimmy^.StoreSelf;
					end;

					EventMask := EventMask or evBRoadcast;  {replace for actual closing}
				end;

				{check to see if the jimmy being stored is relevant to the one this box
				is for}
				cmJimmyStored : begin
					StoredJimmy := PJimmyStoredInfo(Event.InfoPtr)^.Jimmy;

					{The only real way of recognising one is by checking the *memory* pointer
					or the disk one, in case of -1 --> nnnn pointers}
					if (Jimmy^.Recno=StoredJimmy^.RecNo) or (Jimmy=StoredJimmy) then begin
						inherited SetData(StoredJimmy^);
						Redraw;
					end;
				end;

				{jimmy being edited has been locked/unlocked}
				cmJimmyLocked : if PJimmy(Event.InfoPtr)^.RecNo = Jimmy^.RecNo then
						if (PJimmy(Event.InfoPtr)^.GetLock = 0) and ViewOnly then
							SetViewOnly(Off)
						else
							if (PJimmy(Event.InfoPtr)^.GetLock<>0) and not ViewOnly then
								SetViewOnly(On);

			end; {case}

		end; {evbroadcast}

		{closing box, then unlock jimmy if not locked from before}
		if ((Event.What=evBroadCast) or (Event.What=evCommand))
							and ((Event.Command=cmCancel) or (Event.Command=cmClose) or (Event.Command = cmOK)) then begin
			{clear lock - unless this is just a view-only box with the lock set
			by someone else}
			EventMask := EventMask and not evBroadcast;
			Jimmy^.DecLock; {auto store if changed}
			EventMask := EventMask or evBroadCast;
		end;

	end; {jimmy not nil}

end;

procedure TJimmyInputGroup.GetData;
begin
{	inherited GetData(Jimmy^);
{	Jimmy^.StoreSelf; {botch botch botch{}
	longint(Rec) := Jimmy^.RecNo;
end;

procedure TJimmyINputGroup.SetData;
var Result : Word;
	 InitParam : TJimmyInitParam;

begin
	{interesting thing to watch for - in fixit mode, when updating pointers
	on screen (say $IFdef fixit in teditbox.handleevent below), the getdata
	and setdata (used to) force a reget of jimmy, ie disposing of the one that
	was being stored.  Now we get around this by only regetting if the recno
	has changed, which is also quicker and more effective, but it is something
	to watch for in general...}

	if (Jimmy<>nil) then begin
		if Jimmy^.RecNo<>-1 then begin
			EventMask := EventMask and not evBroadCast;
			Jimmy^.DecLock; {auto-store}
			EventMask := EventMask or evBroadCast;
		end;

		dispose(Jimmy, done);
	end;

	Jimmy := GetJimmy(longint(Rec));

	if (Jimmy=nil) then begin
		MakeInitParam(InitParam);
		Jimmy := PJimmy(Create(srType, @InitParam))
	end else begin
		if not JimmyValid(Jimmy) then begin
			dispose(Jimmy, done);
			MakeInitParam(InitParam);
			Jimmy := PJimmy(Create(srType, @InitParam));
		end else begin
			EventMask := EventMask and not evBroadCast;
			Result := Jimmy^.IncLock(laAllowView);
			EventMask := EventMask or evBroadCast;
		end;
	end;

	ReInsertEditFields; {in case of change of jimmy}

	if Result = rsViewOnly then SetViewOnly(On);

	inherited SetData(Jimmy^); {set subviews with data of jimmy}
end;

function TJimmyInputGroup.DataSize;
begin DataSize := 4; end;

function TjimmyInputGroup.JimmyValid(TestJimmy : PJimmy) : boolean;
begin
	JimmyValid := True;
end;


procedure TJimmyINputGroup.SetViewOnly;

	procedure DoDisable(P : PView); far;
	begin P^.SetState(sfDisabled, ViewOnly); end;

begin
	ViewOnly := On;
	ForEach(@DoDisable);
	Redraw;
end;

procedure TJimmyInputGroup.MakeInitParam;
begin
	with InitParam do begin
		ListView 	:= nil;
		ForWho 		:= -1; {this is what descendants will normally override}
		FocusedID := -1;
		FocusedParentID := -1;
	end;
end;

{*MUST* be overriden - should set the appropriate field of the attached
jimmy so that it hooks correctly on/whatever to it's owner, when we're
dealing with eg new person/address or person/membership}
procedure TJimmyInputGroup.SetForWho;
begin abstract; end;


{********************************************************
 ***                                                  ***
 ***         ATTACHEDJIMMY INPUT GROUP                ***
 ***                                                  ***
 ********************************************************}
constructor TAttachedJimmyInput.Init;
begin
	inherited init(bounds, Nsrtype);
	hkType := NhkType;
	htType := NhtType; {which forwho is the editbox owner}
	EditBox := NEditBox;
end;

procedure TAttachedJimmyInput.GetData;
begin end;

procedure TAttachedJimmyInput.SetData;
var	ID : longint;

begin
	{get from editboxes' jimmy}
	FileAdmin(fiHooks)^.LogOn;
	ID := HooKFile^.FindFirst(EditBox^.Jimmy^.GetFirstHookPtr(hkType), srType);
	FileAdmin(fiHooks)^.LogOff;

	inherited SetData(ID);
end;

function TAttachedJimmyInput.DataSize;
begin DataSize := 0; end;

procedure TAttachedJimmyInput.InsertEditFields;
begin
	inherited InsertEditFields;

	if Jimmy<>nil then
		Jimmy^.AddFields(@Self, EditBox);

	Redraw;
end;

procedure TAttachedJimmyInput.MakeInitParam;
begin
	inherited MakeInitParam(InitParam);
	if (EditBox<>nil) and (EditBox^.Jimmy<>nil) then InitParam.FOrWho := EditBox^.Jimmy^.RecNo;
end;

{Set forwho from given htType}
procedure TAttachedJimmyInput.SetForWho;
var HookToID, SubHookToID : PLongint;
		NhkType : byte;
		Key : longint;
		InsBias : boolean;

begin
	if Jimmy<>nil then begin
		Jimmy^.GetHookTo(htType, HookToID, SubHookToID, NhkType, Key, InsBias);
		if HookToID=nil then
			ProgramError('TUIJIMMY - Illegal htType '+N2Str(htType)+' for TAttachedJimmyInput',hcInternalErrorMsg)
		else
			if (EditBox<>nil) and (EditBox^.Jimmy<>nil) then HookToID^ := EditBox^.Jimmy^.RecNo;
	end;
end;




{********************************************************
 ***                                                  ***
 ***                 JIMMY EDITBOX                    ***
 ***                                                  ***
 ********************************************************}
constructor TJimmyEditBox.Init(Bounds : TRect; NTitle : STring; NCallingView : PView; NJimmy : PJimmy);
begin
	if NJimmy^.RecNO = -1 then NTitle := 'New '+NTitle;
	inherited Init(Bounds, NTitle, NCallingView);
	Jimmy := NJimmy;
	AcceptorView := nil;

	{shift so it does not start on top of another one}
	while IsViewAt(Origin.X, Origin.Y) do
		MoveTo(Origin.X+1, Origin.Y+1);
end;

destructor TJimmyEditBox.Done;
begin
	dispose(Jimmy, done);
	inherited Done;
end;

{==== HANDLE EVENT ====================}
procedure TJimmyEditBox.HandleEvent(var Event : TEvent);
var B, TemphkType : byte;
		StoredJimmy : PJimmy;
		New : boolean;
		HookToID,SubHookToID : PLongint;
		Key : longint;
		InsBias : boolean;

begin
	{**** CHECK ALSO TJIMMYINPUTGROUP.HANDLEEVENT}


	{message been sent to locate a view that is editing a jimmy}
	if (not GetState(sfDisabled)) and
		 (Event.What=evBroadCast) and (Event.Command=cmIsJImmyEdited) and
			(PISJimmyEditedInfo(Event.InfoPtr)^.lsType=0) and
			(PIsJimmyEditedInfo(Event.InfoPtr)^.JimmyID = PJimmy(JImmy)^.REcNo) and
			(PJImmy(JImmy)^.RecNo<>-1) then
				ClearEvent(Event); {this sets infoptr to self}

	{when closing box, unlock jimmy}
	{{$IFNDEF SIngleUser} {need to allow for self-locks}
	if ((Event.What=evBroadCast) or (Event.What=evCommand))
		and ((Event.Command=cmCancel) or (Event.Command=cmClose) or (Event.Command=cmOK)) then begin
		if Jimmy^.LockTerminal=TerminalNo then
			Jimmy^.DecLock; {auto store if changed}
	end;
	{{$ENDIF}

	{---- Instruction to store jimmy ------------}
	{Sent by storebutton, etc}
	{broadcast event so that Tinputjimmygroup can also store their own jimmy}
	if (Event.What = evBroadcast) and (Event.Command=cmStoreJimmy) then begin
		{as the jimmy is stored, it passes messages around informing any
		views displaying that jimmy to update.  AS this view is one of these,
		it will end up catching and processing these messages.  1) there is
		no point as it is about to be disposed of and it's the new already-
		updated jimmy anyway, and 2) it prevents links being done from this
		box which, lets face it, is already linked and could be dangerous. eg
		crush editbox, which may do a dohistorylist, messing about with
		inserting etc while the desktop is trying to do a foreach}

		{see also below just after inherited Handleevent for second part of
		storing}

		{so disable to prevent picking up messages}
		EventMask := EventMask and not evBRoadcast;{}

		GetData(Jimmy^);
{		Jimmy^.Lock := 0;{just store - may be going on to a sublist}

		{$IFDEF fixit}
		{this was added for the rally, so that changes to op/etc pointers are
		stored before being reloaded by the storeself routine}
		if Jimmy^.recNo<>-1 then PutJimmy(Jimmy);
		{$ENDIF}

		Jimmy^.StoreSelf;

		EventMask := EventMask or evBRoadcast;  {replace for actual closing}

		{$IFDEF kusers}
		if (CurrentUser<>nil) and (PJimmy(DataItem)^.REcNo = CurrentUser^.RecNo) then begin
			{update current user details}
			dispose(CurrentUser, done);
			CurrentUser := PUser(GetJimmy(PJimmy(DataItem)^.RecNo));
		end;
		{$ENDIF}
	end;

	if ((Event.What = evCommand) or (Event.What = evBroadCast))
			and (Event.Command = cmOK) then
		if AcceptorView<>nil then
			Message(AcceptorView, evBroadCast, cmAcceptJimmy, @Jimmy^.RecNo);

	inherited HandleEvent(Event);

	{As the subviews may contain jimmyinputgroups which are stored, thereby
	giving themselves a recno (if they were new), then the jimmy needs to be
	re-put to update these.  However, the pointers may have been updated so
	they need to be reloaded too}
	if (Event.What = evBroadcast) and (Event.Command=cmStoreJimmy) then begin
		GetData(Jimmy^);
		Jimmy^.LoadAllPtrs;
		PutJimmy(Jimmy);
	end;

	{returns currently focused jimmy, for diary repeaters/create froms/etc}
	if (Event.What = evBroadCast) and (Event.Command=cmGetFocusedJimmy) and GetState(sfFocused) then begin
		CLearEvent(Event);
		Event.InfoLong := Jimmy^.RecNo;
	end;


	{check to see if the jimmy being stored is relevant to the one this box
	is for}
	if (Event.What=evBroadCast) and (Event.Command=cmJimmyStored) then begin

		StoredJimmy := PJimmyStoredInfo(Event.InfoPtr)^.Jimmy;

		{if the jimmy has been stored that is HOOKED ONTO the one attached to this
		box (ie the one being edited), then the pointer will already have been
		updated in memory (due to the FindJimmy in the hooking methods providing
		direct access to the attached jimmy).  However, if we are in fixit mode,
		we'll want the appropriate pointer value on the screen updated...}
{$IFDEF fixit}
		{picks up if a jimmy is stored that is HOOKED ONTO the one being edited}
		if (Jimmy^.RecNo<>-1) then
			for B :=1 to Jimmy^.NumHookTo do begin
				StoredJimmy^.GetHookTo(B, HookToID,SubHookToID, TemphkType, Key, InsBias);

				if (HookToID<>nil) and (HookToID^=Jimmy^.RecNo) then begin
					{parent it was hooked to is the one being edited, so load hook pointer}

					GetData(JImmy^); 	{for udating display}

					{Get just correct hook from disk}
					PJImmy(JImmy)^.LoadFirstHookPtr(Temphktype);

					SetData(JImmy^);
					Redraw; {update display}
				end;
			end;
{$ENDIF}

		{the jimmy has been stored that this box is about.  This would not
		normally concern std OK buttons, etc, and the box should be disabled so
		it doesn't catch this event (and --> saves time) but it might be useful
		for lists in dialog boxes, etc where the jimmy is stored on focussing the
		list.  Again, nothing will usually happen as the data will probably be the
		same as has just been stored, but particularly for fixit where the storeing
		may change some items, the jimmy ought to be updated on-screen}
		{The only real way of recognising one is by checking the *memory* pointer
		or the disk one, in case of -1 --> nnnn pointers}
		{Actually can't test the record number, as, for example, with hooked lists
		have a dummy/blank jimmy, and doing a setdata here blanks the box...}
		if (Jimmy<>nil) and {(Jimmy^.Recno=StoredJimmy^.RecNo) or{} (Jimmy=StoredJimmy) then begin
			SetData(StoredJimmy^);
			Redraw;
		end;{}
	end; {}


end;

{********************************************************
 ***                 STORE BUTTON                     ***
 ********************************************************}
constructor TJimmyStoreButton.Init;
begin
	{Should NOT do a forcelink automatically, as linked fields may have just
	been overriden by user.  LEave it to instantiator (eg MakeEditbox) to
	do set it if nec.}
	inherited init(X,Y, ATitle, ACommand, AFlags {or bfForceLink{}, Jimmy);

	if not Jimmy^.AllowChanges then fail; {this doesn't work for some reason: SetState(sfDisabled, True);{}
end;
{getdata now done as part of storejimmy}

{Stores self in chains of people given by ToWho lines, etc in edit box{}
procedure TJimmyStoreButton.Press;
var Event : TEvent;
begin
	inherited Press;  {display pressed, setdata, validate, etc}

	if OwnerValid=0 then {no test done}
		if not Owner^.Valid(cmOK) then begin
			OwnerValid := -1;
			if Command<>cmNone then begin ClearEvent(Event); PutEvent(Event); end; {clear button's event}
		end else
			OwnerValid := 1;{}

	if OwnerValid=-1 then begin DrawState(False); exit; end; {no store, etc}

	{Don't want to bother storing if it hasn't changed, although new ones will
	always require storing, and lets force it to do so if the OK button is pressed}
	if (PJimmy(DataItem)^.RecNo =-1)
		or (Command = cmOK)
		or (Message(Owner, evBroadCast, cmGetChangedIndicator, nil)<>nil) then begin
			Message(Owner, evBroadCast, cmStoreJimmy,nil);
			{will not necessarily focus if there's been no changes.  Anyway, always
			want to refocus if cmOK, but not for other commands}
			if Command = cmOK then Message(Desktop, evBRoadcast, cmFocusJimmy, DataItem);
	end;
end;

{****************************************************************
 ***                      JIMMY OK-BUTTON                     ***
 ****************************************************************}
{The OK/Cancel buttons have to act as complete tidier-uppers if the jimmy
edit box is going to be left loose on the screen as a non-modal view.  They
have to store and unlock the jimmy (the editbox will dispose of it), as
well as informing the original list of a new place to focus. (now done in the
notifyviews part of the TJimmy.storeself method}

{The disposing of the jimmy is a little difficult - we don't want to do it
in the press procedures as then descendants cannot easily make use of the
tied object.  So it is disposed by the jimmyeditbox, when it is destructed}

constructor TJimmyOKButton.Init;
begin
	inherited init(X,Y, 'O~K~', cmOK, bfDefault {or bfGetData{}, JImmy);
	kbType := kbF10;
end;

{procedure TJimmyOKButton.Press;
begin
	PJimmy(DataItem)^.Lock := 0; {clear lock}

{	inherited Press;

{	if OwnerValid=-1 then exit;

	{send accept message, for instant new from input lines, etc}
{	if PJimmyEditBox(Owner)^.AcceptorView<>nil then begin
		Owner^.SetState(sfDisabled, True); {see above storebutton.press for comments}
{		Message(PJImmyEditBox(Owner)^.AcceptorView, evBroadCast, cmAcceptJimmy, @PJimmy(DataItem)^.RecNo);
		Owner^.SetState(sfDisabled, False);
	end;{}
{end;

{============ JIMMY CANCEL & DISPOSER BUTTON ==================}
constructor TJimmyCancelButton.Init;
var bfType : word;
begin
	if Jimmy^.AllowChanges then bfType :=bfNormal else bfType := bfDefault; {so that enter cancels, not saves}
	inherited init(X,Y, '~C~ancel', cmCancel, bfType, JImmy);
	kbType := kbESC;
end;

procedure TJimmyCancelButton.Press;
begin
	if (PJimmy(DataItem)^.RecNo=-1) and not PJimmy(DataItem)^.AllowDeletion then begin
		InputWarning('Abandon not allowed',hcNoAbandonMsg);
		SetState(sfDisabled, True);
		Draw;
		Owner^.FocusNext(False);
	end else begin
		inherited Press;
		{$IFNDEF SingleUser} {now done by editboxPJimmy(DataItem)^.SetLock(False); {with auto store}{$ENDIF}
	end;
end;


{****************************************************************
 ***                                                          ***
 ***                      JIMMY PRINT-BUTTON                  ***
 ***                                                          ***
 ****************************************************************}
constructor	TJimmyPrintButton.Init;
begin
	inherited Init(X,Y, '~P~rint', cmPrint, bfNormal or bfGetData, Jimmy);
	kbType := kbF8;
end;

procedure 	TJimmyPrintButton.Press;
var Event : TEvent;
begin
	inherited Press; {Gets data from owner - box}

	if OwnerValid=-1 then exit;

	PJimmy(DataItem)^.Print;

	{in case fields change, editor box should be updated & reread}
	Owner^.SetData(PJimmy(DataItem)^);
{    if not PJimmy(DataItem)^.AllowDeletion then DisableCommands([cmCancel]);{}
	Owner^.Redraw;
	DrawState(False); {unpress}
end;

end.
