TB2DsgnItemEditor.pas 39 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331
  1. unit TB2DsgnItemEditor;
  2. {
  3. Toolbar2000
  4. Copyright (C) 1998-2005 by Jordan Russell
  5. All rights reserved.
  6. The contents of this file are subject to the "Toolbar2000 License"; you may
  7. not use or distribute this file except in compliance with the
  8. "Toolbar2000 License". A copy of the "Toolbar2000 License" may be found in
  9. TB2k-LICENSE.txt or at:
  10. https://jrsoftware.org/files/tb2k/TB2k-LICENSE.txt
  11. Alternatively, the contents of this file may be used under the terms of the
  12. GNU General Public License (the "GPL"), in which case the provisions of the
  13. GPL are applicable instead of those in the "Toolbar2000 License". A copy of
  14. the GPL may be found in GPL-LICENSE.txt or at:
  15. https://jrsoftware.org/files/tb2k/GPL-LICENSE.txt
  16. If you wish to allow use of your version of this file only under the terms of
  17. the GPL and not to allow others to use your version of this file under the
  18. "Toolbar2000 License", indicate your decision by deleting the provisions
  19. above and replace them with the notice and other provisions required by the
  20. GPL. If you do not delete the provisions above, a recipient may use your
  21. version of this file under either the "Toolbar2000 License" or the GPL.
  22. $jrsoftware: tb2k/Source/TB2DsgnItemEditor.pas,v 1.55 2005/01/27 06:48:53 jr Exp $
  23. }
  24. interface
  25. {$I TB2Ver.inc}
  26. uses
  27. Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
  28. StdCtrls, ExtCtrls, Buttons, ComCtrls, ImgList, Menus,
  29. TB2Item, TB2Toolbar, TB2Dock,
  30. DesignWindows, DesignEditors, DesignIntf;
  31. type
  32. TTBItemEditForm = class(TDesignWindow)
  33. TreeView: TTreeView;
  34. ListView: TListView;
  35. Splitter1: TSplitter;
  36. Toolbar: TTBToolbar;
  37. NewSubmenuButton: TTBItem;
  38. NewItemButton: TTBItem;
  39. NewSepButton: TTBItem;
  40. DeleteButton: TTBItem;
  41. TBSeparatorItem1: TTBSeparatorItem;
  42. TBPopupMenu1: TTBPopupMenu;
  43. TBItemContainer1: TTBItemContainer;
  44. ToolbarItems: TTBSubmenuItem;
  45. CopyButton: TTBItem;
  46. CutButton: TTBItem;
  47. PasteButton: TTBItem;
  48. MoreMenu: TTBSubmenuItem;
  49. TBSeparatorItem2: TTBSeparatorItem;
  50. TBSubmenuItem1: TTBSubmenuItem;
  51. TConvertMenu: TTBItem;
  52. TBSeparatorItem3: TTBSeparatorItem;
  53. MoveUpButton: TTBItem;
  54. MoveDownButton: TTBItem;
  55. procedure FormClose(Sender: TObject; var Action: TCloseAction);
  56. procedure TreeViewChange(Sender: TObject; Node: TTreeNode);
  57. procedure NewSubmenuButtonClick(Sender: TObject);
  58. procedure NewItemButtonClick(Sender: TObject);
  59. procedure ListViewChange(Sender: TObject; Item: TListItem;
  60. Change: TItemChange);
  61. procedure DeleteButtonClick(Sender: TObject);
  62. procedure NewSepButtonClick(Sender: TObject);
  63. procedure ListViewDragOver(Sender, Source: TObject; X, Y: Integer;
  64. State: TDragState; var Accept: Boolean);
  65. procedure ListViewDragDrop(Sender, Source: TObject; X, Y: Integer);
  66. procedure TreeViewEnter(Sender: TObject);
  67. procedure TreeViewDragDrop(Sender, Source: TObject; X, Y: Integer);
  68. procedure TreeViewDragOver(Sender, Source: TObject; X, Y: Integer;
  69. State: TDragState; var Accept: Boolean);
  70. procedure CopyButtonClick(Sender: TObject);
  71. procedure ListViewKeyDown(Sender: TObject; var Key: Word;
  72. Shift: TShiftState);
  73. procedure CutButtonClick(Sender: TObject);
  74. procedure PasteButtonClick(Sender: TObject);
  75. procedure FormActivate(Sender: TObject);
  76. procedure ListViewKeyPress(Sender: TObject; var Key: Char);
  77. procedure ListViewDblClick(Sender: TObject);
  78. procedure ListViewEnter(Sender: TObject);
  79. procedure TreeViewKeyDown(Sender: TObject; var Key: Word;
  80. Shift: TShiftState);
  81. procedure TConvertMenuClick(Sender: TObject);
  82. procedure TreeViewKeyPress(Sender: TObject; var Key: Char);
  83. procedure MoveUpButtonClick(Sender: TObject);
  84. procedure MoveDownButtonClick(Sender: TObject);
  85. private
  86. FParentComponent: TComponent;
  87. FRootItem, FSelParentItem: TTBCustomItem;
  88. FNotifyItemList: TList;
  89. FSettingSel, FRebuildingTree, FRebuildingList: Integer;
  90. function AddListViewItem(const Index: Integer;
  91. const Item: TTBCustomItem): TListItem;
  92. procedure Copy;
  93. procedure CreateNewItem(const AClass: TTBCustomItemClass);
  94. procedure Cut;
  95. procedure Delete;
  96. procedure DeleteItem(const Item: TTBCustomItem);
  97. function GetItemTreeCaption(AItem: TTBCustomItem): String;
  98. procedure GetSelItemList(const AList: TList);
  99. procedure ItemNotification(Ancestor: TTBCustomItem; Relayed: Boolean;
  100. Action: TTBItemChangedAction; Index: Integer; Item: TTBCustomItem);
  101. procedure MoreItemClick(Sender: TObject);
  102. procedure MoveItem(CurIndex, NewIndex: Integer);
  103. procedure Paste;
  104. procedure RebuildList;
  105. procedure RebuildTree;
  106. procedure SelectInObjectInspector(AList: TList);
  107. procedure SetSelParentItem(ASelParentItem: TTBCustomItem);
  108. function TreeViewDragHandler(Sender, Source: TObject; X, Y: Integer;
  109. Drop: Boolean): Boolean;
  110. procedure UnregisterAllNotifications;
  111. protected
  112. procedure Notification(AComponent: TComponent; Operation: TOperation); override;
  113. function UniqueName(Component: TComponent): String; override;
  114. public
  115. constructor Create(AOwner: TComponent); override;
  116. destructor Destroy; override;
  117. function EditAction(Action: TEditAction): Boolean; override;
  118. function GetEditState: TEditState; override;
  119. end;
  120. TTBItemsEditor = class(TDefaultEditor)
  121. public
  122. procedure Edit; override;
  123. procedure ExecuteVerb(Index: Integer); override;
  124. function GetVerb(Index: Integer): String; override;
  125. function GetVerbCount: Integer; override;
  126. end;
  127. TTBItemsPropertyEditor = class(TStringProperty)
  128. public
  129. procedure Edit; override;
  130. function GetAttributes: TPropertyAttributes; override;
  131. function GetValue: String; override;
  132. end;
  133. procedure TBRegisterItemClass(AClass: TTBCustomItemClass;
  134. const ACaption: String; ResInstance: HINST);
  135. type
  136. TTBDsgnEditorHook = procedure(Sender: TTBItemEditForm) of object;
  137. procedure TBRegisterDsgnEditorHook(Hook: TTBDsgnEditorHook);
  138. procedure TBUnregisterDsgnEditorHook(Hook: TTBDsgnEditorHook);
  139. implementation
  140. {$R *.DFM}
  141. uses
  142. TypInfo, CommCtrl, TB2Version, TB2Common, TB2DsgnConverter;
  143. type
  144. TTBCustomItemAccess = class(TTBCustomItem);
  145. TControlAccess = class(TControl);
  146. TDesignerSelectionList = IDesignerSelections;
  147. PItemClassInfo = ^TItemClassInfo;
  148. TItemClassInfo = record
  149. ItemClass: TTBCustomItemClass;
  150. Caption: String;
  151. ImageIndex: Integer;
  152. end;
  153. var
  154. ItemClasses: TList;
  155. ItemImageList: TImageList;
  156. EditFormHooks: TList;
  157. procedure FreeItemClasses;
  158. var
  159. I: Integer;
  160. IC: TList;
  161. begin
  162. if ItemClasses = nil then Exit;
  163. IC := ItemClasses;
  164. ItemClasses := nil;
  165. for I := IC.Count-1 downto 0 do
  166. Dispose(PItemClassInfo(IC[I]));
  167. IC.Free;
  168. end;
  169. procedure UnregisterModuleItemClasses(AModule: NativeInt);
  170. var
  171. I: Integer;
  172. Info: PItemClassInfo;
  173. begin
  174. I := 0;
  175. while I < ItemClasses.Count do begin
  176. Info := ItemClasses[I];
  177. if FindClassHInstance(Info.ItemClass) = HINST(AModule) then begin
  178. ItemClasses.Delete(I);
  179. Dispose(Info);
  180. end
  181. else
  182. Inc(I);
  183. end;
  184. { Note: TTBItemEditForm also holds references to item classes, but since
  185. Delphi automatically closes all editor forms before compiling/removing
  186. a package, we don't need to remove them. }
  187. end;
  188. function LoadItemImage(Instance: HINST; const ResName: String): Integer;
  189. var
  190. Bmp: TBitmap;
  191. begin
  192. Bmp := TBitmap.Create;
  193. try
  194. Bmp.Handle := LoadBitmap(Instance, PChar(ResName));
  195. if Bmp.Handle = 0 then
  196. Result := -1
  197. else
  198. Result := ItemImageList.AddMasked(Bmp, Bmp.Canvas.Pixels[0, Bmp.Height-1]);
  199. finally
  200. Bmp.Free;
  201. end;
  202. end;
  203. procedure TBRegisterItemClass(AClass: TTBCustomItemClass;
  204. const ACaption: String; ResInstance: HINST);
  205. var
  206. Info: PItemClassInfo;
  207. I: Integer;
  208. begin
  209. if ItemClasses <> nil then
  210. for I := ItemClasses.Count - 1 downto 0 do
  211. begin
  212. Info := ItemClasses[I];
  213. if Info.ItemClass = AClass then
  214. begin
  215. Dispose(Info);
  216. ItemClasses.Delete(I);
  217. end;
  218. end;
  219. New(Info);
  220. Info.ItemClass := AClass;
  221. Info.Caption := ACaption;
  222. Info.ImageIndex := LoadItemImage(ResInstance, Uppercase(AClass.ClassName));
  223. ItemClasses.Add(Info);
  224. end;
  225. function GetItemClassImage(AClass: TTBCustomItemClass): Integer;
  226. var
  227. I: Integer;
  228. Info: PItemClassInfo;
  229. begin
  230. for I := ItemClasses.Count-1 downto 0 do begin
  231. Info := ItemClasses[I];
  232. if AClass.InheritsFrom(Info.ItemClass) then begin
  233. Result := Info.ImageIndex;
  234. if Result >= 0 then
  235. Exit;
  236. end;
  237. end;
  238. if AClass.InheritsFrom(TTBSubmenuItem) then
  239. Result := 1
  240. else if AClass.InheritsFrom(TTBSeparatorItem) then
  241. Result := 2
  242. else
  243. Result := 0;
  244. end;
  245. procedure ShowEditForm(AParentComponent: TComponent; ARootItem: TTBCustomItem;
  246. const ADesigner: IDesigner);
  247. var
  248. I: Integer;
  249. Form: TCustomForm;
  250. EditForm: TTBItemEditForm;
  251. begin
  252. if Assigned(ARootItem.LinkSubitems) then begin
  253. case MessageDlg(Format('The LinkSubitems property is set to ''%s''. ' +
  254. 'Would you like to edit that item instead?',
  255. [ARootItem.LinkSubitems.Name]), mtConfirmation, [mbYes, mbNo, mbCancel], 0) of
  256. mrYes: begin
  257. AParentComponent := ARootItem.LinkSubitems;
  258. ARootItem := ARootItem.LinkSubitems;
  259. end;
  260. mrCancel: Exit;
  261. end;
  262. end;
  263. for I := 0 to Screen.FormCount-1 do begin
  264. Form := Screen.Forms[I];
  265. if Form is TTBItemEditForm then
  266. if TTBItemEditForm(Form).FRootItem = ARootItem then begin
  267. Form.Show;
  268. if Form.WindowState = wsMinimized then
  269. Form.WindowState := wsNormal;
  270. Exit;
  271. end;
  272. end;
  273. EditForm := TTBItemEditForm.Create(Application);
  274. try
  275. EditForm.Designer := ADesigner;
  276. EditForm.FParentComponent := AParentComponent;
  277. AParentComponent.FreeNotification(EditForm);
  278. EditForm.FRootItem := ARootItem;
  279. ARootItem.FreeNotification(EditForm);
  280. EditForm.FSelParentItem := ARootItem;
  281. EditForm.Caption := 'Editing ' + AParentComponent.Name;
  282. EditForm.RebuildTree;
  283. EditForm.RebuildList;
  284. EditForm.PopupMode := pmExplicit;
  285. EditForm.Show;
  286. except
  287. EditForm.Free;
  288. raise;
  289. end;
  290. end;
  291. function IsSubmenuItem(Item: TTBCustomItem): Boolean;
  292. begin
  293. Result := tbisSubitemsEditable in TTBCustomItemAccess(Item).ItemStyle;
  294. end;
  295. procedure ShowVersion;
  296. const
  297. AboutText =
  298. '%s'#13#10 +
  299. 'Copyright (C) 1998-2005 by Jordan Russell'#13#10 +
  300. 'For conditions of distribution and use, see LICENSE.TXT.'#13#10 +
  301. #13#10 +
  302. 'Visit my web site for the latest versions of Toolbar2000:'#13#10 +
  303. 'https://jrsoftware.org/';
  304. begin
  305. MessageDlg(Format(AboutText, [Toolbar2000VersionPropText]), mtInformation,
  306. [mbOK], 0);
  307. end;
  308. { TTBItemEditForm }
  309. constructor TTBItemEditForm.Create(AOwner: TComponent);
  310. var
  311. I: Integer;
  312. Info: PItemClassInfo;
  313. Item: TTBItem;
  314. begin
  315. inherited;
  316. FNotifyItemList := TList.Create;
  317. ToolbarItems.SubMenuImages := ItemImageList;
  318. ListView.SmallImages := ItemImageList;
  319. { Populate the 'More' menu }
  320. for I := 0 to ItemClasses.Count-1 do begin
  321. Info := ItemClasses[I];
  322. Item := TTBItem.Create(Self);
  323. Item.Caption := Info.Caption;
  324. Item.ImageIndex := GetItemClassImage(Info.ItemClass);
  325. Item.Tag := Integer(Info.ItemClass);
  326. Item.OnClick := MoreItemClick;
  327. MoreMenu.Add(Item);
  328. end;
  329. { Run the hooks }
  330. if EditFormHooks <> nil then
  331. for I := 0 to EditFormHooks.Count - 1 do
  332. TTBDsgnEditorHook(EditFormHooks[I]^)(Self);
  333. end;
  334. destructor TTBItemEditForm.Destroy;
  335. begin
  336. inherited;
  337. if Assigned(FNotifyItemList) then begin
  338. UnregisterAllNotifications;
  339. FNotifyItemList.Free;
  340. FNotifyItemList := nil;
  341. end;
  342. end;
  343. procedure TTBItemEditForm.FormClose(Sender: TObject;
  344. var Action: TCloseAction);
  345. begin
  346. Action := caFree;
  347. end;
  348. procedure TTBItemEditForm.FormActivate(Sender: TObject);
  349. begin
  350. SetSelParentItem(FSelParentItem);
  351. end;
  352. procedure TTBItemEditForm.Notification(AComponent: TComponent;
  353. Operation: TOperation);
  354. begin
  355. inherited;
  356. if (Operation = opRemove) and
  357. ((AComponent = FParentComponent) or (AComponent = FRootItem)) then
  358. { Must use Free instead of Close, since Close causes the freeing of the
  359. form to be delayed until the next message. We have to destroy the form
  360. immediately, otherwise Delphi will crash when Compile is clicked on the
  361. TB2k package. }
  362. Free;
  363. {}{temp:}
  364. (*if (Operation = opRemove) and (FNotifyItemList.IndexOf(AComponent) <> -1) then begin
  365. outputdebugstring(pchar('Still in list: ' + AComponent.name));
  366. //beep;
  367. end;*)
  368. end;
  369. function TTBItemEditForm.UniqueName(Component: TComponent): String;
  370. begin
  371. Result := Designer.UniqueName(Component.ClassName);
  372. end;
  373. function TTBItemEditForm.GetEditState: TEditState;
  374. begin
  375. Result := [];
  376. if ActiveControl = ListView then begin
  377. if Assigned(ListView.Selected) then
  378. Result := [esCanDelete, esCanCut, esCanCopy];
  379. if ClipboardComponents then
  380. Include(Result, esCanPaste);
  381. end;
  382. end;
  383. function TTBItemEditForm.EditAction(Action: TEditAction): Boolean;
  384. begin
  385. Result := True;
  386. case Action of
  387. eaCut: Cut;
  388. eaCopy: Copy;
  389. eaPaste: Paste;
  390. eaDelete: Delete;
  391. else
  392. Result := False;
  393. end;
  394. end;
  395. procedure TTBItemEditForm.UnregisterAllNotifications;
  396. var
  397. I: Integer;
  398. begin
  399. for I := FNotifyItemList.Count-1 downto 0 do begin
  400. //outputdebugstring(pchar('Unregall: ' + TTBCustomItem(FNotifyItemList[I]).name));
  401. TTBCustomItem(FNotifyItemList[I]).UnregisterNotification(ItemNotification);
  402. FNotifyItemList.Delete(I);
  403. end;
  404. end;
  405. procedure TTBItemEditForm.ItemNotification(Ancestor: TTBCustomItem;
  406. Relayed: Boolean; Action: TTBItemChangedAction; Index: Integer;
  407. Item: TTBCustomItem);
  408. var
  409. ListItem: TListItem;
  410. TreeNode: TTreeNode;
  411. I: Integer;
  412. C: String;
  413. begin
  414. { Manipulate the list view when items are inserted, deleted, or their Caption
  415. changes }
  416. case Action of
  417. tbicInserted:
  418. begin
  419. if (Ancestor = FSelParentItem) and not Relayed then
  420. AddListViewItem(Index, Item);
  421. if IsSubmenuItem(Item) then
  422. RebuildTree;
  423. end;
  424. tbicDeleting:
  425. if (Ancestor = FSelParentItem) and not Relayed then begin
  426. ListItem := ListView.FindData(0, Item, True, False);
  427. if Assigned(ListItem) then
  428. ListItem.Delete;
  429. end;
  430. tbicInvalidateAndResize:
  431. if (Ancestor = FSelParentItem) and not Relayed then begin
  432. ListItem := ListView.FindData(0, Item, True, False);
  433. if Assigned(ListItem) and (ListItem.Caption <> TTBCustomItem(Item).Caption) then
  434. ListItem.Caption := TTBCustomItem(Item).Caption;
  435. end;
  436. end;
  437. { Update tree view when an item is deleted, or a Caption changes }
  438. if Action = tbicDeleting then begin
  439. I := FNotifyItemList.IndexOf(Item);
  440. if I <> -1 then begin
  441. //outputdebugstring(pchar('Deleting, so unreging: ' + item.name));
  442. TTBCustomItem(Item).UnregisterNotification(ItemNotification);
  443. FNotifyItemList.Delete(I);
  444. end;
  445. end;
  446. if Action in [tbicDeleting, tbicInvalidateAndResize, tbicNameChanged] then begin
  447. TreeNode := TreeView.Items.GetFirstNode;
  448. while Assigned(TreeNode) do begin
  449. if TreeNode.Data = Item then begin
  450. if Action = tbicDeleting then begin
  451. TreeNode.Delete;
  452. if FSelParentItem = Item then
  453. SetSelParentItem(TTBCustomItem(Item).Parent);
  454. end
  455. else begin
  456. { tbicInvalidateAndResize, tbicNameChanged: }
  457. C := GetItemTreeCaption(Item);
  458. if TreeNode.Text <> C then
  459. TreeNode.Text := C;
  460. end;
  461. Break;
  462. end;
  463. TreeNode := TreeNode.GetNext;
  464. end;
  465. end;
  466. end;
  467. function TTBItemEditForm.GetItemTreeCaption(AItem: TTBCustomItem): String;
  468. begin
  469. if AItem <> FRootItem then begin
  470. Result := AItem.Caption;
  471. if Result = '' then
  472. Result := '[' + AItem.Name + ']';
  473. end
  474. else
  475. Result := '(Root)';
  476. end;
  477. procedure TTBItemEditForm.RebuildTree;
  478. procedure Recurse(const AParentItem: TTBCustomItem; const ATreeNode: TTreeNode;
  479. var FoundSelParentItem: TTreeNode);
  480. var
  481. I: Integer;
  482. NewNode: TTreeNode;
  483. ChildItem: TTBCustomItem;
  484. begin
  485. {}AParentItem.FreeNotification(Self);
  486. AParentItem.RegisterNotification(ItemNotification);
  487. FNotifyItemList.Add(AParentItem);
  488. NewNode := TreeView.Items.AddChild(ATreeNode, GetItemTreeCaption(AParentItem));
  489. NewNode.Data := AParentItem;
  490. if AParentItem = FSelParentItem then
  491. FoundSelParentItem := NewNode;
  492. for I := 0 to AParentItem.Count-1 do begin
  493. ChildItem := AParentItem[I];
  494. if IsSubmenuItem(ChildItem) then
  495. Recurse(ChildItem, NewNode, FoundSelParentItem);
  496. end;
  497. end;
  498. var
  499. FoundSelParentItem: TTreeNode;
  500. begin
  501. Inc(FRebuildingTree);
  502. try
  503. TreeView.Items.BeginUpdate;
  504. try
  505. TreeView.Items.Clear;
  506. UnregisterAllNotifications;
  507. FoundSelParentItem := nil;
  508. Recurse(FRootItem, nil, FoundSelParentItem);
  509. if FoundSelParentItem = nil then
  510. SetSelParentItem(FRootItem)
  511. else
  512. TreeView.Selected := FoundSelParentItem;
  513. TreeView.Items[0].Expand(True);
  514. finally
  515. TreeView.Items.EndUpdate;
  516. end;
  517. finally
  518. Dec(FRebuildingTree);
  519. end;
  520. end;
  521. function TTBItemEditForm.AddListViewItem(const Index: Integer;
  522. const Item: TTBCustomItem): TListItem;
  523. begin
  524. Result := ListView.Items.Insert(Index);
  525. Result.Data := Item;
  526. if not(Item is TTBControlItem) then begin
  527. Result.Caption := Item.Caption;
  528. Result.Subitems.Add(Item.ClassName);
  529. Result.ImageIndex := GetItemClassImage(TTBCustomItemClass(Item.ClassType));
  530. end
  531. else begin
  532. Result.Caption := '(Control)';
  533. Result.Subitems.Add(Item.ClassName);
  534. Result.ImageIndex := -1;
  535. end;
  536. end;
  537. procedure TTBItemEditForm.RebuildList;
  538. var
  539. ChildItem: TTBCustomItem;
  540. I: Integer;
  541. begin
  542. Inc(FRebuildingList);
  543. try
  544. ListView.Items.BeginUpdate;
  545. try
  546. ListView.Items.Clear;
  547. if Assigned(FSelParentItem) then begin
  548. for I := 0 to FSelParentItem.Count-1 do begin
  549. ChildItem := FSelParentItem[I];
  550. { Check for csDestroying because deleting an item in the tree view
  551. causes the parent item to be selected, and the parent item won't
  552. get a notification that the item is deleting since notifications
  553. were already sent }
  554. if not(csDestroying in ChildItem.ComponentState) then
  555. AddListViewItem(I, ChildItem);
  556. end;
  557. { Add an empty item to the end }
  558. ListView.Items.Add.ImageIndex := -1;
  559. end;
  560. finally
  561. ListView.Items.EndUpdate;
  562. end;
  563. { Work around a strange TListView bug(?). Without this, the column header
  564. isn't painted properly. }
  565. if HandleAllocated then
  566. SetWindowPos(ListView.Handle, 0, 0, 0, 0, 0, SWP_FRAMECHANGED or
  567. SWP_NOACTIVATE or SWP_NOMOVE or SWP_NOSIZE or SWP_NOZORDER);
  568. finally
  569. Dec(FRebuildingList);
  570. end;
  571. end;
  572. procedure TTBItemEditForm.SelectInObjectInspector(AList: TList);
  573. var
  574. CompList1, CompList2: TDesignerSelectionList;
  575. I: Integer;
  576. C: TComponent;
  577. begin
  578. { Designer.SetSelections will make components appear selected on the form.
  579. It will also select the component in Object Inspector, but only if the
  580. form has the focus. TDesignWindow.SetSelection will select the component
  581. in Object Inspector regardless of whether the form has the focus. }
  582. CompList1 := CreateSelectionList;
  583. CompList2 := CreateSelectionList;
  584. for I := 0 to AList.Count-1 do begin
  585. C := AList[I];
  586. { Must check for csDestroying. If SetSelection is passed a component that's
  587. destroying, Delphi will crash. }
  588. if not(csDestroying in C.ComponentState) then begin
  589. CompList1.Add(C);
  590. CompList2.Add(C);
  591. end;
  592. end;
  593. if CompList1.Count <> 0 then
  594. begin
  595. Designer.SetSelections(CompList1);
  596. end;
  597. end;
  598. procedure TTBItemEditForm.GetSelItemList(const AList: TList);
  599. var
  600. ListItem: TListItem;
  601. begin
  602. ListItem := nil;
  603. while True do begin
  604. ListItem := ListView.GetNextItem(ListItem, sdAll, [isSelected]);
  605. if ListItem = nil then
  606. Break;
  607. if Assigned(ListItem.Data) then
  608. AList.Add(ListItem.Data);
  609. end;
  610. end;
  611. procedure TTBItemEditForm.SetSelParentItem(ASelParentItem: TTBCustomItem);
  612. { - Rebuilds the list view to match a new selection (ASelParentItem) in the
  613. tree view
  614. - Updates toolbar
  615. - Selects selected item(s) into Object Inspector }
  616. var
  617. I: Integer;
  618. TreeNode: TTreeNode;
  619. ItemIsSelected: Boolean;
  620. List: TList;
  621. begin
  622. if FSettingSel > 0 then
  623. Exit;
  624. List := TList.Create;
  625. Inc(FSettingSel);
  626. try
  627. if FSelParentItem <> ASelParentItem then begin
  628. FSelParentItem := ASelParentItem;
  629. NewSubmenuButton.Enabled := Assigned(ASelParentItem);
  630. NewItemButton.Enabled := Assigned(ASelParentItem);
  631. NewSepButton.Enabled := Assigned(ASelParentItem);
  632. for I := 0 to MoreMenu.Count-1 do
  633. MoreMenu[I].Enabled := Assigned(ASelParentItem);
  634. if not Assigned(TreeView.Selected) or (TreeView.Selected.Data <> FSelParentItem) then begin
  635. if FSelParentItem = nil then
  636. TreeView.Selected := nil
  637. else begin
  638. TreeNode := TreeView.Items.GetFirstNode;
  639. while Assigned(TreeNode) do begin
  640. if TreeNode.Data = FSelParentItem then begin
  641. TreeView.Selected := TreeNode;
  642. Break;
  643. end;
  644. TreeNode := TreeNode.GetNext;
  645. end;
  646. end;
  647. end;
  648. RebuildList;
  649. end;
  650. ItemIsSelected := (ActiveControl = ListView) and Assigned(ListView.Selected) and
  651. Assigned(ListView.Selected.Data);
  652. if ItemIsSelected then
  653. GetSelItemList(List);
  654. CutButton.Enabled := ItemIsSelected;
  655. CopyButton.Enabled := ItemIsSelected;
  656. PasteButton.Enabled := (ActiveControl = ListView);
  657. DeleteButton.Enabled := ItemIsSelected or
  658. ((ActiveControl = TreeView) and (FSelParentItem <> FRootItem));
  659. MoveUpButton.Enabled := ItemIsSelected and
  660. (FSelParentItem.IndexOf(List.First) > 0);
  661. MoveDownButton.Enabled := ItemIsSelected and
  662. (FSelParentItem.IndexOf(List.Last) < FSelParentItem.Count-1);
  663. if ActiveControl = ListView then begin
  664. if List.Count = 0 then
  665. { No item was selected, or the blank item was selected.
  666. Select the root item so it looks like no item was selected in
  667. Object Inspector }
  668. List.Add(FRootItem);
  669. end
  670. else if not Assigned(ASelParentItem) or (ASelParentItem = FRootItem) then
  671. List.Add(FParentComponent)
  672. else
  673. List.Add(ASelParentItem);
  674. SelectInObjectInspector(List);
  675. finally
  676. Dec(FSettingSel);
  677. List.Free;
  678. end;
  679. end;
  680. procedure TTBItemEditForm.Cut;
  681. begin
  682. Copy;
  683. Delete;
  684. end;
  685. procedure TTBItemEditForm.Copy;
  686. var
  687. SelList: TList;
  688. CompList: TDesignerSelectionList;
  689. I: Integer;
  690. Item: TTBCustomItem;
  691. begin
  692. if ListView.Selected = nil then Exit;
  693. CompList := nil;
  694. SelList := TList.Create;
  695. try
  696. GetSelItemList(SelList);
  697. CompList := CreateSelectionList;
  698. for I := 0 to SelList.Count-1 do begin
  699. Item := SelList[I];
  700. if Item is TTBControlItem then
  701. raise EInvalidOperation.Create('Cannot cut or copy TTBControlItems');
  702. CompList.Add(Item);
  703. end;
  704. CopyComponents(FParentComponent.Owner, CompList);
  705. finally
  706. SelList.Free;
  707. end;
  708. end;
  709. procedure TTBItemEditForm.Paste;
  710. var
  711. CompList: TDesignerSelectionList;
  712. begin
  713. if FSelParentItem = nil then Exit;
  714. CompList := CreateSelectionList;
  715. PasteComponents(FParentComponent.Owner, FSelParentItem, CompList);
  716. if CompList.Count <> 0 then
  717. Designer.Modified;
  718. end;
  719. procedure TTBItemEditForm.DeleteItem(const Item: TTBCustomItem);
  720. begin
  721. if csAncestor in Item.ComponentState then
  722. raise EInvalidOperation.Create('Items introduced in an ancestor form cannot be deleted');
  723. Item.Free;
  724. Designer.Modified;
  725. end;
  726. procedure TTBItemEditForm.Delete;
  727. var
  728. List: TList;
  729. Item: TTBCustomItem;
  730. ListItem: TListItem;
  731. begin
  732. List := TList.Create;
  733. try
  734. List.Add(FSelParentItem);
  735. SelectInObjectInspector(List);
  736. finally
  737. List.Free;
  738. end;
  739. FSelParentItem.ViewBeginUpdate;
  740. try
  741. while Assigned(ListView.Selected) do begin
  742. Item := ListView.Selected.Data;
  743. if Item = nil then
  744. Break;
  745. DeleteItem(Item);
  746. end;
  747. finally
  748. FSelParentItem.ViewEndUpdate;
  749. end;
  750. { After deleting the items, select the item with the focus }
  751. ListItem := ListView.GetNextItem(nil, sdAll, [isFocused]);
  752. if Assigned(ListItem) then
  753. ListItem.Selected := True;
  754. end;
  755. procedure TTBItemEditForm.MoveItem(CurIndex, NewIndex: Integer);
  756. var
  757. WasFocused: Boolean;
  758. begin
  759. WasFocused := ListView.Items[CurIndex].Focused;
  760. FSelParentItem.Move(CurIndex, NewIndex);
  761. Designer.Modified;
  762. if WasFocused then
  763. ListView.Items[NewIndex].Focused := True;
  764. ListView.Items[NewIndex].Selected := True;
  765. end;
  766. procedure TTBItemEditForm.TreeViewChange(Sender: TObject; Node: TTreeNode);
  767. var
  768. NewSelectedParentItem: TTBCustomItem;
  769. begin
  770. if (FRebuildingTree > 0) or (FSettingSel > 0) then Exit;
  771. if Node = nil then
  772. NewSelectedParentItem := nil
  773. else
  774. NewSelectedParentItem := Node.Data;
  775. SetSelParentItem(NewSelectedParentItem);
  776. end;
  777. procedure TTBItemEditForm.TreeViewEnter(Sender: TObject);
  778. { When the tree view gets the focus, act as if the currently selected item
  779. was clicked. }
  780. begin
  781. ListView.Selected := nil;
  782. SetSelParentItem(FSelParentItem);
  783. end;
  784. procedure TTBItemEditForm.ListViewChange(Sender: TObject; Item: TListItem;
  785. Change: TItemChange);
  786. begin
  787. if (FRebuildingList > 0) or (FSettingSel > 0) or (Change <> ctState) or
  788. (csDestroying in ListView.ComponentState) then
  789. Exit;
  790. SetSelParentItem(FSelParentItem);
  791. end;
  792. procedure TTBItemEditForm.ListViewEnter(Sender: TObject);
  793. begin
  794. { When list view gets the focus, update the toolbar }
  795. SetSelParentItem(FSelParentItem);
  796. end;
  797. procedure TTBItemEditForm.ListViewDblClick(Sender: TObject);
  798. var
  799. SelItem: TTBCustomItem;
  800. PropCount, I: Integer;
  801. Props: PPropList;
  802. PropInfo: PPropInfo;
  803. MethodName: String;
  804. Method: TMethod;
  805. begin
  806. SelItem := nil;
  807. if Assigned(ListView.Selected) then
  808. SelItem := ListView.Selected.Data;
  809. if SelItem = nil then Exit;
  810. if IsSubmenuItem(SelItem) then begin
  811. SetSelParentItem(SelItem);
  812. Exit;
  813. end;
  814. PropCount := GetPropList(SelItem.ClassInfo, [tkMethod], nil);
  815. GetMem(Props, PropCount * SizeOf(PPropInfo));
  816. try
  817. GetPropList(SelItem.ClassInfo, [tkMethod], Props);
  818. for I := PropCount-1 downto 0 do begin
  819. PropInfo := Props[I];
  820. if CompareText({MP}string(PropInfo.Name), 'OnClick') = 0 then begin
  821. Method := GetMethodProp(SelItem, PropInfo);
  822. MethodName := Designer.GetMethodName(Method);
  823. if MethodName = '' then begin
  824. MethodName := SelItem.Name + 'Click';
  825. Method := Designer.CreateMethod(MethodName, GetTypeData(PropInfo.PropType^));
  826. SetMethodProp(SelItem, string(PropInfo.Name), Method);
  827. Designer.Modified;
  828. end;
  829. if Designer.MethodExists(MethodName) then
  830. Designer.ShowMethod(MethodName);
  831. Break;
  832. end;
  833. end;
  834. finally
  835. FreeMem(Props);
  836. end;
  837. end;
  838. procedure TTBItemEditForm.ListViewKeyDown(Sender: TObject; var Key: Word;
  839. Shift: TShiftState);
  840. begin
  841. case Key of
  842. VK_RETURN: begin
  843. Key := 0;
  844. ActivateInspector(#0);
  845. end;
  846. VK_INSERT: begin
  847. Key := 0;
  848. if ssCtrl in Shift then
  849. NewSubmenuButtonClick(Sender)
  850. else
  851. NewItemButtonClick(Sender);
  852. end;
  853. VK_DELETE: begin
  854. Key := 0;
  855. Delete;
  856. end;
  857. end;
  858. end;
  859. procedure TTBItemEditForm.TreeViewKeyDown(Sender: TObject; var Key: Word;
  860. Shift: TShiftState);
  861. begin
  862. case Key of
  863. VK_RETURN: begin
  864. Key := 0;
  865. ActivateInspector(#0);
  866. end;
  867. VK_DELETE: begin
  868. Key := 0;
  869. DeleteButtonClick(Sender);
  870. end;
  871. end;
  872. end;
  873. procedure TTBItemEditForm.TreeViewKeyPress(Sender: TObject; var Key: Char);
  874. begin
  875. if {MP} CharInSet(Key, [#33..#126]) then begin
  876. ActivateInspector(Key);
  877. Key := #0;
  878. end
  879. else if Key = #13 then
  880. Key := #0; { suppress beep }
  881. end;
  882. procedure TTBItemEditForm.ListViewKeyPress(Sender: TObject; var Key: Char);
  883. begin
  884. if Key = '-' then begin
  885. NewSepButtonClick(Sender);
  886. Key := #0;
  887. end
  888. else if {MP} CharInSet(Key, [#33..#126]) then begin
  889. ActivateInspector(Key);
  890. Key := #0;
  891. end;
  892. end;
  893. procedure TTBItemEditForm.ListViewDragOver(Sender, Source: TObject; X,
  894. Y: Integer; State: TDragState; var Accept: Boolean);
  895. { List item dragged over the list view }
  896. var
  897. Item: TListItem;
  898. begin
  899. Accept := False;
  900. if (Sender = ListView) and (Source = ListView) and (ListView.SelCount = 1) then begin
  901. Item := ListView.GetItemAt(X, Y);
  902. if Assigned(Item) and (Item <> ListView.Selected) then
  903. Accept := True;
  904. end;
  905. end;
  906. procedure TTBItemEditForm.ListViewDragDrop(Sender, Source: TObject; X,
  907. Y: Integer);
  908. { List item dropped onto another list item }
  909. var
  910. ListItem: TListItem;
  911. Item: TTBCustomItem;
  912. NewIndex: Integer;
  913. begin
  914. if (Sender = ListView) and (Source = ListView) and (ListView.SelCount = 1) then begin
  915. ListItem := ListView.GetItemAt(X, Y);
  916. if Assigned(ListItem) and (ListItem <> ListView.Selected) and Assigned(FSelParentItem) then begin
  917. NewIndex := FSelParentItem.IndexOf(ListItem.Data);
  918. if NewIndex <> -1 then begin
  919. ListView.Items.BeginUpdate;
  920. { For good performance and to prevent Object Inspector flicker, increment
  921. FSettingSel to prevent calls to SetSelParentItem while moving items }
  922. Inc(FSettingSel);
  923. try
  924. Item := ListView.Selected.Data;
  925. MoveItem(FSelParentItem.IndexOf(Item), NewIndex);
  926. finally
  927. Dec(FSettingSel);
  928. ListView.Items.EndUpdate;
  929. end;
  930. { After decrementing FSettingSel, now call SetSelParentItem, to update
  931. the toolbar buttons }
  932. SetSelParentItem(FSelParentItem);
  933. end;
  934. end;
  935. end;
  936. end;
  937. function TTBItemEditForm.TreeViewDragHandler(Sender, Source: TObject;
  938. X, Y: Integer; Drop: Boolean): Boolean;
  939. var
  940. Node: TTreeNode;
  941. ListItem: TListItem;
  942. Item, NewParentItem: TTBCustomItem;
  943. ItemList: TList;
  944. I: Integer;
  945. NeedRebuildTree: Boolean;
  946. begin
  947. Result := False;
  948. if (Sender = TreeView) and (Source = ListView) then begin
  949. Node := TreeView.GetNodeAt(X, Y);
  950. if Assigned(Node) and (Node <> TreeView.Selected) then begin
  951. NewParentItem := Node.Data;
  952. ItemList := TList.Create;
  953. try
  954. ListItem := nil;
  955. while True do begin
  956. ListItem := ListView.GetNextItem(ListItem, sdAll, [isSelected]);
  957. if ListItem = nil then
  958. Break;
  959. Item := ListItem.Data;
  960. if Assigned(Item) and (Item <> NewParentItem) and
  961. not Item.ContainsItem(NewParentItem) and
  962. not(Item is TTBControlItem) then begin
  963. Result := True;
  964. ItemList.Add(Item);
  965. end;
  966. end;
  967. if Drop then begin
  968. NeedRebuildTree := False;
  969. for I := 0 to ItemList.Count-1 do begin
  970. Item := ItemList[I];
  971. Item.Parent.Remove(Item);
  972. NewParentItem.Add(Item);
  973. Designer.Modified;
  974. if IsSubmenuItem(Item) then
  975. NeedRebuildTree := True;
  976. end;
  977. if NeedRebuildTree then
  978. RebuildTree;
  979. end;
  980. finally
  981. ItemList.Free;
  982. end;
  983. end;
  984. end;
  985. end;
  986. procedure TTBItemEditForm.TreeViewDragOver(Sender, Source: TObject; X,
  987. Y: Integer; State: TDragState; var Accept: Boolean);
  988. { List item dragged over the tree view }
  989. begin
  990. Accept := TreeViewDragHandler(Sender, Source, X, Y, False);
  991. end;
  992. procedure TTBItemEditForm.TreeViewDragDrop(Sender, Source: TObject; X,
  993. Y: Integer);
  994. { List item dropped onto the tree view }
  995. begin
  996. TreeViewDragHandler(Sender, Source, X, Y, True);
  997. end;
  998. procedure TTBItemEditForm.CreateNewItem(const AClass: TTBCustomItemClass);
  999. var
  1000. NewIndex: Integer;
  1001. NewItem: TTBCustomItem;
  1002. ListItem: TListItem;
  1003. begin
  1004. if FSelParentItem = nil then Exit;
  1005. NewIndex := -1;
  1006. if (GetKeyState(VK_SHIFT) >= 0) and Assigned(ListView.Selected) then
  1007. NewIndex := FSelParentItem.IndexOf(ListView.Selected.Data);
  1008. if NewIndex = -1 then
  1009. NewIndex := FSelParentItem.Count;
  1010. NewItem := AClass.Create(FParentComponent.Owner{Designer.Form});
  1011. try
  1012. NewItem.Name := Designer.UniqueName(NewItem.ClassName);
  1013. FSelParentItem.Insert(NewIndex, NewItem);
  1014. except
  1015. NewItem.Free;
  1016. raise;
  1017. end;
  1018. Designer.Modified;
  1019. ListView.Selected := nil;
  1020. ListItem := ListView.FindData(0, NewItem, True, False);
  1021. if Assigned(ListItem) then begin
  1022. ListItem.Selected := True;
  1023. ListItem.Focused := True;
  1024. ListItem.MakeVisible(False);
  1025. ListView.SetFocus;
  1026. end;
  1027. end;
  1028. procedure TTBItemEditForm.NewSubmenuButtonClick(Sender: TObject);
  1029. begin
  1030. CreateNewItem(TTBSubmenuItem);
  1031. end;
  1032. procedure TTBItemEditForm.NewItemButtonClick(Sender: TObject);
  1033. begin
  1034. CreateNewItem(TTBItem);
  1035. end;
  1036. procedure TTBItemEditForm.NewSepButtonClick(Sender: TObject);
  1037. begin
  1038. CreateNewItem(TTBSeparatorItem);
  1039. end;
  1040. procedure TTBItemEditForm.MoreItemClick(Sender: TObject);
  1041. begin
  1042. CreateNewItem(TTBCustomItemClass((Sender as TTBItem).Tag));
  1043. end;
  1044. procedure TTBItemEditForm.CutButtonClick(Sender: TObject);
  1045. begin
  1046. Cut;
  1047. end;
  1048. procedure TTBItemEditForm.CopyButtonClick(Sender: TObject);
  1049. begin
  1050. Copy;
  1051. end;
  1052. procedure TTBItemEditForm.PasteButtonClick(Sender: TObject);
  1053. begin
  1054. Paste;
  1055. end;
  1056. procedure TTBItemEditForm.DeleteButtonClick(Sender: TObject);
  1057. begin
  1058. if ActiveControl = ListView then
  1059. Delete
  1060. else if (ActiveControl = TreeView) and (FSelParentItem <> FRootItem) then
  1061. DeleteItem(FSelParentItem);
  1062. end;
  1063. procedure TTBItemEditForm.MoveUpButtonClick(Sender: TObject);
  1064. var
  1065. SelList: TList;
  1066. I, J: Integer;
  1067. Item: TTBCustomItem;
  1068. ListItem: TListItem;
  1069. begin
  1070. if FSelParentItem = nil then Exit;
  1071. SelList := TList.Create;
  1072. try
  1073. GetSelItemList(SelList);
  1074. if SelList.Count = 0 then Exit;
  1075. ListView.Items.BeginUpdate;
  1076. FSelParentItem.ViewBeginUpdate;
  1077. { For good performance and to prevent Object Inspector flicker, increment
  1078. FSettingSel to prevent calls to SetSelParentItem while moving items }
  1079. Inc(FSettingSel);
  1080. try
  1081. for I := 0 to SelList.Count-1 do begin
  1082. Item := SelList[I];
  1083. J := FSelParentItem.IndexOf(Item);
  1084. if J <> -1 then
  1085. MoveItem(J, J-1);
  1086. end;
  1087. ListItem := ListView.FindData(0, SelList[0], True, False);
  1088. if Assigned(ListItem) then
  1089. ListItem.MakeVisible(False);
  1090. finally
  1091. Dec(FSettingSel);
  1092. FSelParentItem.ViewEndUpdate;
  1093. ListView.Items.EndUpdate;
  1094. end;
  1095. { After decrementing FSettingSel, now call SetSelParentItem, to update
  1096. the toolbar buttons }
  1097. SetSelParentItem(FSelParentItem);
  1098. finally
  1099. SelList.Free;
  1100. end;
  1101. end;
  1102. procedure TTBItemEditForm.MoveDownButtonClick(Sender: TObject);
  1103. var
  1104. SelList: TList;
  1105. I, J: Integer;
  1106. Item: TTBCustomItem;
  1107. ListItem: TListItem;
  1108. begin
  1109. if FSelParentItem = nil then Exit;
  1110. SelList := TList.Create;
  1111. try
  1112. GetSelItemList(SelList);
  1113. if SelList.Count = 0 then Exit;
  1114. ListView.Items.BeginUpdate;
  1115. FSelParentItem.ViewBeginUpdate;
  1116. { For good performance and to prevent Object Inspector flicker, increment
  1117. FSettingSel to prevent calls to SetSelParentItem while moving items }
  1118. Inc(FSettingSel);
  1119. try
  1120. for I := SelList.Count-1 downto 0 do begin
  1121. Item := SelList[I];
  1122. J := FSelParentItem.IndexOf(Item);
  1123. if J <> -1 then
  1124. MoveItem(J, J+1);
  1125. end;
  1126. ListItem := ListView.FindData(0, SelList[SelList.Count-1], True, False);
  1127. if Assigned(ListItem) then
  1128. ListItem.MakeVisible(False);
  1129. finally
  1130. Dec(FSettingSel);
  1131. FSelParentItem.ViewEndUpdate;
  1132. ListView.Items.EndUpdate;
  1133. end;
  1134. { After decrementing FSettingSel, now call SetSelParentItem, to update
  1135. the toolbar buttons }
  1136. SetSelParentItem(FSelParentItem);
  1137. finally
  1138. SelList.Free;
  1139. end;
  1140. end;
  1141. procedure TTBItemEditForm.TConvertMenuClick(Sender: TObject);
  1142. begin
  1143. if FSelParentItem = nil then Exit;
  1144. DoConvert(FSelParentItem, FParentComponent.Owner);
  1145. end;
  1146. { TTBItemsEditor }
  1147. procedure TTBItemsEditor.Edit;
  1148. var
  1149. Intf: ITBItems;
  1150. begin
  1151. if Assigned(Component) and Component.GetInterface(ITBItems, Intf) then
  1152. ShowEditForm(Component, Intf.GetItems, Designer);
  1153. end;
  1154. procedure TTBItemsEditor.ExecuteVerb(Index: Integer);
  1155. begin
  1156. case Index of
  1157. 0: Edit;
  1158. 1: ShowVersion;
  1159. end;
  1160. end;
  1161. function TTBItemsEditor.GetVerbCount: Integer;
  1162. begin
  1163. Result := 2;
  1164. end;
  1165. function TTBItemsEditor.GetVerb(Index: Integer): String;
  1166. begin
  1167. case Index of
  1168. 0: Result := 'Edit...';
  1169. 1: Result := 'Version...';
  1170. else
  1171. Result := '';
  1172. end;
  1173. end;
  1174. { TTBItemsPropertyEditor }
  1175. procedure TTBItemsPropertyEditor.Edit;
  1176. var
  1177. Editor: IComponentEditor;
  1178. begin
  1179. if PropCount <> 1 then Exit;
  1180. Editor := GetComponentEditor(GetComponent(0) as TComponent, Designer);
  1181. Editor.Edit;
  1182. end;
  1183. function TTBItemsPropertyEditor.GetAttributes: TPropertyAttributes;
  1184. begin
  1185. Result := inherited GetAttributes + [paDialog, paReadOnly];
  1186. end;
  1187. function TTBItemsPropertyEditor.GetValue: String;
  1188. begin
  1189. Result := '(TB2000 Items)';
  1190. end;
  1191. procedure TBRegisterDsgnEditorHook(Hook: TTBDsgnEditorHook);
  1192. var
  1193. H: ^TTBDsgnEditorHook;
  1194. begin
  1195. New(H);
  1196. H^ := Hook;
  1197. EditFormHooks.Add(H);
  1198. end;
  1199. procedure TBUnregisterDsgnEditorHook(Hook: TTBDsgnEditorHook);
  1200. var
  1201. H: ^TTBDsgnEditorHook;
  1202. I: Integer;
  1203. begin
  1204. for I := EditFormHooks.Count - 1 downto 0 do
  1205. begin
  1206. H := EditFormHooks[I];
  1207. if (TMethod(H^).Code = TMethod(Hook).Code) and
  1208. (TMethod(H^).Data = TMethod(Hook).Data) then
  1209. begin
  1210. Dispose(H);
  1211. EditFormHooks.Delete(I);
  1212. // Break;
  1213. end;
  1214. end;
  1215. end;
  1216. initialization
  1217. ItemImageList := TImageList.Create(nil);
  1218. ItemImageList.Handle := ImageList_LoadImage(HInstance, 'TB2_DSGNEDITORIMAGES',
  1219. 16, 0, clFuchsia, IMAGE_BITMAP, 0);
  1220. ItemClasses := TList.Create;
  1221. EditFormHooks := TList.Create;
  1222. AddModuleUnloadProc(UnregisterModuleItemClasses);
  1223. finalization
  1224. RemoveModuleUnloadProc(UnregisterModuleItemClasses);
  1225. FreeItemClasses;
  1226. FreeAndNil(ItemImageList);
  1227. FreeAndNil(EditFormHooks);
  1228. end.