/* Devin Client - DMS - November 00 - Francois Chenebit */ /* GLOBAL CONSTANT */ /* GLOBAL VARIABLE */ var MAX_OF_PREDICTION = 4096;; /* NB : take car, we never verify that this limitation is respected ( because databse can be edited with other tools, so there is no ways of checking that. Aniway, the only problem it can generate is that the next predictions are not inserted in the correct position inside the list box.*/ var SIZE_OF_PREDICTION_PACKET = 35;; var PACKED_PREDICTION_SIZE = 100;; /* Communication Constructors */ defcom CGiveNextPredictions = GiveNextPredictions I;; defcom CGivePrecisePrediction = GivePrecisePrediction I;; defcom CUpdatePrediction = UpdatePrediction I S;; defcom CCreatePrediction = CreatePrediction S;; defcom CDeletePrediction = DeletePrediction I;; defcom CClosingClient = ClosingClient;; /* Graphical objects of the client */ typeof OBCreate = ObjButton;; typeof OBUpdate = ObjButton;; typeof OBDelete = ObjButton;; typeof OBRefresh = ObjButton;; typeof OBExit = ObjButton;; typeof OLPrediction = ObjList;; typeof OTNumPrediction = ObjText;; typeof OTTxtPrediction = ObjText;; /* function prototype */ proto WaitOn = fun[] I;; proto WaitOff = fun[] I;; /* FUNCTION */ /* GENERAL FUNCTIONS*/ /* ErrorMessage : this function write an error message into the log, and in a dialogue window it open Parameters : SerrorMsg : the string to add in the middle of the error message Return value : an unsignifiant integer */ fun ErrorMessage(SErrorMsg)= ( _fooS strcat "### " SErrorMsg; _DLGMessageBox _channel nil (_loc this "TitreErreur" nil) SErrorMsg 0; 0 );; /* This function is used to refresh the list box from the server. It is used in the initialisation, and in the refresh button action. It just ask the first predictions to the server. The predictions are received inside __ReceivePrediction ; and __ReceivePrediction ask the next ones to the server. Parameters and return values : unsignifiacnt */ fun RefreshPrediction(Unil1,Unil2)= ( /* list is cleaned before new predictions are inserted */ WaitOn; _RSTlist OLPrediction; _DMSsend this CGiveNextPredictions [ 1 ] );; /* this function add a list of predictions to the list box. It works recursivly : the next prediction is add, and if there is still one, it call itself again parameter : a list of string in the form "NumPrediction PredictionText"::... return value : the number of prediction already inserted */ fun AddPredictionToList(LSPredictions)= ( if LSPredictions == nil then ( 0; ) else ( _ADDlist OLPrediction MAX_OF_PREDICTION (hd LSPredictions ); let AddPredictionToList(tl LSPredictions) -> IalreadyAdd in ( IalreadyAdd + 1 ); ) );; /* WINDOW MANAGMENT FUNCTIONS */ /* Destruction of a zone callback function. This function destroy the client module when one of its graphical zone is destroyed, because the module can only work with all its zones. The closing of the client is signaled to the server wth the message ClosingClient Parameters and return Value are unsignifciant */ fun DestructionClient(Unil1,Unil2)= ( _DMSsend this CClosingClient []; _DMSdelete this );; /* this function is called when an asked one has already been reserved by another module should never happen, but never know. A error is signaled, and the module is closed. parameter : the zone name return value : unsignificant */ fun ErrorConflict(SZoneName)= ( ErrorMessage(strcatn (_loc this "ErreurConfiltZone" nil)::" "::SZoneName::nil); _DMSdelete this );; /* this function is the resize of the "ListeDesPredictions" callback. it resize just the list inside the zone Parameters : mandatory parameters on a resize function : a tuple containing the window and and the new coordinates, and the name of the zone return value : unsignificant */ fun ResizeListeDesPredictions(TOWINewSize,SZoneName)= ( let TOWINewSize -> [ _ Ix Iy Iw Ih ] in ( _SIZElist OLPrediction Iw Ih Ix Iy ); 0 );; /* this function is used to find the size of OTNumPrediction the heigth is max(Ih, 20), and the width is max (40 Iw*0.80) parameters : width and heigth of the zone where OTNumPrediction is return values : a tuple, containing the width and heigth of the OT */ fun FindSizeNumPrediction(Iw,Ih)= ( [ min 50 (Iw*1/5) min 30 Ih ] );; /* this function is the resize of the "DetailPrediction" callback. it resize both the editLine, and the editText, like in the window init Parameters : mandatory parameters on a resize function : a tuple containing the window and and the new coordinates, and the name of the zone return value : unsignificant */ fun ResizeDetailPrediction(TOWINewSize,SZoneName)= ( let TOWINewSize -> [ _ Ix Iy Iw Ih ] in ( let FindSizeNumPrediction Iw Ih -> [ InumW InumH ] in ( _SIZEtext OTNumPrediction InumW InumH (Ix + 5) (Iy+5); _SIZEtext OTTxtPrediction (Iw - (Ix + 15 + InumW )) Ih (Ix + 10 + InumW ) (Iy + 5 ) ) ); 0 );; /* this function is the resize of the "PaletteBoutonAction" callback it resize the 3 buttons of the zone, like in the window init Parameters : mandatory parameters on a resize function : a tuple containing the window and and the new coordinates, and the name of the zone return value : unsignificant */ fun ResizePaletteBoutonAction(TOWINewSize,SZoneName)= ( let TOWINewSize -> [ _ Ix Iy Iw Ih ] in ( _SIZEbutton OBCreate (Iw / 4) min 30 Ih (Ix + 5) (Iy + 5); _SIZEbutton OBUpdate (Iw / 4) min 30 Ih (Ix + 10 + (Iw / 4)) (Iy + 5); _SIZEbutton OBDelete (Iw / 4) min 30 Ih (Ix + 15 + (2 * Iw / 4)) (Iy + 5) ); 0 );; /* this function is the resize of the "PaletteBoutonFenetre" callback it resize the 2 buttons of the zone, like in the window init Parameters : mandatory parameters on a resize function : a tuple containing the window and and the new coordinates, and the name of the zone return value : unsignificant */ fun ResizePaletteBoutonFenetre(TOWINewSize,SZoneName)= ( let TOWINewSize -> [ _ Ix Iy Iw Ih ] in ( _SIZEbutton OBRefresh (Iw / 3) min 30 Ih (Ix + 5) (Iy + 5) ; _SIZEbutton OBExit (Iw / 3) min 30 Ih (Ix + 10 + (Iw / 3)) (Iy + 5) ); 0 );; /* This function is the OLPreidction list clisck callback It just asks to the server the prediction, with the sending of GivePrecisePrediction parameters : standard list callback parameters. Just SPredictionClicked is used return value : unsignificant */ fun ListClick(Unil1,Unil2,IPositionClicked,SPredictionClicked)= ( WaitOn; let atoi hd hd strextr SPredictionClicked -> IpredictionId in ( _DMSsend this CGivePrecisePrediction [ IpredictionId ]; ) );; /* Create button click callback. It takes the text in the TxtPrediction Zone, find the current last number, based on the list size, put that number in the NumPrediction zone, and then ask the server to insert the prediction. The server answer is the __ErrorDatabase or _CorrectDatabaseOperation messages. parameters and returnvalue : unsignificant */ fun OBCreateClick(Unil1,Unil2)= ( WaitOn; _SETtext OTNumPrediction itoa ((_GETlistCount OLPrediction) +1); _DMSsend this CCreatePrediction [ _GETtext OTTxtPrediction ] );; /* Update button click callback. It is the easier of the action button. It take the text of the NumPrediction and TxtPrediction, and send a message to the server to update these data. Server answer is givent with the __ErrorDatabase or _CorrectDatabaseOperation messages. parameters and return value : unsignificant */ fun OBUpdateClick(Unil1,Unil2)= ( let atoi _GETtext OTNumPrediction -> IpredictionNumber in ( WaitOn; _DELlist OLPrediction (IpredictionNumber - 1); _DMSsend this CUpdatePrediction [ (atoi _GETtext OTNumPrediction) (_GETtext OTTxtPrediction) ] ) );; /* Delete button click callback. It is the most difficult of the three action. It asks the server to delete the prediction identified by OTNumPrediction. In case of error, the answer is the message : ErrorDatabase. But if the delete is correct, the answer will be in ReceivePrecisePrediction, to update the text of OTTxtPrediction parameters and return value : unsignificant */ fun OBDeleteClick(Unil1,Unil2)= ( WaitOn; _DELlist OLPrediction ((_GETlistCount(OLPrediction)) - 1); _DMSsend this CDeletePrediction[ atoi _GETtext OTNumPrediction] );; /* this function is used to freeze the window while waiting for something, usually an answer from the server. all click events are made impossible parameters and return value : unsignificant */ fun WaitOn()= ( _ENlist OLPrediction 0; _ENbutton OBCreate 0; _ENbutton OBUpdate 0; _ENbutton OBDelete 0; _ENbutton OBRefresh 0; _ENbutton OBExit 0; 0 );; /* this function is the inverse of the precedent. It is used to enable the click on the differents objects of the windows parameters and return value : unsignificant */ fun WaitOff()= ( _ENlist OLPrediction 1; _ENbutton OBCreate 1; _ENbutton OBUpdate 1; _ENbutton OBDelete 1; _ENbutton OBRefresh 1; _ENbutton OBExit 1; 0 );; /* COMMUNICATION FUNCTION */ /* this function receive the next predictions given to it by the server. if there are still prediction to read, it asks them to the server. So, this function is in crossed recursivity with the server function : it ask the server the prediction, and the server give them to it parameters : a string of line in the form of "PredictionNumber PredictionText\n PredictionNumber2 PredictionText2...". return values : unsignificant */ fun __ReceivePredictions(SListOfPredictions)= ( let hd lineextr SListOfPredictions -> SfirstLine in ( let atoi (hd hd strextr SfirstLine) -> IfirstPredictionId in ( if (AddPredictionToList lineextr SListOfPredictions) != SIZE_OF_PREDICTION_PACKET then ( nil ) else ( _DMSsend this CGiveNextPredictions [ IfirstPredictionId + SIZE_OF_PREDICTION_PACKET ]; ) ) ); WaitOff; );; /* this function is called by the server to send the client a precise prediction. this prediction is put in the detailPrediction zone parameter : the prediction Id number, and the prediction text return value : unsignificant */ fun __ReceivePrecisePrediction(IPredictionNumber,SPredictionText)= ( _SETtext OTNumPrediction itoa IPredictionNumber; _SETtext OTTxtPrediction SPredictionText; WaitOff );; /* this function is used by the server to send the client a delete operation result. This result is the number of the prediction to delete, and the text of the last prediction, that become the text of the prediction to delete. the last prediction is deleted from the database. the last line is deleted in the list box, and then the line of the prediction to delete, and the text box are updated parameters : see upsides return value : unsignificant */ fun __CorrectDeleteDatabaseOperation(IPredictionId,SPredictionText)= ( _SETtext OTNumPrediction itoa IPredictionId; _SETtext OTTxtPrediction SPredictionText; _DELlist OLPrediction (IPredictionId - 1); _ADDlist OLPrediction (IPredictionId - 1) strcatn (itoa IPredictionId)::" "::SPredictionText::nil; _SELlist OLPrediction (IPredictionId - 1); WaitOff );; /* this function is called by the server to signal the client that an error has occured in the processing of a request asked by the client. The most probable reason is that someone else, on another client has deleted the prediction this client worked on. An error message is send. parameters and return value : unsignificant */ fun __ErrorDatabase()= ( ErrorMessage _loc this "ErreurDatabase" nil; WaitOff );; /* this function is called by the server, to signal the client that the last operation has occured correctly it put the prediction in the detail prediction zone in the list box. parameters and return value : unsignificant */ fun __CorrectDatabaseOperation()= ( _ADDlist OLPrediction ( (atoi _GETtext OTNumPrediction) - 1 ) (strcatn (_GETtext OTNumPrediction)::" " ::(substr _GETtext OTTxtPrediction 0 PACKED_PREDICTION_SIZE)::"..."::nil); _SELlist OLPrediction (atoi _GETtext OTNumPrediction) - 1; WaitOff );; /* MODULE MANAGEMENT FUNCTIONS */ /* this function is the initialisation of the client parameters : A string containing all the user currently logged in return value : unsignificant */ fun IniDMI(param)= ( let mknode @DestructionClient nil -> destructionZone in ( /* creation des objets dans les zones graphiques correspondantes */ let _DMSgetZone this "ListeDesPredictions" @ErrorConflict @ResizeListeDesPredictions destructionZone -> [ OWzone Ix Iy Iw Ih ] in ( set OLPrediction = _CRlist _channel OWzone Ix Iy Iw Ih LB_VSCROLL|LB_BORDER; _CBlistClick OLPrediction @ListClick nil; ); let _DMSgetZone this "DetailPrediction" @ErrorConflict @ResizeDetailPrediction destructionZone -> [ OWzone Ix Iy Iw Ih ] in ( _fooS strcatn "### taille de la zone : x : "::(itoa Ix)::" , y : "::(itoa Iy)::" , w : "::(itoa Iw)::" , h : "::(itoa Ih)::nil; let FindSizeNumPrediction Iw Ih -> [ InumW InumH ] in ( _fooS strcatn "### taille du controle : numW : "::(itoa InumW)::", INumH : "::(itoa InumH)::nil; set OTNumPrediction = _CRtext _channel OWzone (Ix + 5) (Iy+5) InumW InumH ET_BORDER|ET_DOWN|ET_TABFOCUS|ET_NUMBER nil; set OTTxtPrediction = _CReditText _channel OWzone (Ix + 10 + InumW ) (Iy + 5 ) ( Iw - (15 + InumW )) Ih ET_BORDER|ET_DOWN|ET_TABFOCUS nil ); ); let _DMSgetZone this "PaletteBoutonAction" @ErrorConflict @ResizePaletteBoutonAction destructionZone -> [ OWzone Ix Iy Iw Ih ] in ( set OBCreate = _CRbutton _channel OWzone (Ix + 5) (Iy + 5) (Iw / 4) min 30 Ih PB_TABFOCUS (_loc this "TitreBoutonCreation" nil); _CBbutton OBCreate @OBCreateClick nil; set OBUpdate = _CRbutton _channel OWzone (Ix + 10 + (Iw / 4)) (Iy + 5) (Iw / 4) min 30 Ih PB_TABFOCUS (_loc this "TitreBoutonUpdate" nil); _CBbutton OBUpdate @OBUpdateClick nil; set OBDelete = _CRbutton _channel OWzone (Ix + 15 + (2 * Iw / 4)) (Iy + 5) (Iw / 4) min 30 Ih PB_TABFOCUS (_loc this "TitreBoutonSuppression" nil); _CBbutton OBDelete @OBDeleteClick nil ); let _DMSgetZone this "PaletteBoutonFenetre" @ErrorConflict @ResizePaletteBoutonFenetre destructionZone -> [ OWzone Ix Iy Iw Ih ] in ( set OBRefresh = _CRbutton _channel OWzone (Ix + 5) (Iy + 5) (Iw / 3) min 30 Ih PB_TABFOCUS (_loc this "TitreBoutonRefresh" nil); _CBbutton OBRefresh @RefreshPrediction nil; set OBExit = _CRbutton _channel OWzone (Ix + 10 + (Iw / 3)) (Iy + 5) (Iw / 3) min 30 Ih PB_TABFOCUS (_loc this "TitreBoutonExit" nil); _CBbutton OBExit @DestructionClient nil ) ); if (strfind "\" \"" param 0) != nil then /* It is possible to find this string inside param only if there is more than one client editing the databse */ ( /* there is someone who is currently editing the database */ let strcatn (_loc this "ClientOuvert" nil)::" "::param::nil -> SErrorMsg in ( _DLGMessageBox _channel nil (_loc this "TitreErreur" nil) SErrorMsg 0 ) ) else ( /* nothing to do */ nil ); RefreshPrediction nil nil );;