1 {
2 *****************************************************************************
3 See the file COPYING.modifiedLGPL.txt, included in this distribution,
4 for details about the license.
5 *****************************************************************************
6
7 Author: Ondrej Pokorny
8
9 Abstract:
10 Interface to the IDE toolbars.
11 }
12 unit ToolBarIntf;
13
14 {$mode objfpc}{$H+}
15
16 interface
17
18 uses
19 Classes,
20 // LCL
21 Controls, ComCtrls, Menus,
22 // LazUtils
23 LazUTF8,
24 // IdeIntf
25 IDECommands, MenuIntf, IDEImagesIntf, SrcEditorIntf;
26
27 type
28 TIDEToolButton = class;
29 TIDEToolButtonClass = class of TIDEToolButton;
30 TIDEToolButtons = class;
31
32 TIDEButtonCommand = class(TIDESpecialCommand)
33 private
34 FTag: PtrInt;
35 FToolButtonClass: TIDEToolButtonClass;
36 FToolButtons: TIDEToolButtons;
37 protected
38 procedure SetName(const aName: string); override;
39 procedure SetEnabled(const aEnabled: Boolean); override;
40 procedure SetChecked(const aChecked: Boolean); override;
41 procedure SetCaption(aCaption: string); override;
42 procedure SetHint(const aHint: string); override;
43 procedure SetImageIndex(const aImageIndex: Integer); override;
44 procedure SetResourceName(const aResourceName: string); override;
45 procedure ShortCutsUpdated(const aShortCut, aShortCutKey2: TShortCut); override;
46 public
47 procedure ToolButtonAdded(const aBtn: TIDEToolButton);
48 public
49 constructor Create(const TheName: string); override;
50 destructor Destroy; override;
51 public
52 property Tag: PtrInt read FTag write FTag;
53 property ToolButtonClass: TIDEToolButtonClass read FToolButtonClass write FToolButtonClass;
54 property ToolButtons: TIDEToolButtons read FToolButtons;
55 end;
56
57 { TIDEToolButton }
58
59 TIDEToolButton = class(TToolButton)
60 private
61 FItem: TIDEButtonCommand;
62 protected
63 procedure DoOnShowHint(HintInfo: PHintInfo); override;
64 public
65 procedure DoOnAdded; virtual;
66
67 procedure Click; override;
68 property Item: TIDEButtonCommand read FItem write FItem;
69 end;
70
71 {%region *** Classes for toolbuttons with arrow *** }
72
73 TIDEToolButton_WithArrow_Class = class of TIDEToolButton_WithArrow;
74 TIDEToolButton_ButtonDrop_Class = class of TIDEToolButton_ButtonDrop;
75 TIDEToolButton_DropDown_Class = class of TIDEToolButton_DropDown;
76
77 { TIDEToolButton_WithArrow } // [ ][▼], [ ▼]
78
79 TIDEToolButton_WithArrow = class(TIDEToolButton)
80 private
GetSectionnull81 function GetSection: TIDEMenuSection;
82 protected
83 procedure DoOnMenuPopup(Sender: TObject);
84 procedure RefreshMenu; virtual;
85 property Section: TIDEMenuSection read GetSection;
86 public
87 constructor Create(AOwner: TComponent); override;
88 end;
89
90 { TIDEToolButton_DropDown } // [ ][▼]
91
92 TIDEToolButton_DropDown = class(TIDEToolButton_WithArrow)
93 public
94 procedure DoOnAdded; override;
95 end;
96
97 { TIDEToolButton_ButtonDrop } // [ ▼]
98
99 TIDEToolButton_ButtonDrop = class(TIDEToolButton_WithArrow)
100 protected
101 procedure PopUpAloneMenu(Sender: TObject);
102 public
103 procedure DoOnAdded; override;
104 end;
105 {%endregion}
106
107 TIDEToolButtonCategory = class
108 private
109 FButtons: TFPList;
110 FDescription: string;
111 FName: string;
GetButtonsnull112 function GetButtons(Index: Integer): TIDEButtonCommand;
113 public
114 constructor Create;
115 destructor Destroy; override;
116 public
117 property Description: string read FDescription write FDescription;
118 property Name: string read FName write FName;
ButtonCountnull119 function ButtonCount: Integer;
120 property Buttons[Index: Integer]: TIDEButtonCommand read GetButtons; default;
121 end;
122
123 TIDEToolButtonCategories = class
124 private
125 FButtonNames: TStringListUTF8Fast;
126 FCategories: TStringListUTF8Fast;
GetItemsnull127 function GetItems(Index: Integer): TIDEToolButtonCategory;
128 public
129 constructor Create;
130 destructor Destroy; override;
131 public
Countnull132 function Count: Integer;
AddButtonnull133 function AddButton(const aCategory: TIDEToolButtonCategory; const aName: string;
134 const aCommand: TIDECommand): TIDEButtonCommand; overload;
AddButtonnull135 function AddButton(const aCommand: TIDECommand): TIDEButtonCommand; overload;
FindCategorynull136 function FindCategory(const aName: string): TIDEToolButtonCategory;
FindCreateCategorynull137 function FindCreateCategory(const aName, aDescription: string): TIDEToolButtonCategory;
FindItemByNamenull138 function FindItemByName(const aName: string): TIDEButtonCommand;
FindItemByMenuPathOrNamenull139 function FindItemByMenuPathOrName(var aName: string): TIDEButtonCommand;
FindItemByCommandnull140 function FindItemByCommand(const aCommand: TIDECommand): TIDEButtonCommand;
FindItemByCommandnull141 function FindItemByCommand(const aCommand: Word): TIDEButtonCommand;
142 property Items[Index: Integer]: TIDEToolButtonCategory read GetItems; default;
143 end;
144
145 TIDEToolButtonsEnumerator = class
146 private
147 FList: TIDEToolButtons;
148 FPosition: Integer;
149 public
150 constructor Create(AButtons: TIDEToolButtons);
GetCurrentnull151 function GetCurrent: TIDEToolButton;
MoveNextnull152 function MoveNext: Boolean;
153 property Current: TIDEToolButton read GetCurrent;
154 end;
155
156 TIDEToolButtons = class(TComponent)
157 private
158 FList: TFPList;
GetCountnull159 function GetCount: Integer;
GetItemsnull160 function GetItems(Index: Integer): TIDEToolButton;
161 protected
162 procedure Notification(AComponent: TComponent; Operation: TOperation); override;
163 public
164 constructor Create(aOwner: TComponent); override;
165 destructor Destroy; override;
166 public
GetEnumeratornull167 function GetEnumerator: TIDEToolButtonsEnumerator;
168 procedure Add(const aBtn: TIDEToolButton);
169
170 property Count: Integer read GetCount;
171 property Items[Index: Integer]: TIDEToolButton read GetItems; default;
172 end;
173
174
175 var
176 IDEToolButtonCategories: TIDEToolButtonCategories = nil;// created by the IDE
177
178
RegisterIDEButtonCategorynull179 function RegisterIDEButtonCategory(const aName, aDescription: string): TIDEToolButtonCategory;
RegisterIDEButtonCommandnull180 function RegisterIDEButtonCommand(const aCategory: TIDEToolButtonCategory; const aName: string;
181 const aCommand: TIDECommand): TIDEButtonCommand;
RegisterIDEButtonCommandnull182 function RegisterIDEButtonCommand(const aCommand: TIDECommand): TIDEButtonCommand;
183
GetCommand_DropDownnull184 function GetCommand_DropDown(ACommand: Word; AMenuSection: TIDEMenuSection;
185 AButtonClass: TIDEToolButton_DropDown_Class=nil): TIDECommand;
GetCommand_ButtonDropnull186 function GetCommand_ButtonDrop(ACommand: Word; AMenuSection: TIDEMenuSection;
187 AButtonClass: TIDEToolButton_ButtonDrop_Class=nil): TIDECommand;
188
189
190 implementation
191
RegisterIDEButtonCategorynull192 function RegisterIDEButtonCategory(const aName, aDescription: string): TIDEToolButtonCategory;
193 begin
194 Result := IDEToolButtonCategories.FindCreateCategory(aName, aDescription);
195 end;
196
RegisterIDEButtonCommandnull197 function RegisterIDEButtonCommand(const aCategory: TIDEToolButtonCategory;
198 const aName: string; const aCommand: TIDECommand): TIDEButtonCommand;
199 begin
200 Result := IDEToolButtonCategories.AddButton(aCategory, aName, aCommand);
201 end;
202
RegisterIDEButtonCommandnull203 function RegisterIDEButtonCommand(const aCommand: TIDECommand): TIDEButtonCommand;
204 begin
205 Result := IDEToolButtonCategories.AddButton(aCommand);
206 end;
207
208 {%region *** Functions and classes for toolbuttons with arrow *** }
209
GetCommand_BtnWithArrownull210 function GetCommand_BtnWithArrow(ACommand: Word; AMenuSection: TIDEMenuSection; // not in Interface
211 AButtonClass: TIDEToolButton_WithArrow_Class): TIDECommand;
212 var
213 ButtonCommand: TIDEButtonCommand;
214 begin
215 Result:=IDECommandList.FindIDECommand(ACommand);
216 if Result=nil then
217 Exit(nil);
218 ButtonCommand:=RegisterIDEButtonCommand(Result);
219 ButtonCommand.ToolButtonClass:=AButtonClass;
220 if AButtonClass.InheritsFrom(TIDEToolButton_ButtonDrop) then
221 ButtonCommand.ImageIndex:=AMenuSection.ImageIndex;
222 ButtonCommand.Tag:=PtrInt(AMenuSection);
223 end;
224
GetCommand_DropDownnull225 function GetCommand_DropDown(ACommand: Word; AMenuSection: TIDEMenuSection;
226 AButtonClass: TIDEToolButton_DropDown_Class=nil): TIDECommand;
227 begin
228 if AButtonClass=nil then
229 AButtonClass:=TIDEToolButton_DropDown;
230 Result:=GetCommand_BtnWithArrow(ACommand, AMenuSection, AButtonClass);
231 end;
232
GetCommand_ButtonDropnull233 function GetCommand_ButtonDrop(ACommand: Word; AMenuSection: TIDEMenuSection;
234 AButtonClass: TIDEToolButton_ButtonDrop_Class=nil): TIDECommand;
235 begin
236 if AButtonClass=nil then
237 AButtonClass:=TIDEToolButton_ButtonDrop;
238 Result:=GetCommand_BtnWithArrow(ACommand, AMenuSection, AButtonClass);
239 end;
240
241 { TIDEToolButton_WithArrow }
242
243 constructor TIDEToolButton_WithArrow.Create(AOwner: TComponent);
244 begin
245 inherited Create(AOwner);
246 DropdownMenu := TPopupMenu.Create(Self);
247 DropdownMenu.Images := IDEImages.Images_16;
248 DropdownMenu.OnPopup := @DoOnMenuPopup;
249 end;
250
GetSectionnull251 function TIDEToolButton_WithArrow.GetSection: TIDEMenuSection;
252 begin
253 Result:=nil;
254 if (Item<>nil) then
255 Result:=TIDEMenuSection(Item.Tag);
256 end;
257
258 procedure TIDEToolButton_WithArrow.DoOnMenuPopup(Sender: TObject);
259 begin
260 DropdownMenu.Items.Clear;
261 RefreshMenu;
262 end;
263
264 procedure TIDEToolButton_WithArrow.RefreshMenu;
265 begin
266 if Section=nil then
267 Exit;
268 if Section.MenuItem=nil then
269 Section.GetRoot.CreateMenuItem; // this forces creating menu (it is necessary
270 // for TPopupMenu before first popup)
271 if Section.MenuItem<>nil then
272 DropdownMenu.Items.Assign(Section.MenuItem);
273 end;
274
275 { TIDEToolButton_DropDown }
276
277 procedure TIDEToolButton_DropDown.DoOnAdded;
278 begin
279 Style := tbsDropDown; // not in constructor
280 end;
281
282 { TIDEToolButton_ButtonDrop }
283
284 procedure TIDEToolButton_ButtonDrop.DoOnAdded;
285 begin
286 Style := tbsButtonDrop; // not in constructor
287 if (Item<>nil) then
288 if (Item.Command<>nil) then
289 Item.Command.OnExecute:=@PopUpAloneMenu;
290 end;
291
292 procedure TIDEToolButton_ButtonDrop.PopUpAloneMenu(Sender: TObject);
293 var
294 ActiveEditor: TSourceEditorInterface;
295 ScreenXY: TPoint;
296 begin
297 ActiveEditor := SourceEditorManagerIntf.ActiveEditor;
298 if ActiveEditor=nil then
299 Exit;
300 ScreenXY := ActiveEditor.EditorControl.ClientToScreen(Point(0, 0));
301 DropdownMenu.PopUp(ScreenXY.X, ScreenXY.Y);
302 end;
303 {%endregion}
304
305 { TIDEToolButtonsEnumerator }
306
307 constructor TIDEToolButtonsEnumerator.Create(AButtons: TIDEToolButtons);
308 begin
309 inherited Create;
310 FList := AButtons;
311 FPosition := -1;
312 end;
313
314
GetCurrentnull315 function TIDEToolButtonsEnumerator.GetCurrent: TIDEToolButton;
316 begin
317 Result := FList[FPosition];
318 end;
319
TIDEToolButtonsEnumerator.MoveNextnull320 function TIDEToolButtonsEnumerator.MoveNext: Boolean;
321 begin
322 Inc(FPosition);
323 Result := FPosition < FList.Count;
324 end;
325
326 { TIDEToolButtons }
327
328 procedure TIDEToolButtons.Add(const aBtn: TIDEToolButton);
329 begin
330 FList.Add(aBtn);
331 aBtn.FreeNotification(Self);
332 end;
333
334 constructor TIDEToolButtons.Create(aOwner: TComponent);
335 begin
336 inherited Create(aOwner);
337 FList := TFPList.Create;
338 end;
339
340 destructor TIDEToolButtons.Destroy;
341 var
342 I: Integer;
343 begin
344 for I := 0 to Count-1 do
345 Items[I].RemoveFreeNotification(Self);
346 FList.Free;
347 inherited Destroy;
348 end;
349
GetCountnull350 function TIDEToolButtons.GetCount: Integer;
351 begin
352 Result := FList.Count;
353 end;
354
GetEnumeratornull355 function TIDEToolButtons.GetEnumerator: TIDEToolButtonsEnumerator;
356 begin
357 Result := TIDEToolButtonsEnumerator.Create(Self);
358 end;
359
TIDEToolButtons.GetItemsnull360 function TIDEToolButtons.GetItems(Index: Integer): TIDEToolButton;
361 begin
362 Result := TIDEToolButton(FList[Index]);
363 end;
364
365 procedure TIDEToolButtons.Notification(AComponent: TComponent; Operation: TOperation);
366 var
367 xIndex: Integer;
368 begin
369 inherited Notification(AComponent, Operation);
370 if (Operation = opRemove) then
371 begin
372 xIndex := FList.IndexOf(AComponent);
373 if xIndex >= 0 then
374 FList.Delete(xIndex);
375 end;
376 end;
377
378 { TIDEButtonCommand }
379
380 constructor TIDEButtonCommand.Create(const TheName: string);
381 begin
382 inherited Create(TheName);
383 FToolButtonClass := TIDEToolButton;
384 FToolButtons := TIDEToolButtons.Create(nil);
385 end;
386
387 destructor TIDEButtonCommand.Destroy;
388 begin
389 FToolButtons.Free;
390 inherited Destroy;
391 end;
392
393 procedure TIDEButtonCommand.SetEnabled(const aEnabled: Boolean);
394 var
395 xBtn: TIDEToolButton;
396 begin
397 inherited SetEnabled(aEnabled);
398 for xBtn in FToolButtons do
399 xBtn.Enabled:=Enabled;
400 end;
401
402 procedure TIDEButtonCommand.SetHint(const aHint: string);
403 var
404 xBtn: TIDEToolButton;
405 begin
406 inherited SetHint(aHint);
407 for xBtn in FToolButtons do
408 xBtn.Hint:=GetHintOrCaptionWithShortCut;
409 end;
410
411 procedure TIDEButtonCommand.SetImageIndex(const aImageIndex: Integer);
412 var
413 xBtn: TIDEToolButton;
414 begin
415 inherited SetImageIndex(aImageIndex);
416 for xBtn in FToolButtons do
417 xBtn.ImageIndex:=ImageIndex;
418 end;
419
420 procedure TIDEButtonCommand.SetName(const aName: string);
421 var
422 i: Integer;
423 begin
424 if Name=aName then Exit;
425 i:=IDEToolButtonCategories.FButtonNames.IndexOf(Name);
426 inherited SetName(aName);
427 if (i>=0) and (IDEToolButtonCategories.FButtonNames.Objects[i] = Self) then
428 begin
429 IDEToolButtonCategories.FButtonNames.Delete(i);
430 IDEToolButtonCategories.FButtonNames.AddObject(aName, Self);
431 end;
432 end;
433
434 procedure TIDEButtonCommand.SetCaption(aCaption: string);
435 var
436 xBtn: TIDEToolButton;
437 begin
438 inherited SetCaption(aCaption);
439 for xBtn in FToolButtons do
440 xBtn.Hint:=GetHintOrCaptionWithShortCut;
441 end;
442
443 procedure TIDEButtonCommand.SetChecked(const aChecked: Boolean);
444 var
445 xBtn: TIDEToolButton;
446 begin
447 inherited SetChecked(aChecked);
448 for xBtn in FToolButtons do
449 xBtn.Down:=Checked;
450 end;
451
452 procedure TIDEButtonCommand.SetResourceName(const aResourceName: string);
453 var
454 xBtn: TIDEToolButton;
455 begin
456 inherited SetResourceName(aResourceName);
457 for xBtn in FToolButtons do
458 xBtn.ImageIndex:=ImageIndex;
459 end;
460
461 procedure TIDEButtonCommand.ShortCutsUpdated(const aShortCut, aShortCutKey2: TShortCut);
462 var
463 xBtn: TIDEToolButton;
464 begin
465 inherited ShortCutsUpdated(aShortCut, aShortCutKey2);
466 for xBtn in FToolButtons do
467 xBtn.Hint:=GetHintOrCaptionWithShortCut;
468 end;
469
470 procedure TIDEButtonCommand.ToolButtonAdded(const aBtn: TIDEToolButton);
471 begin
472 FToolButtons.Add(aBtn);
473 aBtn.DoOnAdded;
474 end;
475
476 { TIDEToolButtonCategory }
477
ButtonCountnull478 function TIDEToolButtonCategory.ButtonCount: Integer;
479 begin
480 Result := FButtons.Count;
481 end;
482
483 constructor TIDEToolButtonCategory.Create;
484 begin
485 FButtons := TFPList.Create;
486 end;
487
488 destructor TIDEToolButtonCategory.Destroy;
489 var
490 i: Integer;
491 begin
492 for i := 0 to ButtonCount-1 do
493 Buttons[i].Free;
494 FButtons.Free;
495 inherited Destroy;
496 end;
497
TIDEToolButtonCategory.GetButtonsnull498 function TIDEToolButtonCategory.GetButtons(Index: Integer): TIDEButtonCommand;
499 begin
500 Result := TIDEButtonCommand(FButtons[Index]);
501 end;
502
503 { TIDEToolButtonCategories }
504
AddButtonnull505 function TIDEToolButtonCategories.AddButton(const aCommand: TIDECommand): TIDEButtonCommand;
506 var
507 xCategory: TIDEToolButtonCategory;
508 begin
509 Assert(aCommand<>nil, 'TIDEToolButtonCategories.AddButton: aCommand=nil');
510 xCategory := RegisterIDEButtonCategory(aCommand.Category.Name, aCommand.Category.Description);
511 Result := RegisterIDEButtonCommand(xCategory, aCommand.Name, aCommand);
512 end;
513
AddButtonnull514 function TIDEToolButtonCategories.AddButton(
515 const aCategory: TIDEToolButtonCategory; const aName: string;
516 const aCommand: TIDECommand): TIDEButtonCommand;
517 begin
518 Result := FindItemByName(aName);
519 if Result=nil then
520 begin
521 Result := TIDEButtonCommand.Create(aName);
522 FButtonNames.AddObject(aName, Result);
523 aCategory.FButtons.Add(Result);
524 Result.Command:=aCommand;
525 end;
526 end;
527
TIDEToolButtonCategories.Countnull528 function TIDEToolButtonCategories.Count: Integer;
529 begin
530 Result := FCategories.Count;
531 end;
532
533 constructor TIDEToolButtonCategories.Create;
534 begin
535 FButtonNames := TStringListUTF8Fast.Create;
536 FButtonNames.Sorted := True;
537 FButtonNames.Duplicates := dupIgnore;
538 FCategories := TStringListUTF8Fast.Create;
539 FCategories.Sorted := True;
540 FCategories.Duplicates := dupIgnore;
541 FCategories.OwnsObjects := True;
542 end;
543
544 destructor TIDEToolButtonCategories.Destroy;
545 begin
546 FButtonNames.Free;
547 FCategories.Free;
548 inherited Destroy;
549 end;
550
FindCategorynull551 function TIDEToolButtonCategories.FindCategory(const aName: string
552 ): TIDEToolButtonCategory;
553 var
554 i: Integer;
555 begin
556 i := FCategories.IndexOf(aName);
557 if (i>=0) and (FCategories.Objects[i]<>nil) then
558 Result := FCategories.Objects[i] as TIDEToolButtonCategory
559 else
560 Result := nil;
561 end;
562
FindItemByMenuPathOrNamenull563 function TIDEToolButtonCategories.FindItemByMenuPathOrName(var aName: string
564 ): TIDEButtonCommand;
565 var
566 xMI: TIDEMenuItem;
567 begin
568 Result := FindItemByName(aName);
569 if Result<>nil then Exit;
570
571 //find by path from aName (backwards compatibility)
572 xMI := IDEMenuRoots.FindByPath(aName, False);
573 if Assigned(xMI) and Assigned(xMI.Command) then
574 begin
575 Result := FindItemByCommand(xMI.Command);
576 if Assigned(Result) then
577 aName := xMI.Command.Name;
578 end;
579 end;
580
FindCreateCategorynull581 function TIDEToolButtonCategories.FindCreateCategory(const aName,
582 aDescription: string): TIDEToolButtonCategory;
583 var
584 i: Integer;
585 begin
586 i := FCategories.IndexOf(aName);
587 if (i>=0) and (FCategories.Objects[i]<>nil) then
588 Result := FCategories.Objects[i] as TIDEToolButtonCategory
589 else
590 begin
591 Result := TIDEToolButtonCategory.Create;
592 Result.Name := aName;
593 Result.Description := aDescription;
594 FCategories.AddObject(aName, Result);
595 end;
596 end;
597
FindItemByCommandnull598 function TIDEToolButtonCategories.FindItemByCommand(const aCommand: TIDECommand
599 ): TIDEButtonCommand;
600 var
601 i, l: Integer;
602 begin
603 for i := 0 to Count-1 do
604 for l := 0 to Items[i].ButtonCount-1 do
605 if Items[i].Buttons[l].Command = aCommand then
606 Exit(Items[i].Buttons[l]);
607
608 Result := nil;
609 end;
610
FindItemByCommandnull611 function TIDEToolButtonCategories.FindItemByCommand(const aCommand: Word
612 ): TIDEButtonCommand;
613 var
614 i, l: Integer;
615 begin
616 for i := 0 to Count-1 do
617 for l := 0 to Items[i].ButtonCount-1 do
618 if Items[i].Buttons[l].Command.Command = aCommand then
619 Exit(Items[i].Buttons[l]);
620
621 Result := nil;
622 end;
623
TIDEToolButtonCategories.FindItemByNamenull624 function TIDEToolButtonCategories.FindItemByName(const aName: string
625 ): TIDEButtonCommand;
626 var
627 i: Integer;
628 begin
629 i := FButtonNames.IndexOf(aName);
630 if (i>=0) and (FButtonNames.Objects[i]<>nil) then
631 Result := FButtonNames.Objects[i] as TIDEButtonCommand
632 else
633 Result := nil;
634 end;
635
TIDEToolButtonCategories.GetItemsnull636 function TIDEToolButtonCategories.GetItems(Index: Integer): TIDEToolButtonCategory;
637 begin
638 Result := TIDEToolButtonCategory(FCategories.Objects[Index]);
639 end;
640
641 { TIDEToolButton }
642
643 procedure TIDEToolButton.Click;
644 begin
645 inherited Click;
646 if Assigned(FItem) then
647 FItem.DoOnClick;
648 end;
649
650 procedure TIDEToolButton.DoOnAdded;
651 begin
652 //override in descendants
653 end;
654
655 procedure TIDEToolButton.DoOnShowHint(HintInfo: PHintInfo);
656 begin
657 inherited DoOnShowHint(HintInfo);
658 if Assigned(FItem) and FItem.DoOnRequestCaption(Self) then
659 HintInfo^.HintStr := FItem.GetHintOrCaptionWithShortCut;
660 end;
661
662 end.
663
664