1 {
2   Copyright (C) 2007 Graeme Geldenhuys (graemeg@gmail.com)
3 
4   This library is free software; you can redistribute it and/or modify it
5   under the terms of the GNU Library General Public License as published by
6   the Free Software Foundation; either version 2 of the License, or (at your
7   option) any later version.
8 
9   This program is distributed in the hope that it will be useful, but WITHOUT
10   ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11   FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License
12   for more details.
13 
14   You should have received a copy of the GNU Library General Public License
15   along with this library; if not, write to the Free Software Foundation,
16   Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1335, USA.
17 }
18 
19 unit ToolbarConfig;
20 
21 {$mode objfpc}{$H+}
22 
23 interface
24 
25 uses
26   Classes, SysUtils,
27   // LCL
28   LCLProc, LclIntf, Controls, Forms, Graphics, ExtCtrls, Buttons, StdCtrls,
29   ComCtrls, Menus, ButtonPanel,
30   // LazControls
31   TreeFilterEdit,
32   // LazUtils
33   Laz2_XMLCfg,
34   // IdeIntf
35   ToolBarIntf, IDEImagesIntf, IDEWindowIntf,
36   // IDE
37   LazarusIDEStrConsts;
38 
39 const
40   IDEToolBarConfigVersion = 1;  // File version in configuration.
41 
42 type
43   { TToolBarConfig }
44 
45   TToolBarConfig = class(TForm)
46     btnAdd: TSpeedButton;
47     btnAddDivider: TSpeedButton;
48     btnCancel: TButton;
49     btnHelp: TBitBtn;
50     btnMoveDown: TSpeedButton;
51     btnMoveUp: TSpeedButton;
52     btnOK: TButton;
53     btnRemove: TSpeedButton;
54     FilterEdit: TTreeFilterEdit;
55     lblMenuTree: TLabel;
56     lblToolbar: TLabel;
57     lblSelect: TLabel;
58     lvToolbar: TListView;
59     miAll: TMenuItem;
60     miCustom: TMenuItem;
61     miDebug: TMenuItem;
62     miDesign: TMenuItem;
63     miHTML: TMenuItem;
64     pnlButtons: TButtonPanel;
65     Splitter1: TSplitter;
66     TV: TTreeView;
67     procedure btnHelpClick(Sender: TObject);
68     procedure FormClose(Sender: TObject; var {%H-}CloseAction: TCloseAction);
69     procedure FormCreate(Sender: TObject);
70     procedure FormDestroy(Sender: TObject);
71     procedure lvToolbarDblClick(Sender: TObject);
72     procedure lvToolbarEnterExit(Sender: TObject);
73     procedure TVDblClick(Sender: TObject);
74     procedure UpdateButtonsState;
75     procedure btnAddClick(Sender: TObject);
76     procedure btnAddDividerClick(Sender: TObject);
77     procedure btnMoveDownClick(Sender: TObject);
78     procedure btnMoveUpClick(Sender: TObject);
79     procedure btnRemoveClick(Sender: TObject);
80     procedure lvToolbarSelectItem(Sender: TObject; {%H-}Item: TListItem;
81       {%H-}Selected: Boolean);
82     procedure TVSelectionChanged(Sender: TObject);
83   private
84     Image: TBitMap;
85     defImageIndex: integer;
86     procedure AddCommand;
87     procedure AddDivider;
88     procedure AddTailItem;
89     procedure AddToolBarItem(CmdItem: TIDEButtonCommand);
90     procedure InsertItem(Item: TListItem);
91     procedure MoveUpDown(aOffset: integer);
NewLvItemnull92     function NewLvItem(aCaption: string): TListItem;
93     procedure RemoveCommand;
94     procedure SetupCaptions;
95     procedure LoadCategories;
96     procedure SortCategories(ACtgList: TStrings);
97     procedure AddMenuItem(ParentNode: TTreeNode; CmdItem: TIDEButtonCommand);
RootNodeCaptionnull98     function RootNodeCaption(CmdItem: TIDEButtonCommand): string;
99   public
100     procedure LoadSettings(SL: TStringList);
101     procedure SaveSettings(SL: TStringList);
102   end;
103 
104   { TIDEToolBarOptionsBase }
105 
106   TIDEToolBarOptionsBase = class
107   private
108     FButtonNames: TStringList;
109   protected
110     procedure LoadButtonNames(XMLConfig: TXMLConfig; SubPath: String);
111     procedure SaveButtonNames(XMLConfig: TXMLConfig; SubPath: String);
112   public
113     constructor Create;
114     destructor Destroy; override;
115     procedure Clear;
Equalsnull116     function Equals(Opts: TIDEToolBarOptionsBase): boolean; overload;
117     procedure Assign(Source: TIDEToolBarOptionsBase);
118     //procedure Load(XMLConfig: TXMLConfig; Path: String);
119     //procedure Save(XMLConfig: TXMLConfig; Path: String);
120   published
121     property ButtonNames: TStringList read FButtonNames; // write FButtonNames;
122   end;
123 
124   { TIDEToolbarBase }
125 
126   TIDEToolbarBase = class(TComponent)
127   private
128   protected
129     FToolBar: TToolBar;
130     procedure AddButton(ACommand: TIDEButtonCommand);
131     procedure AddDivider;
132     procedure CopyFromOptions(Options: TIDEToolBarOptionsBase);
133     procedure PositionAtEnd(AToolBar: TToolBar; AButton: TToolButton);
134     procedure PostCopyOptions; virtual;
135   public
136     //constructor Create(AOwner: TComponent); override;
137     //destructor Destroy; override;
138     property ToolBar: TToolBar read FToolBar;
139   end;
140 
141 const
142   cIDEToolbarDivider = '---------------';
143   cTailItemCaption = '                                             ';
144 
ShowToolBarConfignull145 function ShowToolBarConfig(aNames: TStringList): TModalResult;
146 
147 
148 implementation
149 
150 {$R *.lfm}
151 
ShowToolBarConfignull152 function ShowToolBarConfig(aNames: TStringList): TModalResult;
153 var
154   Conf: TToolBarConfig;
155 begin
156   Conf := TToolBarConfig.Create(Nil);
157   try
158     if Assigned(aNames) then
159       Conf.LoadSettings(aNames);
160     Result := Conf.ShowModal;
161     if (Result = mrOK) and Assigned(aNames) then
162       Conf.SaveSettings(aNames);
163   finally
164     Conf.Free;
165   end;
166 end;
167 
168 { TToolBarConfig }
169 
170 procedure TToolBarConfig.FormCreate(Sender: TObject);
171 begin
172   inherited;
173   pnlButtons.Color := clBtnFace;
174   lblSelect.Caption := '';
175   // load button images
176   IDEImages.AssignImage(btnAdd, 'arrow__darkgreen_right');
177   IDEImages.AssignImage(btnRemove, 'arrow__darkred_left');
178   IDEImages.AssignImage(btnMoveUp, 'arrow__darkgreen_up');
179   IDEImages.AssignImage(btnMoveDown, 'arrow__darkgreen_down');
180   //IDEImages.AssignImage(btnAddDivider, 'menu_divider16');  // uncomment if 'menu_divider16' exists (currently not)
181 
182   btnAddDivider.Caption := '---';
183   btnAdd.Hint       := lisCoolBarAddSelected;
184   btnRemove.Hint    := lisCoolBarRemoveSelected;
185   btnMoveUp.Hint    := lisCoolBarMoveSelectedUp;
186   btnMoveDown.Hint  := lisCoolBarMoveSelectedDown;
187   btnAddDivider.Hint:= lisCoolBarAddDivider;
188 
189   TV.Images := IDEImages.Images_16;
190   lvToolbar.SmallImages := IDEImages.Images_16;
191   // default image to be used when none is available
192   defImageIndex := IDEImages.LoadImage('execute');
193 
194   Image := TBitmap.Create;
195   SetupCaptions;
196   LoadCategories;
197   IDEDialogLayoutList.ApplyLayout(Self);
198 end;
199 
200 procedure TToolBarConfig.FormClose(Sender: TObject; var CloseAction: TCloseAction);
201 begin
202   IDEDialogLayoutList.SaveLayout(Self);
203 end;
204 
205 procedure TToolBarConfig.FormDestroy(Sender: TObject);
206 begin
207   Image.Free;
208 end;
209 
210 procedure TToolBarConfig.lvToolbarDblClick(Sender: TObject);
211 begin
212   RemoveCommand;
213 end;
214 
215 procedure TToolBarConfig.lvToolbarEnterExit(Sender: TObject);
216 begin
217   UpdateButtonsState;
218 end;
219 
220 procedure TToolBarConfig.TVDblClick(Sender: TObject);
221 begin
222   AddCommand;
223 end;
224 
225 procedure TToolBarConfig.btnHelpClick(Sender: TObject);
226 begin
227   OpenUrl('http://wiki.freepascal.org/IDE_Window:_Toolbar_Config');
228 end;
229 
230 procedure TToolBarConfig.UpdateButtonsState;
231 var
232   I: Integer;
233 begin
234   I := lvToolbar.ItemIndex;
235   btnAdd.Enabled := Assigned(TV.Selected) and Assigned(TV.Selected.Data);
236   btnRemove.Enabled := (I>-1) and (I<lvToolbar.Items.Count-1);
237   btnMoveUp.Enabled := (I>0) and (I<lvToolbar.Items.Count-1);
238   btnMoveDown.Enabled := (I>-1) and (I<lvToolbar.Items.Count-2);
239   btnAddDivider.Enabled := True;
240 end;
241 
242 procedure TToolBarConfig.TVSelectionChanged(Sender: TObject);
243 begin
244   UpdateButtonsState;
245 end;
246 
247 procedure TToolBarConfig.InsertItem(Item: TListItem);
248 begin
249   lvToolbar.ItemIndex := -1;
250   lvToolbar.Selected := nil;
251   if Item.Index < lvToolbar.Items.Count then
252     lvToolbar.ItemIndex := Item.Index+1
253   else
254     lvToolbar.ItemIndex := Item.Index;
255 end;
256 
257 procedure TToolBarConfig.btnAddClick(Sender: TObject);
258 begin
259   AddCommand;
260 end;
261 
NewLvItemnull262 function TToolBarConfig.NewLvItem(aCaption: string): TListItem;
263 var
264   I: Integer;
265 begin
266   I := lvToolbar.ItemIndex;
267   if I = -1 then
268     I := lvToolbar.Items.Count-1;    // Add before the last empty item.
269   Result := lvToolbar.Items.Insert(I);
270   Result.Caption := aCaption;
271 end;
272 
273 procedure TToolBarConfig.AddCommand;
274 var
275   Node: TTreeNode;
276   CmdCaption: string;
277   lvItem: TListItem;
278 begin
279   Node := TV.Selected;
280   if (Node = Nil) or (Node.Data = Nil) then
281     Exit;
282   CmdCaption := TIDEButtonCommand(Node.Data).Caption;
283   DeleteAmpersands(CmdCaption);
284   lvItem := NewLvItem(CmdCaption);
285   lvItem.Data := Node.Data;
286   if Node.ImageIndex > -1 then
287     lvItem.ImageIndex := Node.ImageIndex
288   else
289     lvItem.ImageIndex := defImageIndex;
290   InsertItem(lvItem);                  // Add the newly created item to ListView.
291   // Update selection in TreeView.
292   Node := TV.Selected.GetNext;
293   TV.Selected.Visible := False;
294   if Node <> nil then
295     TV.Selected := Node;
296   UpdateButtonsState;
297 end;
298 
299 procedure TToolBarConfig.RemoveCommand;
300 Var
301   Cmd: TIDEButtonCommand;
302   Node: TTreeNode;
303   I: Integer;
304 begin
305   I := lvToolbar.ItemIndex;
306   if (I<0) or (I>=lvToolbar.Items.Count-1) then Exit;
307   Cmd := TIDEButtonCommand(lvToolbar.Items[I].Data);
308   lvToolbar.Items.Delete(I);
309   {$IF DEFINED(LCLQt) or DEFINED(LCLQt5)}
310   lvToolbar.ItemIndex := -1;     // Try to make LCLQt behave.
311   lvToolbar.ItemIndex := I;
312   {$ENDIF}
313   lvToolbar.Selected := lvToolbar.Items[I];
314   // Show the command as available again in TreeView.
315   if Assigned(Cmd) then
316   begin
317     Node:= TV.Items.FindNodeWithData(Cmd);
318     if Node<>nil then
319       Node.Visible:= True;
320   end;
321   UpdateButtonsState;
322 end;
323 
324 procedure TToolBarConfig.btnAddDividerClick(Sender: TObject);
325 var
326   lvItem: TListItem;
327 begin
328   lvItem := NewLvItem(cIDEToolbarDivider);
329   lvItem.ImageIndex := -1;
330   InsertItem(lvItem);
331   UpdateButtonsState;
332 end;
333 
334 procedure TToolBarConfig.btnRemoveClick(Sender: TObject);
335 begin
336   RemoveCommand;
337 end;
338 
339 procedure TToolBarConfig.lvToolbarSelectItem(Sender: TObject;
340   Item: TListItem; Selected: Boolean);
341 var
342   RealCount: integer;
343 begin
344   UpdateButtonsState;
345   // Update selection status label.
346   RealCount := lvToolbar.Items.Count-1;
347   if lvToolbar.ItemIndex < RealCount then
348     lblSelect.Caption := Format('%d / %d', [lvToolbar.ItemIndex+1, RealCount])
349   else
350     lblSelect.Caption := Format('%d+ / %d', [lvToolbar.ItemIndex, RealCount])
351 end;
352 
353 procedure TToolBarConfig.MoveUpDown(aOffset: integer);
354 var
355   Index1,Index2: Integer;
356 begin
357   Index1 := lvToolbar.ItemIndex;
358   Index2 := Index1 + aOffset;
359   lvToolbar.Items.Exchange(Index1,Index2);
360   lvToolbar.Items[Index1].Selected := False;
361   lvToolbar.Items[Index2].Selected := False;
362   lvToolbar.ItemIndex:= -1;
363   lvToolbar.Selected := Nil;
364   lvToolbar.ItemIndex:= Index2;
365   lvToolbar.Selected := lvToolbar.Items[Index2];
366 end;
367 
368 procedure TToolBarConfig.btnMoveDownClick(Sender: TObject);
369 begin
370   if (lvToolbar.ItemIndex<0) or (lvToolbar.ItemIndex>=lvToolbar.Items.Count-2) then
371     Exit;
372   MoveUpDown(1);
373 end;
374 
375 procedure TToolBarConfig.btnMoveUpClick(Sender: TObject);
376 begin
377   if (lvToolbar.ItemIndex<1) or (lvToolbar.ItemIndex>=lvToolbar.Items.Count-1) then
378     Exit;
379   MoveUpDown(-1);
380 end;
381 
382 procedure TToolBarConfig.SetupCaptions;
383 begin
384   Caption             := lisToolbarConfiguration;
385   lblMenuTree.Caption := lisCoolbarAvailableCommands;
386   lblToolbar.Caption  := lisCoolbarToolbarCommands;
387 end;
388 
389 procedure TToolBarConfig.LoadCategories;
390 var
391   i, l: integer;
392   xCategory: TIDEToolButtonCategory;
393   xCaption: string;
394   Node: TTreeNode;
395   SortedCtgList: TStringList;
396 begin
397   TV.Items.BeginUpdate;
398   SortedCtgList := TStringList.Create;
399   try
400     SortedCtgList.OwnsObjects := False;
401     for i := 0 to IDEToolButtonCategories.Count-1 do
402     begin
403       xCategory := IDEToolButtonCategories[i];
404       SortedCtgList.AddObject(xCategory.Description, xCategory);
405     end;
406     SortCategories(SortedCtgList);
407 
408     TV.Items.Clear;
409     for i := 0 to SortedCtgList.Count-1 do
410     begin
411       xCaption := SortedCtgList[i];
412       xCategory := SortedCtgList.Objects[i] as TIDEToolButtonCategory;
413       DeleteAmpersands(xCaption);
414       Node := TV.Items.AddChild(nil, Format('%s', [xCaption]));
415       for l := 0 to xCategory.ButtonCount-1 do
416         AddMenuItem(Node, xCategory.Buttons[l]);
417     end;
418   finally
419     SortedCtgList.Free;
420     TV.Items.EndUpdate;
421   end;
422 end;
423 
424 procedure TToolBarConfig.SortCategories(ACtgList: TStrings);
425 var
426   NewIndex: Integer;
427 
428   procedure MoveItem(s: String);
429   var
430     OldIndex: Integer;
431   begin
432     OldIndex := ACtgList.IndexOf(s);
433     if (OldIndex<0) or (NewIndex>=ACtgList.Count) then Exit;
434     ACtgList.Move(OldIndex, NewIndex);
435     Inc(NewIndex);
436   end;
437 
438 begin
439   NewIndex := 0;
440   MoveItem(srkmCatFileMenu);
441   MoveItem(srkmCatCmdCmd);
442   MoveItem(srkmCatSelection);
443   MoveItem(srkmCatMacroRecording);
444   MoveItem(srkmCatSearchReplace);
445   MoveItem(srkmCatMarker);
446   MoveItem(srkmCatViewMenu);
447   MoveItem(srkmCatCodeTools);
448   MoveItem(srkmCatEditing);
449   MoveItem(srkmCatProjectMenu);
450   MoveItem(srkmCatRunMenu);
451   MoveItem(srkmCatPackageMenu);
452   MoveItem(srkmCatToolMenu);
453   MoveItem(srkmCatSrcNoteBook);
454   MoveItem(srkmCarHelpMenu);
455 end;
456 
457 procedure TToolBarConfig.AddMenuItem(ParentNode: TTreeNode; CmdItem: TIDEButtonCommand);
458 var
459   Node: TTreeNode;
460 begin
461   if CmdItem.Caption = '-' then Exit;   // divider
462   Node := TV.Items.AddChild(ParentNode, Format('%s', [CmdItem.GetCaptionWithShortCut]));
463   Node.ImageIndex := CmdItem.ImageIndex;
464   Node.SelectedIndex := CmdItem.ImageIndex;
465   Node.Data := CmdItem;
466 end;
467 
TToolBarConfig.RootNodeCaptionnull468 function TToolBarConfig.RootNodeCaption(CmdItem: TIDEButtonCommand): string;
469 begin
470   case CmdItem.Caption of
471     'IDEMainMenu':        Result := lisCoolbarIDEMainMenu;    // mnuMain
472     'SourceTab':          Result := lisCoolbarSourceTab;      // SourceTabMenuRootName
473     'SourceEditor':       Result := lisCoolbarSourceEditor;   // SourceEditorMenuRootName
474     'Messages':           Result := lisCoolbarMessages;       // MessagesMenuRootName
475     'Code Explorer':      Result := lisCoolbarCodeExplorer;   // CodeExplorerMenuRootName
476     'CodeTemplates':      Result := lisCoolbarCodeTemplates;  // CodeTemplatesMenuRootName
477     'Designer':           Result := lisCoolbarDesigner;       // DesignerMenuRootName
478     'PackageEditor':      Result := lisCoolbarPackageEditor;  // PackageEditorMenuRootName
479     'PackageEditorFiles': Result := lisCoolbarPackageEditorFiles // PackageEditorMenuFilesRootName
480     else                  Result := CmdItem.Caption;
481   end;
482 end;
483 
484 procedure TToolBarConfig.AddToolBarItem(CmdItem: TIDEButtonCommand);
485 Var
486   Node: TTreeNode;
487   lvItem: TListItem;
488 begin
489   if CmdItem=Nil then Exit;
490   lvItem := lvToolbar.Items.Add;
491   lvItem.Caption := CmdItem.GetCaptionWithShortCut;
492   lvItem.Data := CmdItem;
493   if CmdItem.ImageIndex > -1 then
494     lvItem.ImageIndex := CmdItem.ImageIndex
495   else
496     lvItem.ImageIndex := defImageIndex;
497   Node := TV.Items.FindNodeWithData(CmdItem);
498   if Node<>nil then
499     Node.Visible := False;
500 end;
501 
502 procedure TToolBarConfig.AddDivider;
503 var
504   lvItem: TListItem;
505 begin
506   lvItem := lvToolbar.Items.Add;
507   lvItem.Caption := cIDEToolbarDivider;
508   lvItem.ImageIndex := -1;
509 end;
510 
511 procedure TToolBarConfig.AddTailItem;
512 // An extra item at the end of list so that new command can be inserted there.
513 // TToolBarConfig.SaveSettings excludes this item from saving.
514 // In lvToolbar this item may only be selected, any actions with it are prohibited.
515 var
516   lvItem: TListItem;
517 begin
518   lvItem := lvToolbar.Items.Add;
519   lvItem.Caption := cTailItemCaption;
520 end;
521 
522 procedure TToolBarConfig.LoadSettings(SL: TStringList);
523 var
524   I: Integer;
525   Value: string;
526   Cmd: TIDEButtonCommand;
527 begin
528   for I := 0 to SL.Count - 1 do
529   begin
530     Value := SL[I];
531     if Value = '' then Continue;
532     if Value = cIDEToolbarDivider then
533       AddDivider                // Add divider.
534     else
535     begin
536       Cmd := IDEToolButtonCategories.FindItemByMenuPathOrName(Value);
537       AddToolBarItem(Cmd);      // Add command.
538       if Value <> SL[I] then
539         DebugLn(['TToolBarConfig.LoadSettings: SL[I]=', SL[I], ', Value=', Value]);
540       SL[I] := Value;
541     end;
542   end;
543   AddTailItem;                  // Add tail item at the end.
544   lvToolbar.ItemIndex:=lvToolbar.Items.Count-1;
545 end;
546 
547 procedure TToolBarConfig.SaveSettings(SL: TStringList);
548 var
549   lvItem: TListItem;
550   Cmd: TIDEButtonCommand;
551   I: Integer;
552 begin
553   SL.Clear;
554   for I := 0 to lvToolbar.Items.Count - 2 do  // excluding tail item
555   begin
556     lvItem := lvToolbar.Items[I];
557     Cmd := TIDEButtonCommand(lvItem.Data);
558     if lvItem.Caption = cIDEToolbarDivider then
559       SL.Add(cIDEToolbarDivider)
560     else begin
561       Assert(Assigned(Cmd), 'TToolBarConfig.SaveSettings: Cmd = Nil.');
562       SL.Add(Cmd.Name);
563     end;
564   end;
565 end;
566 
567 { TIDEToolBarOptionsBase }
568 
569 constructor TIDEToolBarOptionsBase.Create;
570 begin
571   FButtonNames := TStringList.Create;
572 end;
573 
574 destructor TIDEToolBarOptionsBase.Destroy;
575 begin
576   FButtonNames.Free;
577   inherited Destroy;
578 end;
579 
580 procedure TIDEToolBarOptionsBase.Clear;
581 begin
582   FButtonNames.Clear;
583 end;
584 
Equalsnull585 function TIDEToolBarOptionsBase.Equals(Opts: TIDEToolBarOptionsBase): boolean;
586 begin
587   Result := FButtonNames.Equals(Opts.FButtonNames);
588 end;
589 
590 procedure TIDEToolBarOptionsBase.Assign(Source: TIDEToolBarOptionsBase);
591 begin
592   FButtonNames.Assign(Source.FButtonNames);
593 end;
594 
595 procedure TIDEToolBarOptionsBase.LoadButtonNames(XMLConfig: TXMLConfig; SubPath: String);
596 var
597   ButtonCount: Integer;
598   ButtonName: string;
599   I, FileVersion: Integer;
600 begin
601   FileVersion := XMLConfig.GetValue(SubPath + 'Version', 0);
602   ButtonCount := XMLConfig.GetValue(SubPath + 'Count', 0);
603   if (FileVersion < 1) and (ButtonCount = 0) then  // Old format
604     ButtonCount := XMLConfig.GetValue(SubPath + 'ButtonCount/Value', 0);
605   for I := 1 to ButtonCount do
606   begin
607     ButtonName := XMLConfig.GetValue(SubPath + 'Button' + IntToStr(I) + '/Name', '');
608     if (FileVersion < 1) and (ButtonName = '') then  // Old format
609       ButtonName := XMLConfig.GetValue(SubPath + 'Buttons/Name' + IntToStr(I) + '/Value', '');
610     if ButtonName <> '' then
611       ButtonNames.Add(ButtonName);
612   end;
613 end;
614 
615 procedure TIDEToolBarOptionsBase.SaveButtonNames(XMLConfig: TXMLConfig; SubPath: String);
616 var
617   I: Integer;
618 begin
619   XMLConfig.SetValue(SubPath + 'Version', IDEToolBarConfigVersion);
620   XMLConfig.SetDeleteValue(SubPath + 'Count', ButtonNames.Count, 0);
621   for I := 0 to ButtonNames.Count-1 do
622     XMLConfig.SetDeleteValue(SubPath + 'Button' + IntToStr(I+1) + '/Name', ButtonNames[I], '');
623 end;
624 
625 { TIDEToolbarBase }
626 {                           For future needs ...
627 constructor TIDEToolbarBase.Create(AOwner: TComponent);
628 begin
629   inherited Create(AOwner);
630 end;
631 
632 destructor TIDEToolbarBase.Destroy;
633 begin
634   inherited Destroy;
635 end;
636 }
637 procedure TIDEToolbarBase.AddButton(ACommand: TIDEButtonCommand);
638 var
639   B: TIDEToolButton;
640 begin
641   B := ACommand.ToolButtonClass.Create(FToolBar);
642   B.Hint := ACommand.GetHintOrCaptionWithShortCut;
643   B.Enabled := ACommand.Enabled;
644   // If we have a image, use it. Otherwise supply a default.
645   if ACommand.ImageIndex <> -1 then
646     B.ImageIndex := ACommand.ImageIndex
647   else
648     B.ImageIndex := IDEImages.LoadImage('execute');
649   B.Style := tbsButton;
650   B.Item := ACommand;
651   PositionAtEnd(FToolBar, B);
652   ACommand.ToolButtonAdded(B);
653 end;
654 
655 procedure TIDEToolbarBase.AddDivider;
656 var
657   B: TToolButton;
658 begin
659   B := TToolButton.Create(FToolBar);
660   B.Style := tbsDivider;
661   PositionAtEnd(FToolBar, B);
662 end;
663 
664 procedure TIDEToolbarBase.CopyFromOptions(Options: TIDEToolBarOptionsBase);
665 var
666   Cmd: TIDEButtonCommand;
667   ButtonName: string;
668   i: Integer;
669 begin
670   FToolBar.BeginUpdate;
671   try
672     for i := 0 to Options.ButtonNames.Count-1 do
673     begin
674       ButtonName := Options.ButtonNames[i];
675       if ButtonName = cIDEToolbarDivider then
676         AddDivider
677       else
678       begin
679         Cmd := IDEToolButtonCategories.FindItemByMenuPathOrName(ButtonName);
680         Options.ButtonNames[i] := ButtonName;
681         if Assigned(Cmd) then
682           AddButton(Cmd);
683       end;
684     end;
685     PostCopyOptions;
686   finally
687     FToolBar.EndUpdate;
688   end;
689 end;
690 
691 procedure TIDEToolbarBase.PositionAtEnd(AToolBar: TToolBar; AButton: TToolButton);
692 // position the button next to the last button
693 var
694   SiblingButton: TToolButton;
695 begin
696   if AToolBar.ButtonCount > 0 then
697   begin
698     SiblingButton := AToolBar.Buttons[AToolBar.ButtonCount-1];
699     AButton.SetBounds(SiblingButton.Left + SiblingButton.Width,
700       SiblingButton.Top, AButton.Width, AButton.Height);
701   end;
702   AButton.Parent := AToolBar;
703 end;
704 
705 procedure TIDEToolbarBase.PostCopyOptions;
706 begin
707   // Can be overridden.
708 end;
709 
710 end.
711 
712