Index: VerpakkingsDefinitie/UI/NavProductScherm.pas =================================================================== diff -u -r594 -r595 --- VerpakkingsDefinitie/UI/NavProductScherm.pas (.../NavProductScherm.pas) (revision 594) +++ VerpakkingsDefinitie/UI/NavProductScherm.pas (.../NavProductScherm.pas) (revision 595) @@ -53,10 +53,12 @@ Navigator.NavigeerNaar(NAVHOME); // Geef aan parent navigator NAVZOEKPRODUCTEN: begin - ApplicationContext.ProductsContext.Reset(); // Maak beide grids leeg TUtil.FreeControlChildren(GridPanelLeft); TUtil.FreeControlChildren(GridPanelRight); + // Reset de data. Na het verwijderen van de schermen zodat deze niet eerst updaten + ApplicationContext.ProductsContext.Reset(False); + ApplicationContext.ProductVerpakkingContext.Reset(); // Vul linkergrid TUtil.PlaatsControlOpGrid(GridPanelLeft, TFormZoekProducten.Create(GridPanelLeft, self, ApplicationContext, FProductsAgent), 0, 0); Index: VerpakkingsDefinitie/UI/GevondenProductenScherm.pas =================================================================== diff -u -r594 -r595 --- VerpakkingsDefinitie/UI/GevondenProductenScherm.pas (.../GevondenProductenScherm.pas) (revision 594) +++ VerpakkingsDefinitie/UI/GevondenProductenScherm.pas (.../GevondenProductenScherm.pas) (revision 595) @@ -21,6 +21,7 @@ FProductSubject: TSubject; FSubjectObserver: TSubjectObserver; FProductsAgent: TProductsAgent; + procedure UpdateGui(Sender: TObject); public Constructor Create(AOwner: TComponent; Navigator: INavigator; ApplicationContext: TApplicationContext; @@ -55,12 +56,12 @@ procedure TFormGevondenProducten.ListViewProductenSelectItem(Sender: TObject; Item: TListItem; Selected: Boolean); begin - if (Selected = false) or (Item = nil) or (Item.Data = nil) then + if Selected = false then exit; - // Product selectie registreren. Observatie uitzetten want dit scherm zet de selectie, reageert er niet op. + + // Product selectie registreren.Observatie uitzetten want dit scherm zet de selectie, reageert er niet op. self.FSubjectObserver.Enabled := false; ApplicationContext.ProductsContext.GeselecteerdProduct := Item.Data; - ApplicationContext.ProductsContext.NotifyChanged(); { TODO : Vervangen door notify changed in setter } self.FSubjectObserver.Enabled := True; self.Navigator.NavigeerNaar(NAVTOONPRODUCT); @@ -86,10 +87,7 @@ Data := Product; end; end; - ListViewProducten.Items.EndUpdate; - - // Bij opnieuw inladen is de selectie verloren gegaan. - self.ApplicationContext.ProductVerpakkingContext.Reset(); + ListViewProducten.Items.EndUpdate(); end; end. Index: VerpakkingsDefinitie/UI/ZoekProductenScherm.dfm =================================================================== diff -u -r594 -r595 --- VerpakkingsDefinitie/UI/ZoekProductenScherm.dfm (.../ZoekProductenScherm.dfm) (revision 594) +++ VerpakkingsDefinitie/UI/ZoekProductenScherm.dfm (.../ZoekProductenScherm.dfm) (revision 595) @@ -23,7 +23,7 @@ Top = 0 Width = 361 Height = 204 - ActivePage = TabSheetTekst + ActivePage = TabSheetKortTekst Anchors = [akLeft, akTop, akRight, akBottom] Font.Charset = DEFAULT_CHARSET Font.Color = clWindowText Index: VerpakkingsDefinitie/Other/ReadOnlyList.pas =================================================================== diff -u --- VerpakkingsDefinitie/Other/ReadOnlyList.pas (revision 0) +++ VerpakkingsDefinitie/Other/ReadOnlyList.pas (revision 595) @@ -0,0 +1,326 @@ +unit ReadOnlyList; + +interface + +// Eigen gemaakt list gebaseerd op TList zonder methodes om de lijst te manipuleren na creatie. + +uses + System.Generics.Collections, System.Generics.Defaults, System.SysUtils, System.RTLConsts; + +type + TReadOnlyList = class(TEnumerable) + private + FItems: array of T; + FCount: Integer; + FComparer: IComparer; + FOnNotify: TCollectionNotifyEvent; + + function GetCapacity: Integer; + procedure SetCapacity(Value: Integer); + procedure SetCount(Value: Integer); + function GetItem(Index: Integer): T; + + procedure Grow(ACount: Integer); + procedure GrowCheck(ACount: Integer); inline; + + procedure DeleteRange(AIndex, ACount: Integer); + + procedure Insert(Index: Integer; const Value: T); + + procedure InsertRange(Index: Integer; const Collection: TEnumerable); overload; + protected + function DoGetEnumerator: TEnumerator; override; + procedure Notify(const Item: T; Action: TCollectionNotification); virtual; + public + constructor Create; overload; + constructor Create(const AComparer: IComparer); overload; + constructor Create(Collection: TEnumerable); overload; + destructor Destroy; override; + + function First: T; + function Last: T; + + function Contains(const Value: T): Boolean; + function IndexOf(const Value: T): Integer; + function LastIndexOf(const Value: T): Integer; + + function BinarySearch(const Item: T; out Index: Integer): Boolean; overload; + function BinarySearch(const Item: T; out Index: Integer; const AComparer: IComparer): Boolean; overload; + + procedure TrimExcess; + + function ToArray: TArray; override; final; + + property Capacity: Integer read GetCapacity write SetCapacity; + property Count: Integer read FCount write SetCount; + // property Items[Index: Integer]: T read GetItem write SetItem; default; + property Items[Index: Integer]: T read GetItem; default; + property OnNotify: TCollectionNotifyEvent read FOnNotify write FOnNotify; + + type + TEnumerator = class(TEnumerator) + private + FList: TReadOnlyList; + FIndex: Integer; + function GetCurrent: T; + protected + function DoGetCurrent: T; override; + function DoMoveNext: Boolean; override; + public + constructor Create(AList: TReadOnlyList); + property Current: T read GetCurrent; + function MoveNext: Boolean; + end; + + function GetEnumerator: TEnumerator; reintroduce; + end; + +implementation + +function TReadOnlyList.GetCapacity: Integer; +begin + Result := Length(FItems); +end; + +procedure TReadOnlyList.SetCapacity(Value: Integer); +begin + if Value < Count then + Count := Value; + SetLength(FItems, Value); +end; + +procedure TReadOnlyList.SetCount(Value: Integer); +begin + if Value < 0 then + raise EArgumentOutOfRangeException.CreateRes(@SArgumentOutOfRange); + if Value > Capacity then + SetCapacity(Value); + if Value < Count then + DeleteRange(Value, Count - Value); + FCount := Value; +end; + +function TReadOnlyList.GetItem(Index: Integer): T; +begin + if (Index < 0) or (Index >= Count) then + raise EArgumentOutOfRangeException.CreateRes(@SArgumentOutOfRange); + Result := FItems[Index]; +end; + + +procedure TReadOnlyList.Grow(ACount: Integer); +var + newCount: Integer; +begin + newCount := Length(FItems); + if newCount = 0 then + newCount := ACount + else + repeat + newCount := newCount * 2; + if newCount < 0 then + OutOfMemoryError; + until newCount >= ACount; + Capacity := newCount; +end; + +procedure TReadOnlyList.GrowCheck(ACount: Integer); +begin + if ACount > Length(FItems) then + Grow(ACount) + else if ACount < 0 then + OutOfMemoryError; +end; + +procedure TReadOnlyList.Notify(const Item: T; Action: TCollectionNotification); +begin + if Assigned(FOnNotify) then + FOnNotify(Self, Item, Action); +end; + +constructor TReadOnlyList.Create; +begin + Create(TComparer.Default); +end; + +constructor TReadOnlyList.Create(const AComparer: IComparer); +begin + inherited Create; + FComparer := AComparer; + if FComparer = nil then + FComparer := TComparer.Default; +end; + +constructor TReadOnlyList.Create(Collection: TEnumerable); +begin + inherited Create; + FComparer := TComparer.Default; + InsertRange(0, Collection); +end; + +destructor TReadOnlyList.Destroy; +begin + Capacity := 0; + inherited; +end; + +function TReadOnlyList.DoGetEnumerator: TEnumerator; +begin + Result := GetEnumerator; +end; + + + +function TReadOnlyList.BinarySearch(const Item: T; out Index: Integer): Boolean; +begin + Result := TArray.BinarySearch(FItems, Item, Index, FComparer, 0, Count); +end; + +function TReadOnlyList.BinarySearch(const Item: T; out Index: Integer; const AComparer: IComparer): Boolean; +begin + Result := TArray.BinarySearch(FItems, Item, Index, AComparer, 0, Count); +end; + +procedure TReadOnlyList.Insert(Index: Integer; const Value: T); +begin + if (Index < 0) or (Index > Count) then + raise EArgumentOutOfRangeException.CreateRes(@SArgumentOutOfRange); + + GrowCheck(Count + 1); + if Index <> Count then + begin + System.Move(FItems[Index], FItems[Index + 1], (Count - Index) * SizeOf(T)); + FillChar(FItems[Index], SizeOf(FItems[Index]), 0); + end; + FItems[Index] := Value; + Inc(FCount); + Notify(Value, cnAdded); +end; + +procedure TReadOnlyList.InsertRange(Index: Integer; const Collection: TEnumerable); +var + Item: T; +begin + for Item in Collection do + begin + Insert(Index, Item); + Inc(Index); + end; +end; + +function TReadOnlyList.First: T; +begin + Result := Items[0]; +end; + +procedure TReadOnlyList.DeleteRange(AIndex, ACount: Integer); +var + oldItems: array of T; + tailCount, i: Integer; +begin + if (AIndex < 0) or (ACount < 0) or (AIndex + ACount > Count) or (AIndex + ACount < 0) then + raise EArgumentOutOfRangeException.CreateRes(@SArgumentOutOfRange); + if ACount = 0 then + Exit; + + SetLength(oldItems, ACount); + System.Move(FItems[AIndex], oldItems[0], ACount * SizeOf(T)); + + tailCount := Count - (AIndex + ACount); + if tailCount > 0 then + begin + System.Move(FItems[AIndex + ACount], FItems[AIndex], tailCount * SizeOf(T)); + FillChar(FItems[Count - ACount], ACount * SizeOf(T), 0); + end + else + begin + FillChar(FItems[AIndex], ACount * SizeOf(T), 0); + end; + Dec(FCount, ACount); + + for i := 0 to Length(oldItems) - 1 do + Notify(oldItems[i], cnRemoved); +end; + +function TReadOnlyList.Contains(const Value: T): Boolean; +begin + Result := IndexOf(Value) >= 0; +end; + +function TReadOnlyList.IndexOf(const Value: T): Integer; +var + i: Integer; +begin + for i := 0 to Count - 1 do + if FComparer.Compare(FItems[i], Value) = 0 then + Exit(i); + Result := -1; +end; + +function TReadOnlyList.Last: T; +begin + Result := Items[Count - 1]; +end; + +function TReadOnlyList.LastIndexOf(const Value: T): Integer; +var + i: Integer; +begin + for i := Count - 1 downto 0 do + if FComparer.Compare(FItems[i], Value) = 0 then + Exit(i); + Result := -1; +end; + +function TReadOnlyList.ToArray: TArray; +var + i: Integer; +begin + SetLength(Result, Count); + for i := 0 to Count - 1 do + Result[i] := Items[i]; +end; + +procedure TReadOnlyList.TrimExcess; +begin + Capacity := Count; +end; + +function TReadOnlyList.GetEnumerator: TEnumerator; +begin + Result := TEnumerator.Create(Self); +end; + +{ TReadOnlyList.TEnumerator } + +constructor TReadOnlyList.TEnumerator.Create(AList: TReadOnlyList); +begin + inherited Create; + FList := AList; + FIndex := -1; +end; + +function TReadOnlyList.TEnumerator.DoGetCurrent: T; +begin + Result := GetCurrent; +end; + +function TReadOnlyList.TEnumerator.DoMoveNext: Boolean; +begin + Result := MoveNext; +end; + +function TReadOnlyList.TEnumerator.GetCurrent: T; +begin + Result := FList[FIndex]; +end; + +function TReadOnlyList.TEnumerator.MoveNext: Boolean; +begin + if FIndex >= FList.Count then + Exit(False); + Inc(FIndex); + Result := FIndex < FList.Count; +end; + +end. Index: VerpakkingsDefinitie/WS/ProductsAgent.pas =================================================================== diff -u -r594 -r595 --- VerpakkingsDefinitie/WS/ProductsAgent.pas (.../ProductsAgent.pas) (revision 594) +++ VerpakkingsDefinitie/WS/ProductsAgent.pas (.../ProductsAgent.pas) (revision 595) @@ -30,8 +30,8 @@ pxBoxDataObj: OptiServerService.pxBoxData); overload; procedure RegistreerMislukteOpzoeking(ProductDetailContext: TProductVerpakkingenContext; pxStatusObj: OptiServerService.pxStatus); overload; - function GetBoxDataIDsViaProduct(ProductNr: Integer; UserContext: TUserContext; ProductDetailContext: TProductVerpakkingenContext) - : TList; + function GetBoxDataIDsViaProduct(ProductNr: Integer; UserContext: TUserContext; + ProductDetailContext: TProductVerpakkingenContext): TList; public Constructor Create(); procedure LaadUIInstellingen(UserContext: TUserContext; UiInstellingenContext: TUiInstellingenContext); @@ -268,19 +268,19 @@ Lijnen: TStringList; LijnenProduct: TStringList; XMLDoc: IXMLDocument; + NieuweProducten: TList; NieuwProduct: TProductInformatie; begin // Andere velden juist zetten ProductsContext.IsOK := True; ProductsContext.ErrorMessage := ''; ProductsContext.InternalErrorMessage := ''; - ProductsContext.Producten.Clear(); - - // Producten inladen - LijnenProduct := TStringList.Create; - Lijnen := GeefBruikbareLijnenUitXMLDataSet(DataSet); try + // Producten inladen + LijnenProduct := TStringList.Create; + Lijnen := GeefBruikbareLijnenUitXMLDataSet(DataSet); + NieuweProducten := TList.Create(); // De 'Select' elementen overlopen en elk element mappen naar een property van een instantie. // Deze instantie toevoegen aan de lijst. for Lijn in Lijnen do @@ -299,13 +299,16 @@ XMLDoc := LoadXMLData(TempStr); // XML document van maken // Elementen uit XML laden, toewijzen en instantie toevoegen aan lijst. NieuwProduct := TProductInformatie.Create(); - NieuwProduct.ProductNr := XMLDoc.DocumentElement.ChildValues['ProductNr']; - NieuwProduct.Tekst := XMLDoc.DocumentElement.ChildValues['Tekst']; - NieuwProduct.Kol1 := XMLDoc.DocumentElement.ChildValues['Kol1']; - NieuwProduct.Kol2 := XMLDoc.DocumentElement.ChildValues['Kol2']; - NieuwProduct.Kol3 := XMLDoc.DocumentElement.ChildValues['Kol3']; - NieuwProduct.Kol4 := XMLDoc.DocumentElement.ChildValues['Kol4']; - ProductsContext.Producten.Add(NieuwProduct); + with NieuwProduct do + begin + ProductNr := XMLDoc.DocumentElement.ChildValues['ProductNr']; + Tekst := XMLDoc.DocumentElement.ChildValues['Tekst']; + Kol1 := XMLDoc.DocumentElement.ChildValues['Kol1']; + Kol2 := XMLDoc.DocumentElement.ChildValues['Kol2']; + Kol3 := XMLDoc.DocumentElement.ChildValues['Kol3']; + Kol4 := XMLDoc.DocumentElement.ChildValues['Kol4']; + end; + NieuweProducten.Add(NieuwProduct); // klaarzetten voor (mogelijks) volgend product LijnenProduct.Clear(); @@ -315,18 +318,20 @@ // Standaard productlijnen toevoegen LijnenProduct.Add(Lijn); end; + // Opgehaalde producten registreren + ProductsContext.Reset(false); + ProductsContext.SetProducten(NieuweProducten); finally - Lijnen.Free(); - LijnenProduct.Free(); + FreeAndNil(Lijnen); + FreeAndNil(LijnenProduct); + FreeAndNil(NieuweProducten); end; - - ProductsContext.NotifyChanged(); end; procedure TProductsAgent.RegistreerMislukteOpzoeking(ProductsContext: TProductsContext; pxStatusObj: SelectService.pxStatus); begin // Ander velden leegmaken - ProductsContext.Producten.Clear(); + ProductsContext.Reset(); ProductsContext.IsOK := pxStatusObj.IsOK; ProductsContext.ErrorMessage := pxStatusObj.Message_; Index: VerpakkingsDefinitie/ApplicationContext.pas =================================================================== diff -u -r594 -r595 --- VerpakkingsDefinitie/ApplicationContext.pas (.../ApplicationContext.pas) (revision 594) +++ VerpakkingsDefinitie/ApplicationContext.pas (.../ApplicationContext.pas) (revision 595) @@ -8,7 +8,7 @@ uses ObserverPattern, - System.Generics.Collections, SysUtils; + System.Generics.Collections, SysUtils, ReadOnlyList; // SUB CONTEXTS: klassen die overeenkomen met bepaalde sub-context (bv. alles gerelateerd met authenticatie). @@ -94,17 +94,18 @@ FIsOK: Boolean; FErrorMessage: string; FInternalErrorMessage: string; + + procedure SetGeselecteerdProduct(ProductInformatie: TProductInformatie); + function GetProductenLijst: TReadOnlyList; public constructor Create(); - procedure Reset(); procedure NotifyChanged(); - property Producten: TList read FProducten; - { TODO : -Immutable list type retourneren en functie om item(s) toe te voegen (met Notify) -https://stackoverflow.com/questions/22693154/make-delphi-tlist-immutable } - property GeselecteerdProduct: TProductInformatie read FGeselecteerdProduct write FGeselecteerdProduct; - { TODO : GeselecteerdProduct setter hierop plaatsen en NotifyChanged() callen } + procedure Reset(Notify: Boolean = True); + property Producten: TReadOnlyList read GetProductenLijst; + procedure SetProducten(Collection: TEnumerable); + property GeselecteerdProduct: TProductInformatie read FGeselecteerdProduct write SetGeselecteerdProduct; + property IsOK: Boolean read FIsOK write FIsOK; property ErrorMessage: string read FErrorMessage write FErrorMessage; property InternalErrorMessage: string read FInternalErrorMessage write FInternalErrorMessage; @@ -187,7 +188,7 @@ property DefaultRichtingen: TList read FDefaultRichtingen; property Parameters: TList read FParameters; - { TODO : Immutable list } + { TODO : Immutable list } property DeelVanID: string read FDeelVanID write FDeelVanID; property DeelVanCaption: string read FDeelVanCaption write FDeelVanCaption; @@ -213,9 +214,9 @@ procedure NotifyChanged(); procedure Reset(); property ProductVerpakkingen: TList read FProductVerpakkingen; - { TODO : -Immutable list type retourneren en functie om item(s) toe te voegen (met Notify) -https://stackoverflow.com/questions/22693154/make-delphi-tlist-immutable } + { TODO : + Immutable list type retourneren en functie om item(s) toe te voegen (met Notify) + https://stackoverflow.com/questions/22693154/make-delphi-tlist-immutable } function GetDeelVanOpties(ProductVerpakking: TProductVerpakking): TList; property GeselecteerdeVerpakking: TProductVerpakking read FGeselecteerdeVerpakking write FGeselecteerdeVerpakking; { TODO : GeselecteerdeVerpakking setter hierop plaatsen en NotifyChanged() callen } @@ -279,14 +280,33 @@ self.Change(); end; +function TProductsContext.GetProductenLijst: TReadOnlyList; +begin + Result := TReadOnlyList.Create(FProducten); +end; + +procedure TProductsContext.SetProducten(Collection: TEnumerable); +begin + FProducten.Clear(); + FProducten.AddRange(Collection); + self.NotifyChanged(); +end; + +procedure TProductsContext.SetGeselecteerdProduct(ProductInformatie: TProductInformatie); +begin + FGeselecteerdProduct := ProductInformatie; + self.NotifyChanged(); +end; + // Enkel updaten wanneer nog niet op nil stond. -procedure TProductsContext.Reset(); +procedure TProductsContext.Reset(Notify: Boolean = True); begin if (GeselecteerdProduct <> nil) or (FProducten.Count > 0) then begin FProducten.Clear(); GeselecteerdProduct := nil; - NotifyChanged(); + if Notify then + NotifyChanged(); end; end; @@ -378,13 +398,13 @@ function TProductVerpakking.Equals(Obj: TObject): Boolean; begin if Obj = nil then - Result := false + Result := False else if not(Obj is TProductVerpakking) then - Result := false + Result := False else if (Obj as TProductVerpakking).ID = self.ID then - Result := true + Result := True else - Result := false; + Result := False; end; function TProductVerpakking.GetMetaCaptionDisplay(): string;