unit SpTBXMDIMRU; {============================================================================== Version 2.4.4 The contents of this file are subject to the SpTBXLib License; you may not use or distribute this file except in compliance with the SpTBXLib License. A copy of the SpTBXLib License may be found in SpTBXLib-LICENSE.txt or at: http://www.silverpointdevelopment.com/sptbxlib/SpTBXLib-LICENSE.htm Alternatively, the contents of this file may be used under the terms of the Mozilla Public License Version 1.1 (the "MPL v1.1"), in which case the provisions of the MPL v1.1 are applicable instead of those in the SpTBXLib License. A copy of the MPL v1.1 may be found in MPL-LICENSE.txt or at: http://www.mozilla.org/MPL/ If you wish to allow use of your version of this file only under the terms of the MPL v1.1 and not to allow others to use your version of this file under the SpTBXLib License, indicate your decision by deleting the provisions above and replace them with the notice and other provisions required by the MPL v1.1. If you do not delete the provisions above, a recipient may use your version of this file under either the SpTBXLib License or the MPL v1.1. Software distributed under the License is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either expressed or implied. See the License for the specific language governing rights and limitations under the License. The initial developer of this code is Robert Lee. Requirements: For Delphi/C++Builder 2009 or newer: - Jordan Russell's Toolbar 2000 http://www.jrsoftware.org For Delphi/C++Builder 7-2007: - Jordan Russell's Toolbar 2000 http://www.jrsoftware.org - Troy Wolbrink's TNT Unicode Controls http://www.tntware.com/delphicontrols/unicode/ Development notes: - All the theme changes and adjustments are marked with '[Theme-Change]'. History: 2 December 2009 - version 2.4.4 - No changes. 13 September 2009 - version 2.4.3 - Fixed TSpTBXMRUListItem.LoadFromIni/SaveToIni bug, in Delphi 2009, some strings are not stored correctly (Surrogate Pair), thanks to Totonica for reporting this. - Fixed incorrect TSpTBXMDIHandler MDI buttons painting when using the default Windows theme, thanks to Cybrus for reporting this. 8 May 2009 - version 2.4.2 - Fixed incorrect MRU saving on TSpTBXMRUListItem, the items were not correctly encoded when saving to an Ini file, thanks to Dirk for reporting this. 15 March 2009 - version 2.4.1 - No changes. 17 January 2009 - version 2.4 - Added GetMRUFilenames and MRUClick methods to TSpTBXMRUListItem. - Added Hints to the items of TSpTBXMRUListItem. 26 September 2008 - version 2.3 - No changes. 29 July 2008 - version 2.2 - No changes. 26 June 2008 - version 2.1 - No changes. 3 May 2008 - version 2.0 - No changes. 2 April 2008 - version 1.9.5 - Fixed incorrect MRU loading on TSpTBXMRUListItem, thanks to Pete for reporting this. - Fixed incorrect TSpTBXMRUListItem behavior, MaxItems had no effect when new files were added, thanks to Senfore for reporting this. 3 February 2008 - version 1.9.4 - Added HidePathExtension property to TSpTBXMRUListItem. 19 January 2008 - version 1.9.3 - Initial release. ==============================================================================} interface {$BOOLEVAL OFF} // Unit depends on short-circuit boolean evaluation uses Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs, Menus, ImgList, IniFiles, TB2Item, TB2Toolbar, SpTBXSkins, SpTBXItem; type TSpTBXMDIButtonsItem = class; TSpTBXMRUListClickEvent = procedure(Sender: TObject; const Filename: WideString) of object; { TSpTBXMDIHandler } TSpTBXMDIHandler = class(TComponent) private FButtonsItem: TSpTBXMDIButtonsItem; FSystemMenuItem: TSpTBXSystemMenuItem; FToolbar: TTBCustomToolbar; procedure SetToolbar(Value: TTBCustomToolbar); protected procedure Notification(AComponent: TComponent; Operation: TOperation); override; public constructor Create(AOwner: TComponent); override; destructor Destroy; override; published property Toolbar: TTBCustomToolbar read FToolbar write SetToolbar; end; { TSpTBXMDIButtonsItem: should only be used by TSpTBXMDIHandler } TSpTBXMDIButtonsItem = class(TTBCustomItem) private FMinimizeItem, FRestoreItem, FCloseItem: TSpTBXItem; procedure DrawItem(Sender: TObject; ACanvas: TCanvas; ARect: TRect; ItemInfo: TSpTBXMenuItemInfo; const PaintStage: TSpTBXPaintStage; var PaintDefault: Boolean); procedure DrawItemImage(Sender: TObject; ACanvas: TCanvas; State: TSpTBXSkinStatesType; const PaintStage: TSpTBXPaintStage; var AImageList: TCustomImageList; var AImageIndex: Integer; var ARect: TRect; var PaintDefault: Boolean); procedure InvalidateSystemMenuItem; procedure ItemClick(Sender: TObject); procedure UpdateState(W: HWND; Maximized: Boolean); public constructor Create(AOwner: TComponent); override; destructor Destroy; override; end; { TSpTBXMDIWindowItem } TSpTBXMDIWindowItem = class(TTBCustomItem) private FForm: TForm; FOnUpdate: TNotifyEvent; FWindowMenu: TMenuItem; procedure ItemClick(Sender: TObject); procedure SetForm(AForm: TForm); protected procedure EnabledChanged; override; procedure GetChildren(Proc: TGetChildProc; Root: TComponent); override; procedure Notification(AComponent: TComponent; Operation: TOperation); override; public constructor Create(AOwner: TComponent); override; procedure InitiateAction; override; published property Enabled; property OnUpdate: TNotifyEvent read FOnUpdate write FOnUpdate; end; { TSpTBXMRUListItem } TSpTBXMRUListItem = class(TTBCustomItem) private FMaxItems: Integer; FOnClick: TSpTBXMRUListClickEvent; FHidePathExtension: Boolean; procedure ClickHandler(Sender: TObject); procedure SetHidePathExtension(const Value: Boolean); procedure SetMaxItems(const Value: Integer); public constructor Create(AOwner: TComponent); override; procedure GetMRUFilenames(MRUFilenames: TStrings); function IndexOfMRU(Filename: WideString): Integer; function MRUAdd(Filename: WideString): Integer; function MRUClick(Filename: WideString): Boolean; procedure MRURemove(Filename: WideString); procedure MRUUpdateCaptions; procedure LoadFromIni(Ini: TCustomIniFile; const Section: string); procedure SaveToIni(Ini: TCustomIniFile; const Section: string); published property HidePathExtension: Boolean read FHidePathExtension write SetHidePathExtension default True; property MaxItems: Integer read FMaxItems write SetMaxItems default 4; property OnClick: TSpTBXMRUListClickEvent read FOnClick write FOnClick; end; { TSpTBXMRUItem: should only be used by TSpTBXMRUListItem } TSpTBXMRUItem = class(TSpTBXCustomItem) private FMRUString: WideString; public property MRUString: WideString read FMRUString write FMRUString; end; implementation uses Themes, UxTheme, {$IFNDEF UNICODE} TntSysUtils, {$ENDIF} TB2Common, TB2Consts; type TTBCustomToolbarAccess = class(TTBCustomToolbar); TTBCustomItemAccess = class(TTBCustomItem); //WMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWM { TSpTBXMDIHandler } constructor TSpTBXMDIHandler.Create(AOwner: TComponent); begin inherited; FSystemMenuItem := TSpTBXSystemMenuItem.Create(Self); FSystemMenuItem.MDISystemMenu := True; FButtonsItem := TSpTBXMDIButtonsItem.Create(Self); end; destructor TSpTBXMDIHandler.Destroy; begin SetToolbar(nil); inherited; end; procedure TSpTBXMDIHandler.Notification(AComponent: TComponent; Operation: TOperation); begin inherited; if (AComponent = FToolbar) and (Operation = opRemove) then Toolbar := nil; end; procedure TSpTBXMDIHandler.SetToolbar(Value: TTBCustomToolbar); var Rebuild: Boolean; begin if FToolbar <> Value then begin if Assigned(FToolbar) then begin Rebuild := False; if TTBCustomToolbarAccess(FToolbar).FMDIButtonsItem = FButtonsItem then begin TTBCustomToolbarAccess(FToolbar).FMDIButtonsItem := nil; Rebuild := True; end; if TTBCustomToolbarAccess(FToolbar).FMDISystemMenuItem = FSystemMenuItem then begin TTBCustomToolbarAccess(FToolbar).FMDISystemMenuItem := nil; Rebuild := True; end; if Rebuild and Assigned(FToolbar.View) then FToolbar.View.RecreateAllViewers; end; FToolbar := Value; if Assigned(Value) then begin Value.FreeNotification(Self); TTBCustomToolbarAccess(Value).FMDIButtonsItem := FButtonsItem; TTBCustomToolbarAccess(Value).FMDISystemMenuItem := FSystemMenuItem; Value.View.RecreateAllViewers; end; end; end; //WMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWM { TSpTBXMDIButtonsItem } var CBTHookHandle: HHOOK; MDIButtonsItems: TList; function WindowIsMDIChild(W: HWND): Boolean; var I: Integer; MainForm, ChildForm: TForm; begin MainForm := Application.MainForm; if Assigned(MainForm) then for I := 0 to MainForm.MDIChildCount-1 do begin ChildForm := MainForm.MDIChildren[I]; if ChildForm.HandleAllocated and (ChildForm.Handle = W) then begin Result := True; Exit; end; end; Result := False; end; function CBTHook(Code: Integer; WParam: WPARAM; LParam: LPARAM): LRESULT; stdcall; var Maximizing: Boolean; WindowPlacement: TWindowPlacement; I: Integer; begin case Code of HCBT_SETFOCUS: begin if WindowIsMDIChild(HWND(WParam)) and Assigned(MDIButtonsItems) then begin for I := 0 to MDIButtonsItems.Count-1 do TSpTBXMDIButtonsItem(MDIButtonsItems[I]).InvalidateSystemMenuItem; end; end; HCBT_MINMAX: begin if WindowIsMDIChild(HWND(WParam)) and Assigned(MDIButtonsItems) and (LParam in [SW_SHOWNORMAL, SW_SHOWMAXIMIZED, SW_MINIMIZE, SW_RESTORE]) then begin Maximizing := (LParam = SW_MAXIMIZE); if (LParam = SW_RESTORE) and not IsZoomed(HWND(WParam)) then begin WindowPlacement.length := SizeOf(WindowPlacement); GetWindowPlacement(HWND(WParam), @WindowPlacement); Maximizing := (WindowPlacement.flags and WPF_RESTORETOMAXIMIZED <> 0); end; for I := 0 to MDIButtonsItems.Count-1 do TSpTBXMDIButtonsItem(MDIButtonsItems[I]).UpdateState(HWND(WParam), Maximizing); end; end; HCBT_DESTROYWND: begin if WindowIsMDIChild(HWND(WParam)) and Assigned(MDIButtonsItems) then begin for I := 0 to MDIButtonsItems.Count-1 do TSpTBXMDIButtonsItem(MDIButtonsItems[I]).UpdateState(HWND(WParam), False); end; end; end; Result := CallNextHookEx(CBTHookHandle, Code, WParam, LParam); end; constructor TSpTBXMDIButtonsItem.Create(AOwner: TComponent); function CreateItem(ImageIndex: Integer): TSpTBXItem; var A: TTBCustomItemAccess; begin Result := TSpTBXItem.Create(Self); A := TTBCustomItemAccess(Result); A.ItemStyle := A.ItemStyle + [tbisRightAlign]; Result.Images := MDIButtonsImgList; Result.ImageIndex := ImageIndex; Result.CustomWidth := 17; Result.OnClick := ItemClick; Result.OnDrawItem := DrawItem; Result.OnDrawImage := DrawItemImage; end; begin inherited; ItemStyle := ItemStyle + [tbisEmbeddedGroup]; FMinimizeItem := CreateItem(2); FRestoreItem := CreateItem(3); FCloseItem := CreateItem(0); Add(FMinimizeItem); Add(FRestoreItem); Add(FCloseItem); UpdateState(0, False); AddToList(MDIButtonsItems, Self); if CBTHookHandle = 0 then CBTHookHandle := SetWindowsHookEx(WH_CBT, CBTHook, 0, GetCurrentThreadId); end; destructor TSpTBXMDIButtonsItem.Destroy; begin RemoveFromList(MDIButtonsItems, Self); if (MDIButtonsItems = nil) and (CBTHookHandle <> 0) then begin UnhookWindowsHookEx(CBTHookHandle); CBTHookHandle := 0; end; inherited; end; procedure TSpTBXMDIButtonsItem.DrawItem(Sender: TObject; ACanvas: TCanvas; ARect: TRect; ItemInfo: TSpTBXMenuItemInfo; const PaintStage: TSpTBXPaintStage; var PaintDefault: Boolean); begin // [Theme-Change] // Don't draw the items background if the Default theme is used if (PaintStage = pstPrePaint) and SkinManager.IsDefaultSkin then PaintDefault := False; end; procedure TSpTBXMDIButtonsItem.DrawItemImage(Sender: TObject; ACanvas: TCanvas; State: TSpTBXSkinStatesType; const PaintStage: TSpTBXPaintStage; var AImageList: TCustomImageList; var AImageIndex: Integer; var ARect: TRect; var PaintDefault: Boolean); const ButtonIndexFlags: array[0..3] of Integer = (DFCS_CAPTIONCLOSE, DFCS_CAPTIONMAX, DFCS_CAPTIONMIN, DFCS_CAPTIONRESTORE); NoneFlags: array[TSpTBXSkinStatesType] of Integer = (0, DFCS_INACTIVE, 0, DFCS_PUSHED, DFCS_PUSHED, DFCS_PUSHED); XPPart: array [0..3] of Integer = (WP_MDICLOSEBUTTON, WP_MAXBUTTON, WP_MDIMINBUTTON, WP_MDIRESTOREBUTTON); XPFlags: array[TSpTBXSkinStatesType] of Integer = (CBS_NORMAL, CBS_DISABLED, CBS_HOT, CBS_PUSHED, CBS_PUSHED, CBS_PUSHED); begin if (PaintStage = pstPrePaint) and (AImageList = MDIButtonsImgList) and (AImageIndex >= 0) and (AImageIndex <= 3) then begin case SkinManager.GetSkinType of sknNone: begin PaintDefault := False; DrawFrameControl(ACanvas.Handle, ARect, DFC_CAPTION, ButtonIndexFlags[AImageIndex] or NoneFlags[State]); end; sknWindows: begin PaintDefault := False; DrawThemeBackground(ThemeServices.Theme[teWindow], ACanvas.Handle, XPPart[AImageIndex], XPFlags[State], ARect, nil); end; end; end; end; procedure TSpTBXMDIButtonsItem.UpdateState(W: HWND; Maximized: Boolean); var HasMaxChild, VisibilityChanged: Boolean; procedure UpdateVisibleEnabled(const Item: TTBCustomItem; const AEnabled: Boolean); begin if (Item.Visible <> HasMaxChild) or (Item.Enabled <> AEnabled) then begin Item.Visible := HasMaxChild; Item.Enabled := AEnabled; VisibilityChanged := True; end; end; var MainForm, ActiveMDIChild, ChildForm: TForm; I: Integer; begin HasMaxChild := False; MainForm := Application.MainForm; ActiveMDIChild := nil; if Assigned(MainForm) then begin for I := 0 to MainForm.MDIChildCount - 1 do begin ChildForm := MainForm.MDIChildren[I]; if ChildForm.HandleAllocated and (((ChildForm.Handle = W) and Maximized) or ((ChildForm.Handle <> W) and IsZoomed(ChildForm.Handle))) then begin HasMaxChild := True; Break; end; end; ActiveMDIChild := MainForm.ActiveMDIChild; end; VisibilityChanged := False; UpdateVisibleEnabled(TSpTBXMDIHandler(Owner).FSystemMenuItem, True); UpdateVisibleEnabled(FMinimizeItem, (ActiveMDIChild = nil) or (GetWindowLong(ActiveMDIChild.Handle, GWL_STYLE) and WS_MINIMIZEBOX <> 0)); UpdateVisibleEnabled(FRestoreItem, True); UpdateVisibleEnabled(FCloseItem, True); if VisibilityChanged and Assigned((Owner as TSpTBXMDIHandler).FToolbar) then begin TSpTBXMDIHandler(Owner).FToolbar.View.InvalidatePositions; TSpTBXMDIHandler(Owner).FToolbar.View.TryValidatePositions; end; end; procedure TSpTBXMDIButtonsItem.ItemClick(Sender: TObject); var MainForm, ChildForm: TForm; Cmd: WPARAM; SendTo: HWND; begin MainForm := Application.MainForm; if Assigned(MainForm) then begin ChildForm := MainForm.ActiveMDIChild; if Assigned(ChildForm) then begin // Make sure we send the message to a maximized window SendTo := ChildForm.Handle; while not IsZoomed(SendTo) do begin SendTo := GetWindow(SendTo, GW_HWNDNEXT); if SendTo = 0 then Exit; end; if Sender = FRestoreItem then Cmd := SC_RESTORE else if Sender = FCloseItem then Cmd := SC_CLOSE else Cmd := SC_MINIMIZE; SendMessage(SendTo, WM_SYSCOMMAND, Cmd, GetMessagePos); end; end; end; procedure TSpTBXMDIButtonsItem.InvalidateSystemMenuItem; var View: TTBView; begin if Assigned((Owner as TSpTBXMDIHandler).FToolbar) then begin View := TSpTBXMDIHandler(Owner).FToolbar.View; View.Invalidate(View.Find(TSpTBXMDIHandler(Owner).FSystemMenuItem)); end; end; //WMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWM { TSpTBXMDIWindowItem } constructor TSpTBXMDIWindowItem.Create(AOwner: TComponent); var Form: TForm; begin inherited; ItemStyle := ItemStyle + [tbisEmbeddedGroup]; Caption := STBMDIWindowItemDefCaption; FWindowMenu := TMenuItem.Create(Self); if not (csDesigning in ComponentState) then begin { Need to set WindowMenu before MDI children are created. Otherwise the list incorrectly shows the first 9 child windows, even if window 10+ is active. } Form := Application.MainForm; if (Form = nil) and (Screen.FormCount > 0) then Form := Screen.Forms[0]; SetForm(Form); end; end; procedure TSpTBXMDIWindowItem.GetChildren(Proc: TGetChildProc; Root: TComponent); begin // Do nothing end; procedure TSpTBXMDIWindowItem.Notification(AComponent: TComponent; Operation: TOperation); begin inherited; if (Operation = opRemove) and (AComponent = FForm) then SetForm(nil); end; procedure TSpTBXMDIWindowItem.SetForm(AForm: TForm); begin if FForm <> AForm then begin if Assigned(FForm) and (FForm.WindowMenu = FWindowMenu) then FForm.WindowMenu := nil; FForm := AForm; if Assigned(FForm) then FForm.FreeNotification(Self); end; if Assigned(FForm) then FForm.WindowMenu := FWindowMenu; end; procedure TSpTBXMDIWindowItem.EnabledChanged; var I: Integer; begin inherited; for I := 0 to Count-1 do Items[I].Enabled := Enabled; end; procedure TSpTBXMDIWindowItem.InitiateAction; var MainForm: TForm; I: Integer; M: HMENU; Item: TSpTBXItem; ItemCount: Integer; Buf: array[0..1023] of Char; begin inherited; if csDesigning in ComponentState then Exit; MainForm := Application.MainForm; if Assigned(MainForm) then SetForm(MainForm); if FForm = nil then Exit; if FForm.ClientHandle <> 0 then { This is needed, otherwise windows selected on the More Windows dialog don't move back into the list } SendMessage(FForm.ClientHandle, WM_MDIREFRESHMENU, 0, 0); M := FWindowMenu.Handle; ItemCount := GetMenuItemCount(M) - 1; if ItemCount < 0 then ItemCount := 0; while Count < ItemCount do begin Item := TSpTBXItem.Create(Self); Item.Enabled := Enabled; Item.OnClick := ItemClick; Add(Item); end; while Count > ItemCount do Items[Count - 1].Free; for I := 0 to ItemCount - 1 do begin Item := TSpTBXItem(Items[I]); Item.Tag := GetMenuItemID(M, I+1); if GetMenuString(M, I+1, Buf, SizeOf(Buf), MF_BYPOSITION) = 0 then Buf[0] := #0; Item.Caption := Buf; Item.Checked := GetMenuState(M, I+1, MF_BYPOSITION) and MF_CHECKED <> 0; end; if Assigned(FOnUpdate) then FOnUpdate(Self); end; procedure TSpTBXMDIWindowItem.ItemClick(Sender: TObject); var Form: TForm; begin Form := Application.MainForm; if Assigned(Form) then PostMessage(Form.Handle, WM_COMMAND, TTBCustomItem(Sender).Tag, 0); end; //WMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWM { TSpTBXMRUListItem } procedure TSpTBXMRUListItem.ClickHandler(Sender: TObject); var I: Integer; A: TSpTBXMRUItem; begin if Sender is TSpTBXMRUItem then begin A := TSpTBXMRUItem(Sender); I := IndexOf(A); if I > 0 then Move(I, 0); MRUUpdateCaptions; if Assigned(FOnClick) then FOnClick(Self, A.MRUString); end; end; constructor TSpTBXMRUListItem.Create(AOwner: TComponent); begin inherited; ItemStyle := ItemStyle + [tbisEmbeddedGroup]; Caption := STBMRUListItemDefCaption; Options := Options + [tboShowHint]; FMaxItems := 4; FHidePathExtension := True; end; procedure TSpTBXMRUListItem.GetMRUFilenames(MRUFilenames: TStrings); var I: Integer; begin MRUFilenames.Clear; for I := 0 to Count - 1 do if Items[I] is TSpTBXMRUItem then MRUFilenames.Add(TSpTBXMRUItem(Items[I]).MRUString); end; function TSpTBXMRUListItem.IndexOfMRU(Filename: WideString): Integer; var I: Integer; begin Result := -1; for I := 0 to Count - 1 do if Items[I] is TSpTBXMRUItem then if SpSameText(TSpTBXMRUItem(Items[I]).MRUString, Filename) then begin Result := I; Break; end; end; function TSpTBXMRUListItem.MRUAdd(Filename: WideString): Integer; var A: TSpTBXMRUItem; I: Integer; begin Result := -1; I := IndexOfMRU(Filename); if I > -1 then begin // If Filename is already in the MRU list, move it to the top Move(I, 0); MRUUpdateCaptions; end else begin // Add the new Filename, if it exceeds the MaxItems limit delete the bottom items A := TSpTBXMRUItem.Create(Self); A.MRUString := Filename; A.Hint := Filename; A.OnClick := ClickHandler; Insert(0, A); while Count > FMaxItems do Items[Count - 1].Free; MRUUpdateCaptions; Result := 0; end; end; function TSpTBXMRUListItem.MRUClick(Filename: WideString): Boolean; var I: Integer; begin Result := False; I := IndexOfMRU(Filename); if I > -1 then begin Items[I].Click; Result := True; end; end; procedure TSpTBXMRUListItem.MRURemove(Filename: WideString); var I: Integer; begin I := IndexOfMRU(Filename); if I > -1 then begin Items[I].Free; MRUUpdateCaptions; end; end; procedure TSpTBXMRUListItem.MRUUpdateCaptions; var I: Integer; A: TSpTBXMRUItem; S: WideString; begin for I := 0 to Count - 1 do if Items[I] is TSpTBXMRUItem then begin A := TSpTBXMRUItem(Items[I]); S := A.MRUString; if FHidePathExtension then begin {$IFDEF UNICODE} S := ExtractFileName(S); {$ELSE} S := TntSysUtils.WideExtractFileName(S); {$ENDIF} end; A.Caption := '&' + IntToStr(I + 1) + ' ' + S; end; end; procedure TSpTBXMRUListItem.LoadFromIni(Ini: TCustomIniFile; const Section: string); var I: Integer; S: WideString; begin Clear; for I := FMaxItems downto 1 do begin S := Ini.ReadString(Section, IntToStr(I), ''); {$IFNDEF UNICODE} S := UTF8Decode(S); {$ENDIF} if S <> '' then MRUAdd(S); end; end; procedure TSpTBXMRUListItem.SaveToIni(Ini: TCustomIniFile; const Section: string); var I: Integer; A: TSpTBXMRUItem; S: string; L: TStringList; begin {$IFDEF UNICODE} // If the IniFile doesn't exist create it with Unicode encoding // otherwise we can't write Unicode strings. if (Ini is TIniFile) and not FileExists(Ini.FileName) then begin L := TStringList.Create; try L.SaveToFile(Ini.FileName, TEncoding.Unicode); finally L.Free; end; end; {$ENDIF} for I := 1 to FMaxItems do begin if I <= Count then begin A := TSpTBXMRUItem(Items[I - 1]); {$IFDEF UNICODE} S := A.MRUString; {$ELSE} S := UTF8Encode(A.MRUString); {$ENDIF} Ini.WriteString(Section, IntToStr(I), S); end else Ini.DeleteKey(Section, IntToStr(I)); end; end; procedure TSpTBXMRUListItem.SetHidePathExtension(const Value: Boolean); begin if FHidePathExtension <> Value then begin FHidePathExtension := Value; MRUUpdateCaptions; end; end; procedure TSpTBXMRUListItem.SetMaxItems(const Value: Integer); begin if FMaxItems <> Value then begin FMaxItems := Value; if Count > FMaxItems then begin while Count > FMaxItems do Items[Count - 1].Free; MRUUpdateCaptions; end; end; end; end.