| 1 | unit UCDManagerTabs;
|
|---|
| 2 |
|
|---|
| 3 | {$mode Delphi}{$H+}
|
|---|
| 4 |
|
|---|
| 5 | interface
|
|---|
| 6 |
|
|---|
| 7 | uses
|
|---|
| 8 | Classes, Controls, ExtCtrls, ComCtrls, SysUtils, Dialogs, Contnrs,
|
|---|
| 9 | Menus, Forms, UCDCommon, UCDManager, UCDConjoinForm,
|
|---|
| 10 | LCLType, LMessages, Graphics;
|
|---|
| 11 |
|
|---|
| 12 | type
|
|---|
| 13 |
|
|---|
| 14 | { TCDManagerTabsItem }
|
|---|
| 15 |
|
|---|
| 16 | TCDManagerTabsItem = class(TCDManagerItem)
|
|---|
| 17 | IconImage: TImage;
|
|---|
| 18 | TabSheet: TTabSheet;
|
|---|
| 19 | constructor Create; override;
|
|---|
| 20 | destructor Destroy; override;
|
|---|
| 21 | procedure VisibleChange(Sender: TObject); override;
|
|---|
| 22 | end;
|
|---|
| 23 |
|
|---|
| 24 | { TCDManagerTabs }
|
|---|
| 25 |
|
|---|
| 26 | TCDManagerTabs = class(TCDManager)
|
|---|
| 27 | private
|
|---|
| 28 | MouseDown: Boolean;
|
|---|
| 29 | MouseButton: TMouseButton;
|
|---|
| 30 | FDockItems: TObjectList; // TList<TCDManagerRegionsItem>
|
|---|
| 31 | FUpdating: Boolean;
|
|---|
| 32 | procedure TabControlMouseLeave(Sender: TObject);
|
|---|
| 33 | procedure TabControlMouseDown(Sender: TObject; Button: TMouseButton;
|
|---|
| 34 | Shift: TShiftState; X, Y: Integer);
|
|---|
| 35 | procedure TabControlMouseUp(Sender: TObject; Button: TMouseButton;
|
|---|
| 36 | Shift: TShiftState; X, Y: Integer);
|
|---|
| 37 | procedure InsertControlPanel(AControl: TControl; InsertAt: TAlign;
|
|---|
| 38 | DropCtl: TControl); override;
|
|---|
| 39 | function FindControlInPanels(Control: TControl): TCDManagerItem; override;
|
|---|
| 40 | function GetHeaderPos: THeaderPos; override;
|
|---|
| 41 | function FindTabSheet(TabSheet: TTabSheet): TCDManagerTabsItem;
|
|---|
| 42 | public
|
|---|
| 43 | MouseDownSkip: Boolean;
|
|---|
| 44 | TabImageList: TImageList;
|
|---|
| 45 | PageControl: TPageControl;
|
|---|
| 46 | procedure UpdateClientSize; override;
|
|---|
| 47 | procedure SetHeaderPos(const AValue: THeaderPos); override;
|
|---|
| 48 | procedure InsertControlNoUpdate(Control: TControl; InsertAt: TAlign); virtual;
|
|---|
| 49 | procedure RemoveControl(Control: TControl); override;
|
|---|
| 50 | constructor Create(ADockSite: TWinControl); override;
|
|---|
| 51 | destructor Destroy; override;
|
|---|
| 52 | procedure TabControlChange(Sender: TObject); virtual;
|
|---|
| 53 | procedure PaintSite(DC: HDC); override;
|
|---|
| 54 | procedure Switch(Index: Integer); override;
|
|---|
| 55 | procedure PopupMenuTabCloseClick(Sender: TObject);
|
|---|
| 56 | procedure SetVisible(const AValue: Boolean); override;
|
|---|
| 57 | property DockItems: TObjectList read FDockItems write FDockItems;
|
|---|
| 58 | end;
|
|---|
| 59 |
|
|---|
| 60 | implementation
|
|---|
| 61 |
|
|---|
| 62 | uses
|
|---|
| 63 | UCDClient;
|
|---|
| 64 |
|
|---|
| 65 | { TCDManagerTabsItem }
|
|---|
| 66 |
|
|---|
| 67 | constructor TCDManagerTabsItem.Create;
|
|---|
| 68 | begin
|
|---|
| 69 | IconImage := TImage.Create(nil);
|
|---|
| 70 | end;
|
|---|
| 71 |
|
|---|
| 72 | destructor TCDManagerTabsItem.Destroy;
|
|---|
| 73 | begin
|
|---|
| 74 | IconImage.Free;
|
|---|
| 75 | inherited Destroy;
|
|---|
| 76 | end;
|
|---|
| 77 |
|
|---|
| 78 | procedure TCDManagerTabsItem.VisibleChange(Sender: TObject);
|
|---|
| 79 | var
|
|---|
| 80 | ControlVisible: Boolean;
|
|---|
| 81 | Temp: TControl;
|
|---|
| 82 | Temp2: TControl;
|
|---|
| 83 | begin
|
|---|
| 84 | with TCDManagerTabs(Manager) do begin
|
|---|
| 85 | if TControl(Sender).Visible then begin
|
|---|
| 86 | UpdateClientSize;
|
|---|
| 87 | Switch(DockItems.IndexOf(FindControlInPanels(TControl(Sender))));
|
|---|
| 88 | TCDManagerTabsItem(DockItems[DockItems.IndexOf(
|
|---|
| 89 | FindControlInPanels(TControl(Sender)))]).HideType := dhtPermanent;
|
|---|
| 90 | end else UpdateClientSize;
|
|---|
| 91 | end;
|
|---|
| 92 |
|
|---|
| 93 | // Show current dock clients in parent dock sites
|
|---|
| 94 | if TControl(Sender).Visible then
|
|---|
| 95 | if Assigned(TControl(Sender).HostDockSite) then begin
|
|---|
| 96 | //TControl(Sender).HostDockSite.DockManager.;
|
|---|
| 97 | TControl(Sender).HostDockSite.Visible := True;
|
|---|
| 98 | end;
|
|---|
| 99 | end;
|
|---|
| 100 |
|
|---|
| 101 | { TCDManagerTabs }
|
|---|
| 102 |
|
|---|
| 103 | function TCDManagerTabs.FindControlInPanels(Control: TControl
|
|---|
| 104 | ): TCDManagerItem;
|
|---|
| 105 | var
|
|---|
| 106 | I: Integer;
|
|---|
| 107 | begin
|
|---|
| 108 | I := 0;
|
|---|
| 109 | while (I < FDockItems.Count) and
|
|---|
| 110 | (TCDManagerItem(FDockItems[I]).Control <> Control) do Inc(I);
|
|---|
| 111 | if I < FDockItems.Count then Result := TCDManagerItem(FDockItems[I])
|
|---|
| 112 | else Result := nil;
|
|---|
| 113 | end;
|
|---|
| 114 |
|
|---|
| 115 | procedure TCDManagerTabs.PopupMenuTabCloseClick(Sender: TObject);
|
|---|
| 116 | begin
|
|---|
| 117 | if Assigned(PageControl.ActivePage) then
|
|---|
| 118 | TCDManagerItem(DockItems[PageControl.TabIndex]).Control.Hide;
|
|---|
| 119 | end;
|
|---|
| 120 |
|
|---|
| 121 | procedure TCDManagerTabs.SetVisible(const AValue: Boolean);
|
|---|
| 122 | begin
|
|---|
| 123 | inherited;
|
|---|
| 124 | if (PageControl.TabIndex >= 0) and (PageControl.TabIndex < DockItems.Count) then
|
|---|
| 125 | with TCDManagerItem(DockItems[PageControl.TabIndex]) do begin
|
|---|
| 126 | if AValue and (not Control.Visible) and (Control.Tag = Integer(dhtTemporal)) then begin
|
|---|
| 127 | Control.Show;
|
|---|
| 128 | Control.Tag := Integer(dhtPermanent);
|
|---|
| 129 | end;
|
|---|
| 130 | end;
|
|---|
| 131 | end;
|
|---|
| 132 |
|
|---|
| 133 | procedure TCDManagerTabs.TabControlMouseLeave(Sender: TObject);
|
|---|
| 134 | begin
|
|---|
| 135 | if MouseDown then
|
|---|
| 136 | if Assigned(PageControl.ActivePage) and not Locked then begin
|
|---|
| 137 | //TCDManagerItem(DockItems[PageControl.TabIndex]).ClientAreaPanel.DockSite := False;
|
|---|
| 138 | DragManager.DragStart(TCDManagerItem(DockItems[PageControl.TabIndex]).Control, False, 1);
|
|---|
| 139 | end;
|
|---|
| 140 | MouseDown := False;
|
|---|
| 141 | end;
|
|---|
| 142 |
|
|---|
| 143 | procedure TCDManagerTabs.TabControlChange(Sender: TObject);
|
|---|
| 144 | begin
|
|---|
| 145 | UpdateClientSize;
|
|---|
| 146 | MouseDownSkip := True;
|
|---|
| 147 | end;
|
|---|
| 148 |
|
|---|
| 149 | procedure TCDManagerTabs.TabControlMouseDown(Sender: TObject;
|
|---|
| 150 | Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
|
|---|
| 151 | begin
|
|---|
| 152 | if not MouseDownSkip then begin
|
|---|
| 153 | MouseDown := True;
|
|---|
| 154 | MouseButton := Button;
|
|---|
| 155 | end;
|
|---|
| 156 | MouseDownSkip := False;
|
|---|
| 157 | end;
|
|---|
| 158 |
|
|---|
| 159 | procedure TCDManagerTabs.TabControlMouseUp(Sender: TObject;
|
|---|
| 160 | Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
|
|---|
| 161 | begin
|
|---|
| 162 | MouseDown := False;
|
|---|
| 163 | end;
|
|---|
| 164 |
|
|---|
| 165 | constructor TCDManagerTabs.Create(ADockSite: TWinControl);
|
|---|
| 166 | var
|
|---|
| 167 | NewMenuItem: TMenuItem;
|
|---|
| 168 | NewMenuItem2: TMenuItem;
|
|---|
| 169 | I: Integer;
|
|---|
| 170 | NewTabSheet: TTabSheet;
|
|---|
| 171 | begin
|
|---|
| 172 | inherited;
|
|---|
| 173 | FDockStyle := dsTabs;
|
|---|
| 174 | FDockItems := TObjectList.Create;
|
|---|
| 175 |
|
|---|
| 176 | TabImageList := TImageList.Create(ADockSite); //FDockSite);
|
|---|
| 177 | with TabImageList do begin
|
|---|
| 178 | Name := GetUniqueName(DockSite.Name + 'ImageList');
|
|---|
| 179 | end;
|
|---|
| 180 | PageControl := TPageControl.Create(ADockSite); //FDockSite);
|
|---|
| 181 | with PageControl do begin
|
|---|
| 182 | Parent := ADockSite;
|
|---|
| 183 | Name := GetUniqueName(Self.DockSite.Name + 'TabControl');
|
|---|
| 184 | Visible := True;
|
|---|
| 185 | //Align := alTop;
|
|---|
| 186 | //Height := 24;
|
|---|
| 187 | //Color := clBlue;
|
|---|
| 188 | Align := alClient;
|
|---|
| 189 | OnChange := TabControlChange;
|
|---|
| 190 | MultiLine := True;
|
|---|
| 191 | PopupMenu := Self.PopupMenu;
|
|---|
| 192 | OnMouseLeave := TabControlMouseLeave;
|
|---|
| 193 | OnMouseDown := TabControlMouseDown;
|
|---|
| 194 | //TTabControlNoteBookStrings(Tabs).NoteBook.OnMouseLeave := TabControlMouseLeave;
|
|---|
| 195 | //TTabControlNoteBookStrings(Tabs).NoteBook.OnMouseDown := TabControlMouseDown;
|
|---|
| 196 | //TTabControlNoteBookStrings(Tabs).NoteBook.OnMouseUp := TabControlMouseUp;
|
|---|
| 197 | OnMouseUp := TabControlMouseUp;
|
|---|
| 198 | Images := TabImageList;
|
|---|
| 199 | end;
|
|---|
| 200 |
|
|---|
| 201 | //PageControl.Visible := True;
|
|---|
| 202 | //TabImageList.Clear;
|
|---|
| 203 | for I := 0 to ADockSite.DockClientCount - 1 do
|
|---|
| 204 | InsertControlNoUpdate(ADockSite.DockClients[I], alNone);
|
|---|
| 205 | //TabControlChange(Self);
|
|---|
| 206 | //TCDManagerTabs(Self).TabControlChange(Self);
|
|---|
| 207 | end;
|
|---|
| 208 |
|
|---|
| 209 | destructor TCDManagerTabs.Destroy;
|
|---|
| 210 | begin
|
|---|
| 211 | FDockItems.Free;
|
|---|
| 212 | PageControl.Free;
|
|---|
| 213 | TabImageList.Free;
|
|---|
| 214 | inherited Destroy;
|
|---|
| 215 | end;
|
|---|
| 216 |
|
|---|
| 217 | procedure TCDManagerTabs.PaintSite(DC: HDC);
|
|---|
| 218 | var
|
|---|
| 219 | I: Integer;
|
|---|
| 220 | begin
|
|---|
| 221 | inherited PaintSite(DC);
|
|---|
| 222 | //PageControl.Invalidate;
|
|---|
| 223 | end;
|
|---|
| 224 |
|
|---|
| 225 | procedure TCDManagerTabs.Switch(Index: Integer);
|
|---|
| 226 | begin
|
|---|
| 227 | PageControl.TabIndex := Index;
|
|---|
| 228 | end;
|
|---|
| 229 |
|
|---|
| 230 | procedure TCDManagerTabs.InsertControlNoUpdate(Control: TControl; InsertAt: TAlign);
|
|---|
| 231 | var
|
|---|
| 232 | NewTabSheet: TTabSheet;
|
|---|
| 233 | NewItem: TCDManagerTabsItem;
|
|---|
| 234 | begin
|
|---|
| 235 | inherited;
|
|---|
| 236 | begin
|
|---|
| 237 | NewItem := TCDManagerTabsItem.Create;
|
|---|
| 238 | with NewItem do begin
|
|---|
| 239 | Manager := Self;
|
|---|
| 240 | end;
|
|---|
| 241 | if (Control is TForm) and Assigned((Control as TForm).Icon) then
|
|---|
| 242 | NewItem.IconImage.Picture.Assign((Control as TForm).Icon);
|
|---|
| 243 |
|
|---|
| 244 | NewItem.Control := TWinControl(Control);
|
|---|
| 245 | //NewItem.HideType := dhtTemporal;
|
|---|
| 246 | Control.AddHandlerOnVisibleChanged(NewItem.VisibleChange);
|
|---|
| 247 | Control.AddHandlerOnVisibleChanging(NewItem.VisibleChanging);
|
|---|
| 248 | //AControl.Parent := NewItem.ClientAreaPanel;
|
|---|
| 249 | Control.Align := alClient;
|
|---|
| 250 | if (InsertAt = alTop) or (InsertAt = alLeft) then
|
|---|
| 251 | DockItems.Insert(0, NewItem)
|
|---|
| 252 | else DockItems.Add(NewItem);
|
|---|
| 253 | end;
|
|---|
| 254 | end;
|
|---|
| 255 |
|
|---|
| 256 | procedure TCDManagerTabs.RemoveControl(Control: TControl);
|
|---|
| 257 | var
|
|---|
| 258 | ManagerItem: TCDManagerItem;
|
|---|
| 259 | ClientCount: Integer;
|
|---|
| 260 | begin
|
|---|
| 261 | ManagerItem := FindControlInPanels(Control);
|
|---|
| 262 | if Assigned(ManagerItem) then begin
|
|---|
| 263 | Control.RemoveHandlerOnVisibleChanged(ManagerItem.VisibleChange);
|
|---|
| 264 | Control.RemoveHandlerOnVisibleChanging(ManagerItem.VisibleChanging);
|
|---|
| 265 | end; //else raise Exception.Create(Format('Control %s not found in DockItems', [Control.Name]));
|
|---|
| 266 |
|
|---|
| 267 | ManagerItem.Control.Visible := False;
|
|---|
| 268 | ManagerItem.Control.Parent := nil;
|
|---|
| 269 | DockItems.Remove(ManagerItem);
|
|---|
| 270 | ClientCount := DockItems.Count;
|
|---|
| 271 |
|
|---|
| 272 | //if TCDManager(Manager).DockSite.DockClientCount = 2 then FDockDirection := ddNone;
|
|---|
| 273 | if ClientCount = 1 then begin
|
|---|
| 274 | // Last removed control => Free parent if it is TCDConjoinForm
|
|---|
| 275 | if Self.DockSite is TCDConjoinForm then
|
|---|
| 276 | with TCDConjoinForm(Self.DockSite) do begin
|
|---|
| 277 | if Assigned(Parent) then begin
|
|---|
| 278 | TCDManagerItem(DockItems[0]).Control.ManualDock(HostDockSite);
|
|---|
| 279 | end else TCDManagerItem(DockItems[0]).Control.ManualFloat(Rect(Left, Top, Left + Width, Top + Height));
|
|---|
| 280 | ManualFloat(Rect(Left, Top, Left + Width, Top + Height));
|
|---|
| 281 | //UpdateClientSize;
|
|---|
| 282 | inherited RemoveControl(Control);
|
|---|
| 283 | Free;
|
|---|
| 284 | Exit;
|
|---|
| 285 | end;
|
|---|
| 286 | end;
|
|---|
| 287 | //if ClientCount > 0 then
|
|---|
| 288 | UpdateClientSize;
|
|---|
| 289 | inherited RemoveControl(Control);
|
|---|
| 290 | end;
|
|---|
| 291 |
|
|---|
| 292 | function TCDManagerTabs.GetHeaderPos: THeaderPos;
|
|---|
| 293 | begin
|
|---|
| 294 | Result := inherited;
|
|---|
| 295 | end;
|
|---|
| 296 |
|
|---|
| 297 | function TCDManagerTabs.FindTabSheet(TabSheet: TTabSheet): TCDManagerTabsItem;
|
|---|
| 298 | var
|
|---|
| 299 | I: Integer;
|
|---|
| 300 | begin
|
|---|
| 301 | I := 0;
|
|---|
| 302 | while (I < FDockItems.Count) and
|
|---|
| 303 | (TCDManagerTabsItem(FDockItems[I]).TabSheet <> TabSheet) do Inc(I);
|
|---|
| 304 | if I < FDockItems.Count then Result := TCDManagerTabsItem(FDockItems[I])
|
|---|
| 305 | else Result := nil;
|
|---|
| 306 | end;
|
|---|
| 307 |
|
|---|
| 308 | procedure TCDManagerTabs.SetHeaderPos(const AValue: THeaderPos);
|
|---|
| 309 | begin
|
|---|
| 310 | inherited SetHeaderPos(AValue);
|
|---|
| 311 | with PageControl do
|
|---|
| 312 | case AValue of
|
|---|
| 313 | hpAuto, hpTop: begin
|
|---|
| 314 | //Align := alTop;
|
|---|
| 315 | TabPosition := tpTop;
|
|---|
| 316 | Height := GrabberSize;
|
|---|
| 317 | end;
|
|---|
| 318 | hpLeft: begin
|
|---|
| 319 | //Align := alLeft;
|
|---|
| 320 | TabPosition := tpLeft;
|
|---|
| 321 | Width := GrabberSize;
|
|---|
| 322 | end;
|
|---|
| 323 | hpRight: begin
|
|---|
| 324 | //Align := alRight;
|
|---|
| 325 | TabPosition := tpRight;
|
|---|
| 326 | Width := GrabberSize;
|
|---|
| 327 | end;
|
|---|
| 328 | hpBottom: begin
|
|---|
| 329 | //Align := alBottom;
|
|---|
| 330 | TabPosition := tpBottom;
|
|---|
| 331 | Height := GrabberSize;
|
|---|
| 332 | end;
|
|---|
| 333 | end;
|
|---|
| 334 | end;
|
|---|
| 335 |
|
|---|
| 336 | procedure TCDManagerTabs.InsertControlPanel(AControl: TControl; InsertAt: TAlign;
|
|---|
| 337 | DropCtl: TControl);
|
|---|
| 338 | var
|
|---|
| 339 | NewTabSheet: TTabSheet;
|
|---|
| 340 | begin
|
|---|
| 341 | inherited;
|
|---|
| 342 | InsertControlNoUpdate(AControl, InsertAt);
|
|---|
| 343 | UpdateClientSize;
|
|---|
| 344 | end;
|
|---|
| 345 |
|
|---|
| 346 | procedure TCDManagerTabs.UpdateClientSize;
|
|---|
| 347 | var
|
|---|
| 348 | I: Integer;
|
|---|
| 349 | NewTabSheet: TTabSheet;
|
|---|
| 350 | DeletedPage: TTabSheet;
|
|---|
| 351 | begin
|
|---|
| 352 | for I := 0 to DockItems.Count - 1 do
|
|---|
| 353 | with TCDManagerTabsItem(DockItems[I]) do begin
|
|---|
| 354 | //Control.Tag := Integer(dhtTemporal);
|
|---|
| 355 | //Control.Visible := False;
|
|---|
| 356 | //if I >= DockItems.Count then
|
|---|
| 357 | // Control.Parent := nil;
|
|---|
| 358 | end;
|
|---|
| 359 |
|
|---|
| 360 | // Remove old existed tabs which doesn't have item associated
|
|---|
| 361 | for I := PageControl.PageCount - 1 downto 0 do begin
|
|---|
| 362 | // TCDManagerTabsItem(DockItems[DockItems.Count - 1]).Control.Visible := False;
|
|---|
| 363 | // TCDManagerTabsItem(DockItems[DockItems.Count - 1]).Control.Parent := nil;
|
|---|
| 364 |
|
|---|
| 365 | if FindTabSheet(TTabSheet(PageControl.Pages[I])) = nil then begin
|
|---|
| 366 | PageControl.OnChange := nil;
|
|---|
| 367 | DeletedPage := PageControl.Pages[I];
|
|---|
| 368 | DeletedPage.Parent := nil;
|
|---|
| 369 | PageControl.OnChange := TabControlChange;
|
|---|
| 370 | DeletedPage.Free;
|
|---|
| 371 | TabImageList.Delete(I);
|
|---|
| 372 | end;
|
|---|
| 373 | end;
|
|---|
| 374 |
|
|---|
| 375 | // Create tabs for new items
|
|---|
| 376 | for I := 0 to DockItems.Count - 1 do
|
|---|
| 377 | with TCDManagerTabsItem(DockItems[I]) do begin
|
|---|
| 378 | if not Assigned(TabSheet) then begin
|
|---|
| 379 | NewTabSheet := TTabSheet.Create(PageControl);
|
|---|
| 380 | NewTabSheet.PageControl := PageControl;
|
|---|
| 381 | TabSheet := NewTabSheet;
|
|---|
| 382 | TabImageList.Add(IconImage.Picture.Bitmap, nil);
|
|---|
| 383 | end;
|
|---|
| 384 | end;
|
|---|
| 385 |
|
|---|
| 386 | for I := 0 to DockItems.Count - 1 do
|
|---|
| 387 | with TCDManagerTabsItem(DockItems[I]) do begin
|
|---|
| 388 | PageControl.Pages[I].Caption := Control.Caption;
|
|---|
| 389 | PageControl.Pages[I].ImageIndex := I;
|
|---|
| 390 | TabImageList.Replace(I, IconImage.Picture.Bitmap, nil);
|
|---|
| 391 | //if (I < PageControl.PageCount) and Assigned(PageControl.Pages[I]) then
|
|---|
| 392 | Control.Parent := PageControl.Pages[I];
|
|---|
| 393 | Control.Align := alClient;
|
|---|
| 394 | if PageControl.PageIndex = I then begin
|
|---|
| 395 | if (not Control.Visible) and (HideType = dhtTemporal) then
|
|---|
| 396 | Control.Visible := True;
|
|---|
| 397 | end else begin
|
|---|
| 398 | if Control.Visible then begin
|
|---|
| 399 | HideType := dhtTemporal;
|
|---|
| 400 | Control.Visible := False;
|
|---|
| 401 | end;
|
|---|
| 402 | end;
|
|---|
| 403 | PageControl.Pages[I].TabVisible := Control.Visible or (HideType = dhtTemporal);
|
|---|
| 404 |
|
|---|
| 405 | //TCDClientPanel(DockPanels[I]).ClientAreaPanel.Width := DockSite.Width;
|
|---|
| 406 | //TCDClientPanel(DockPanels[I]).ClientAreaPanel.Height := DockSite.Height - PageControl.Height;
|
|---|
| 407 | //TCDClientPanel(FDockPanels[I]).DockPanelPaint(Self);
|
|---|
| 408 | end;
|
|---|
| 409 | inherited UpdateClientSize;
|
|---|
| 410 | end;
|
|---|
| 411 |
|
|---|
| 412 | end.
|
|---|
| 413 |
|
|---|