12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331 |
- unit TB2DsgnItemEditor;
- {
- Toolbar2000
- Copyright (C) 1998-2005 by Jordan Russell
- All rights reserved.
- The contents of this file are subject to the "Toolbar2000 License"; you may
- not use or distribute this file except in compliance with the
- "Toolbar2000 License". A copy of the "Toolbar2000 License" may be found in
- TB2k-LICENSE.txt or at:
- https://jrsoftware.org/files/tb2k/TB2k-LICENSE.txt
- Alternatively, the contents of this file may be used under the terms of the
- GNU General Public License (the "GPL"), in which case the provisions of the
- GPL are applicable instead of those in the "Toolbar2000 License". A copy of
- the GPL may be found in GPL-LICENSE.txt or at:
- https://jrsoftware.org/files/tb2k/GPL-LICENSE.txt
- If you wish to allow use of your version of this file only under the terms of
- the GPL and not to allow others to use your version of this file under the
- "Toolbar2000 License", indicate your decision by deleting the provisions
- above and replace them with the notice and other provisions required by the
- GPL. If you do not delete the provisions above, a recipient may use your
- version of this file under either the "Toolbar2000 License" or the GPL.
- $jrsoftware: tb2k/Source/TB2DsgnItemEditor.pas,v 1.55 2005/01/27 06:48:53 jr Exp $
- }
- interface
- {$I TB2Ver.inc}
- uses
- Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
- StdCtrls, ExtCtrls, Buttons, ComCtrls, ImgList, Menus,
- TB2Item, TB2Toolbar, TB2Dock,
- DesignWindows, DesignEditors, DesignIntf;
- type
- TTBItemEditForm = class(TDesignWindow)
- TreeView: TTreeView;
- ListView: TListView;
- Splitter1: TSplitter;
- Toolbar: TTBToolbar;
- NewSubmenuButton: TTBItem;
- NewItemButton: TTBItem;
- NewSepButton: TTBItem;
- DeleteButton: TTBItem;
- TBSeparatorItem1: TTBSeparatorItem;
- TBPopupMenu1: TTBPopupMenu;
- TBItemContainer1: TTBItemContainer;
- ToolbarItems: TTBSubmenuItem;
- CopyButton: TTBItem;
- CutButton: TTBItem;
- PasteButton: TTBItem;
- MoreMenu: TTBSubmenuItem;
- TBSeparatorItem2: TTBSeparatorItem;
- TBSubmenuItem1: TTBSubmenuItem;
- TConvertMenu: TTBItem;
- TBSeparatorItem3: TTBSeparatorItem;
- MoveUpButton: TTBItem;
- MoveDownButton: TTBItem;
- procedure FormClose(Sender: TObject; var Action: TCloseAction);
- procedure TreeViewChange(Sender: TObject; Node: TTreeNode);
- procedure NewSubmenuButtonClick(Sender: TObject);
- procedure NewItemButtonClick(Sender: TObject);
- procedure ListViewChange(Sender: TObject; Item: TListItem;
- Change: TItemChange);
- procedure DeleteButtonClick(Sender: TObject);
- procedure NewSepButtonClick(Sender: TObject);
- procedure ListViewDragOver(Sender, Source: TObject; X, Y: Integer;
- State: TDragState; var Accept: Boolean);
- procedure ListViewDragDrop(Sender, Source: TObject; X, Y: Integer);
- procedure TreeViewEnter(Sender: TObject);
- procedure TreeViewDragDrop(Sender, Source: TObject; X, Y: Integer);
- procedure TreeViewDragOver(Sender, Source: TObject; X, Y: Integer;
- State: TDragState; var Accept: Boolean);
- procedure CopyButtonClick(Sender: TObject);
- procedure ListViewKeyDown(Sender: TObject; var Key: Word;
- Shift: TShiftState);
- procedure CutButtonClick(Sender: TObject);
- procedure PasteButtonClick(Sender: TObject);
- procedure FormActivate(Sender: TObject);
- procedure ListViewKeyPress(Sender: TObject; var Key: Char);
- procedure ListViewDblClick(Sender: TObject);
- procedure ListViewEnter(Sender: TObject);
- procedure TreeViewKeyDown(Sender: TObject; var Key: Word;
- Shift: TShiftState);
- procedure TConvertMenuClick(Sender: TObject);
- procedure TreeViewKeyPress(Sender: TObject; var Key: Char);
- procedure MoveUpButtonClick(Sender: TObject);
- procedure MoveDownButtonClick(Sender: TObject);
- private
- FParentComponent: TComponent;
- FRootItem, FSelParentItem: TTBCustomItem;
- FNotifyItemList: TList;
- FSettingSel, FRebuildingTree, FRebuildingList: Integer;
- function AddListViewItem(const Index: Integer;
- const Item: TTBCustomItem): TListItem;
- procedure Copy;
- procedure CreateNewItem(const AClass: TTBCustomItemClass);
- procedure Cut;
- procedure Delete;
- procedure DeleteItem(const Item: TTBCustomItem);
- function GetItemTreeCaption(AItem: TTBCustomItem): String;
- procedure GetSelItemList(const AList: TList);
- procedure ItemNotification(Ancestor: TTBCustomItem; Relayed: Boolean;
- Action: TTBItemChangedAction; Index: Integer; Item: TTBCustomItem);
- procedure MoreItemClick(Sender: TObject);
- procedure MoveItem(CurIndex, NewIndex: Integer);
- procedure Paste;
- procedure RebuildList;
- procedure RebuildTree;
- procedure SelectInObjectInspector(AList: TList);
- procedure SetSelParentItem(ASelParentItem: TTBCustomItem);
- function TreeViewDragHandler(Sender, Source: TObject; X, Y: Integer;
- Drop: Boolean): Boolean;
- procedure UnregisterAllNotifications;
- protected
- procedure Notification(AComponent: TComponent; Operation: TOperation); override;
- function UniqueName(Component: TComponent): String; override;
- public
- constructor Create(AOwner: TComponent); override;
- destructor Destroy; override;
- function EditAction(Action: TEditAction): Boolean; override;
- function GetEditState: TEditState; override;
- end;
- TTBItemsEditor = class(TDefaultEditor)
- public
- procedure Edit; override;
- procedure ExecuteVerb(Index: Integer); override;
- function GetVerb(Index: Integer): String; override;
- function GetVerbCount: Integer; override;
- end;
- TTBItemsPropertyEditor = class(TStringProperty)
- public
- procedure Edit; override;
- function GetAttributes: TPropertyAttributes; override;
- function GetValue: String; override;
- end;
- procedure TBRegisterItemClass(AClass: TTBCustomItemClass;
- const ACaption: String; ResInstance: HINST);
- type
- TTBDsgnEditorHook = procedure(Sender: TTBItemEditForm) of object;
- procedure TBRegisterDsgnEditorHook(Hook: TTBDsgnEditorHook);
- procedure TBUnregisterDsgnEditorHook(Hook: TTBDsgnEditorHook);
- implementation
- {$R *.DFM}
- uses
- TypInfo, CommCtrl, TB2Version, TB2Common, TB2DsgnConverter;
- type
- TTBCustomItemAccess = class(TTBCustomItem);
- TControlAccess = class(TControl);
- TDesignerSelectionList = IDesignerSelections;
- PItemClassInfo = ^TItemClassInfo;
- TItemClassInfo = record
- ItemClass: TTBCustomItemClass;
- Caption: String;
- ImageIndex: Integer;
- end;
- var
- ItemClasses: TList;
- ItemImageList: TImageList;
- EditFormHooks: TList;
- procedure FreeItemClasses;
- var
- I: Integer;
- IC: TList;
- begin
- if ItemClasses = nil then Exit;
- IC := ItemClasses;
- ItemClasses := nil;
- for I := IC.Count-1 downto 0 do
- Dispose(PItemClassInfo(IC[I]));
- IC.Free;
- end;
- procedure UnregisterModuleItemClasses(AModule: NativeInt);
- var
- I: Integer;
- Info: PItemClassInfo;
- begin
- I := 0;
- while I < ItemClasses.Count do begin
- Info := ItemClasses[I];
- if FindClassHInstance(Info.ItemClass) = HINST(AModule) then begin
- ItemClasses.Delete(I);
- Dispose(Info);
- end
- else
- Inc(I);
- end;
- { Note: TTBItemEditForm also holds references to item classes, but since
- Delphi automatically closes all editor forms before compiling/removing
- a package, we don't need to remove them. }
- end;
- function LoadItemImage(Instance: HINST; const ResName: String): Integer;
- var
- Bmp: TBitmap;
- begin
- Bmp := TBitmap.Create;
- try
- Bmp.Handle := LoadBitmap(Instance, PChar(ResName));
- if Bmp.Handle = 0 then
- Result := -1
- else
- Result := ItemImageList.AddMasked(Bmp, Bmp.Canvas.Pixels[0, Bmp.Height-1]);
- finally
- Bmp.Free;
- end;
- end;
- procedure TBRegisterItemClass(AClass: TTBCustomItemClass;
- const ACaption: String; ResInstance: HINST);
- var
- Info: PItemClassInfo;
- I: Integer;
- begin
- if ItemClasses <> nil then
- for I := ItemClasses.Count - 1 downto 0 do
- begin
- Info := ItemClasses[I];
- if Info.ItemClass = AClass then
- begin
- Dispose(Info);
- ItemClasses.Delete(I);
- end;
- end;
- New(Info);
- Info.ItemClass := AClass;
- Info.Caption := ACaption;
- Info.ImageIndex := LoadItemImage(ResInstance, Uppercase(AClass.ClassName));
- ItemClasses.Add(Info);
- end;
- function GetItemClassImage(AClass: TTBCustomItemClass): Integer;
- var
- I: Integer;
- Info: PItemClassInfo;
- begin
- for I := ItemClasses.Count-1 downto 0 do begin
- Info := ItemClasses[I];
- if AClass.InheritsFrom(Info.ItemClass) then begin
- Result := Info.ImageIndex;
- if Result >= 0 then
- Exit;
- end;
- end;
- if AClass.InheritsFrom(TTBSubmenuItem) then
- Result := 1
- else if AClass.InheritsFrom(TTBSeparatorItem) then
- Result := 2
- else
- Result := 0;
- end;
- procedure ShowEditForm(AParentComponent: TComponent; ARootItem: TTBCustomItem;
- const ADesigner: IDesigner);
- var
- I: Integer;
- Form: TCustomForm;
- EditForm: TTBItemEditForm;
- begin
- if Assigned(ARootItem.LinkSubitems) then begin
- case MessageDlg(Format('The LinkSubitems property is set to ''%s''. ' +
- 'Would you like to edit that item instead?',
- [ARootItem.LinkSubitems.Name]), mtConfirmation, [mbYes, mbNo, mbCancel], 0) of
- mrYes: begin
- AParentComponent := ARootItem.LinkSubitems;
- ARootItem := ARootItem.LinkSubitems;
- end;
- mrCancel: Exit;
- end;
- end;
- for I := 0 to Screen.FormCount-1 do begin
- Form := Screen.Forms[I];
- if Form is TTBItemEditForm then
- if TTBItemEditForm(Form).FRootItem = ARootItem then begin
- Form.Show;
- if Form.WindowState = wsMinimized then
- Form.WindowState := wsNormal;
- Exit;
- end;
- end;
- EditForm := TTBItemEditForm.Create(Application);
- try
- EditForm.Designer := ADesigner;
- EditForm.FParentComponent := AParentComponent;
- AParentComponent.FreeNotification(EditForm);
- EditForm.FRootItem := ARootItem;
- ARootItem.FreeNotification(EditForm);
- EditForm.FSelParentItem := ARootItem;
- EditForm.Caption := 'Editing ' + AParentComponent.Name;
- EditForm.RebuildTree;
- EditForm.RebuildList;
- EditForm.PopupMode := pmExplicit;
- EditForm.Show;
- except
- EditForm.Free;
- raise;
- end;
- end;
- function IsSubmenuItem(Item: TTBCustomItem): Boolean;
- begin
- Result := tbisSubitemsEditable in TTBCustomItemAccess(Item).ItemStyle;
- end;
- procedure ShowVersion;
- const
- AboutText =
- '%s'#13#10 +
- 'Copyright (C) 1998-2005 by Jordan Russell'#13#10 +
- 'For conditions of distribution and use, see LICENSE.TXT.'#13#10 +
- #13#10 +
- 'Visit my web site for the latest versions of Toolbar2000:'#13#10 +
- 'https://jrsoftware.org/';
- begin
- MessageDlg(Format(AboutText, [Toolbar2000VersionPropText]), mtInformation,
- [mbOK], 0);
- end;
- { TTBItemEditForm }
- constructor TTBItemEditForm.Create(AOwner: TComponent);
- var
- I: Integer;
- Info: PItemClassInfo;
- Item: TTBItem;
- begin
- inherited;
- FNotifyItemList := TList.Create;
- ToolbarItems.SubMenuImages := ItemImageList;
- ListView.SmallImages := ItemImageList;
- { Populate the 'More' menu }
- for I := 0 to ItemClasses.Count-1 do begin
- Info := ItemClasses[I];
- Item := TTBItem.Create(Self);
- Item.Caption := Info.Caption;
- Item.ImageIndex := GetItemClassImage(Info.ItemClass);
- Item.Tag := Integer(Info.ItemClass);
- Item.OnClick := MoreItemClick;
- MoreMenu.Add(Item);
- end;
- { Run the hooks }
- if EditFormHooks <> nil then
- for I := 0 to EditFormHooks.Count - 1 do
- TTBDsgnEditorHook(EditFormHooks[I]^)(Self);
- end;
- destructor TTBItemEditForm.Destroy;
- begin
- inherited;
- if Assigned(FNotifyItemList) then begin
- UnregisterAllNotifications;
- FNotifyItemList.Free;
- FNotifyItemList := nil;
- end;
- end;
- procedure TTBItemEditForm.FormClose(Sender: TObject;
- var Action: TCloseAction);
- begin
- Action := caFree;
- end;
- procedure TTBItemEditForm.FormActivate(Sender: TObject);
- begin
- SetSelParentItem(FSelParentItem);
- end;
- procedure TTBItemEditForm.Notification(AComponent: TComponent;
- Operation: TOperation);
- begin
- inherited;
- if (Operation = opRemove) and
- ((AComponent = FParentComponent) or (AComponent = FRootItem)) then
- { Must use Free instead of Close, since Close causes the freeing of the
- form to be delayed until the next message. We have to destroy the form
- immediately, otherwise Delphi will crash when Compile is clicked on the
- TB2k package. }
- Free;
- {}{temp:}
- (*if (Operation = opRemove) and (FNotifyItemList.IndexOf(AComponent) <> -1) then begin
- outputdebugstring(pchar('Still in list: ' + AComponent.name));
- //beep;
- end;*)
- end;
- function TTBItemEditForm.UniqueName(Component: TComponent): String;
- begin
- Result := Designer.UniqueName(Component.ClassName);
- end;
- function TTBItemEditForm.GetEditState: TEditState;
- begin
- Result := [];
- if ActiveControl = ListView then begin
- if Assigned(ListView.Selected) then
- Result := [esCanDelete, esCanCut, esCanCopy];
- if ClipboardComponents then
- Include(Result, esCanPaste);
- end;
- end;
- function TTBItemEditForm.EditAction(Action: TEditAction): Boolean;
- begin
- Result := True;
- case Action of
- eaCut: Cut;
- eaCopy: Copy;
- eaPaste: Paste;
- eaDelete: Delete;
- else
- Result := False;
- end;
- end;
- procedure TTBItemEditForm.UnregisterAllNotifications;
- var
- I: Integer;
- begin
- for I := FNotifyItemList.Count-1 downto 0 do begin
- //outputdebugstring(pchar('Unregall: ' + TTBCustomItem(FNotifyItemList[I]).name));
- TTBCustomItem(FNotifyItemList[I]).UnregisterNotification(ItemNotification);
- FNotifyItemList.Delete(I);
- end;
- end;
- procedure TTBItemEditForm.ItemNotification(Ancestor: TTBCustomItem;
- Relayed: Boolean; Action: TTBItemChangedAction; Index: Integer;
- Item: TTBCustomItem);
- var
- ListItem: TListItem;
- TreeNode: TTreeNode;
- I: Integer;
- C: String;
- begin
- { Manipulate the list view when items are inserted, deleted, or their Caption
- changes }
- case Action of
- tbicInserted:
- begin
- if (Ancestor = FSelParentItem) and not Relayed then
- AddListViewItem(Index, Item);
- if IsSubmenuItem(Item) then
- RebuildTree;
- end;
- tbicDeleting:
- if (Ancestor = FSelParentItem) and not Relayed then begin
- ListItem := ListView.FindData(0, Item, True, False);
- if Assigned(ListItem) then
- ListItem.Delete;
- end;
- tbicInvalidateAndResize:
- if (Ancestor = FSelParentItem) and not Relayed then begin
- ListItem := ListView.FindData(0, Item, True, False);
- if Assigned(ListItem) and (ListItem.Caption <> TTBCustomItem(Item).Caption) then
- ListItem.Caption := TTBCustomItem(Item).Caption;
- end;
- end;
- { Update tree view when an item is deleted, or a Caption changes }
- if Action = tbicDeleting then begin
- I := FNotifyItemList.IndexOf(Item);
- if I <> -1 then begin
- //outputdebugstring(pchar('Deleting, so unreging: ' + item.name));
- TTBCustomItem(Item).UnregisterNotification(ItemNotification);
- FNotifyItemList.Delete(I);
- end;
- end;
- if Action in [tbicDeleting, tbicInvalidateAndResize, tbicNameChanged] then begin
- TreeNode := TreeView.Items.GetFirstNode;
- while Assigned(TreeNode) do begin
- if TreeNode.Data = Item then begin
- if Action = tbicDeleting then begin
- TreeNode.Delete;
- if FSelParentItem = Item then
- SetSelParentItem(TTBCustomItem(Item).Parent);
- end
- else begin
- { tbicInvalidateAndResize, tbicNameChanged: }
- C := GetItemTreeCaption(Item);
- if TreeNode.Text <> C then
- TreeNode.Text := C;
- end;
- Break;
- end;
- TreeNode := TreeNode.GetNext;
- end;
- end;
- end;
- function TTBItemEditForm.GetItemTreeCaption(AItem: TTBCustomItem): String;
- begin
- if AItem <> FRootItem then begin
- Result := AItem.Caption;
- if Result = '' then
- Result := '[' + AItem.Name + ']';
- end
- else
- Result := '(Root)';
- end;
- procedure TTBItemEditForm.RebuildTree;
- procedure Recurse(const AParentItem: TTBCustomItem; const ATreeNode: TTreeNode;
- var FoundSelParentItem: TTreeNode);
- var
- I: Integer;
- NewNode: TTreeNode;
- ChildItem: TTBCustomItem;
- begin
- {}AParentItem.FreeNotification(Self);
- AParentItem.RegisterNotification(ItemNotification);
- FNotifyItemList.Add(AParentItem);
- NewNode := TreeView.Items.AddChild(ATreeNode, GetItemTreeCaption(AParentItem));
- NewNode.Data := AParentItem;
- if AParentItem = FSelParentItem then
- FoundSelParentItem := NewNode;
- for I := 0 to AParentItem.Count-1 do begin
- ChildItem := AParentItem[I];
- if IsSubmenuItem(ChildItem) then
- Recurse(ChildItem, NewNode, FoundSelParentItem);
- end;
- end;
- var
- FoundSelParentItem: TTreeNode;
- begin
- Inc(FRebuildingTree);
- try
- TreeView.Items.BeginUpdate;
- try
- TreeView.Items.Clear;
- UnregisterAllNotifications;
- FoundSelParentItem := nil;
- Recurse(FRootItem, nil, FoundSelParentItem);
- if FoundSelParentItem = nil then
- SetSelParentItem(FRootItem)
- else
- TreeView.Selected := FoundSelParentItem;
- TreeView.Items[0].Expand(True);
- finally
- TreeView.Items.EndUpdate;
- end;
- finally
- Dec(FRebuildingTree);
- end;
- end;
- function TTBItemEditForm.AddListViewItem(const Index: Integer;
- const Item: TTBCustomItem): TListItem;
- begin
- Result := ListView.Items.Insert(Index);
- Result.Data := Item;
- if not(Item is TTBControlItem) then begin
- Result.Caption := Item.Caption;
- Result.Subitems.Add(Item.ClassName);
- Result.ImageIndex := GetItemClassImage(TTBCustomItemClass(Item.ClassType));
- end
- else begin
- Result.Caption := '(Control)';
- Result.Subitems.Add(Item.ClassName);
- Result.ImageIndex := -1;
- end;
- end;
- procedure TTBItemEditForm.RebuildList;
- var
- ChildItem: TTBCustomItem;
- I: Integer;
- begin
- Inc(FRebuildingList);
- try
- ListView.Items.BeginUpdate;
- try
- ListView.Items.Clear;
- if Assigned(FSelParentItem) then begin
- for I := 0 to FSelParentItem.Count-1 do begin
- ChildItem := FSelParentItem[I];
- { Check for csDestroying because deleting an item in the tree view
- causes the parent item to be selected, and the parent item won't
- get a notification that the item is deleting since notifications
- were already sent }
- if not(csDestroying in ChildItem.ComponentState) then
- AddListViewItem(I, ChildItem);
- end;
- { Add an empty item to the end }
- ListView.Items.Add.ImageIndex := -1;
- end;
- finally
- ListView.Items.EndUpdate;
- end;
- { Work around a strange TListView bug(?). Without this, the column header
- isn't painted properly. }
- if HandleAllocated then
- SetWindowPos(ListView.Handle, 0, 0, 0, 0, 0, SWP_FRAMECHANGED or
- SWP_NOACTIVATE or SWP_NOMOVE or SWP_NOSIZE or SWP_NOZORDER);
- finally
- Dec(FRebuildingList);
- end;
- end;
- procedure TTBItemEditForm.SelectInObjectInspector(AList: TList);
- var
- CompList1, CompList2: TDesignerSelectionList;
- I: Integer;
- C: TComponent;
- begin
- { Designer.SetSelections will make components appear selected on the form.
- It will also select the component in Object Inspector, but only if the
- form has the focus. TDesignWindow.SetSelection will select the component
- in Object Inspector regardless of whether the form has the focus. }
- CompList1 := CreateSelectionList;
- CompList2 := CreateSelectionList;
- for I := 0 to AList.Count-1 do begin
- C := AList[I];
- { Must check for csDestroying. If SetSelection is passed a component that's
- destroying, Delphi will crash. }
- if not(csDestroying in C.ComponentState) then begin
- CompList1.Add(C);
- CompList2.Add(C);
- end;
- end;
- if CompList1.Count <> 0 then
- begin
- Designer.SetSelections(CompList1);
- end;
- end;
- procedure TTBItemEditForm.GetSelItemList(const AList: TList);
- var
- ListItem: TListItem;
- begin
- ListItem := nil;
- while True do begin
- ListItem := ListView.GetNextItem(ListItem, sdAll, [isSelected]);
- if ListItem = nil then
- Break;
- if Assigned(ListItem.Data) then
- AList.Add(ListItem.Data);
- end;
- end;
- procedure TTBItemEditForm.SetSelParentItem(ASelParentItem: TTBCustomItem);
- { - Rebuilds the list view to match a new selection (ASelParentItem) in the
- tree view
- - Updates toolbar
- - Selects selected item(s) into Object Inspector }
- var
- I: Integer;
- TreeNode: TTreeNode;
- ItemIsSelected: Boolean;
- List: TList;
- begin
- if FSettingSel > 0 then
- Exit;
- List := TList.Create;
- Inc(FSettingSel);
- try
- if FSelParentItem <> ASelParentItem then begin
- FSelParentItem := ASelParentItem;
- NewSubmenuButton.Enabled := Assigned(ASelParentItem);
- NewItemButton.Enabled := Assigned(ASelParentItem);
- NewSepButton.Enabled := Assigned(ASelParentItem);
- for I := 0 to MoreMenu.Count-1 do
- MoreMenu[I].Enabled := Assigned(ASelParentItem);
- if not Assigned(TreeView.Selected) or (TreeView.Selected.Data <> FSelParentItem) then begin
- if FSelParentItem = nil then
- TreeView.Selected := nil
- else begin
- TreeNode := TreeView.Items.GetFirstNode;
- while Assigned(TreeNode) do begin
- if TreeNode.Data = FSelParentItem then begin
- TreeView.Selected := TreeNode;
- Break;
- end;
- TreeNode := TreeNode.GetNext;
- end;
- end;
- end;
- RebuildList;
- end;
- ItemIsSelected := (ActiveControl = ListView) and Assigned(ListView.Selected) and
- Assigned(ListView.Selected.Data);
- if ItemIsSelected then
- GetSelItemList(List);
- CutButton.Enabled := ItemIsSelected;
- CopyButton.Enabled := ItemIsSelected;
- PasteButton.Enabled := (ActiveControl = ListView);
- DeleteButton.Enabled := ItemIsSelected or
- ((ActiveControl = TreeView) and (FSelParentItem <> FRootItem));
- MoveUpButton.Enabled := ItemIsSelected and
- (FSelParentItem.IndexOf(List.First) > 0);
- MoveDownButton.Enabled := ItemIsSelected and
- (FSelParentItem.IndexOf(List.Last) < FSelParentItem.Count-1);
- if ActiveControl = ListView then begin
- if List.Count = 0 then
- { No item was selected, or the blank item was selected.
- Select the root item so it looks like no item was selected in
- Object Inspector }
- List.Add(FRootItem);
- end
- else if not Assigned(ASelParentItem) or (ASelParentItem = FRootItem) then
- List.Add(FParentComponent)
- else
- List.Add(ASelParentItem);
- SelectInObjectInspector(List);
- finally
- Dec(FSettingSel);
- List.Free;
- end;
- end;
- procedure TTBItemEditForm.Cut;
- begin
- Copy;
- Delete;
- end;
- procedure TTBItemEditForm.Copy;
- var
- SelList: TList;
- CompList: TDesignerSelectionList;
- I: Integer;
- Item: TTBCustomItem;
- begin
- if ListView.Selected = nil then Exit;
- CompList := nil;
- SelList := TList.Create;
- try
- GetSelItemList(SelList);
- CompList := CreateSelectionList;
- for I := 0 to SelList.Count-1 do begin
- Item := SelList[I];
- if Item is TTBControlItem then
- raise EInvalidOperation.Create('Cannot cut or copy TTBControlItems');
- CompList.Add(Item);
- end;
- CopyComponents(FParentComponent.Owner, CompList);
- finally
- SelList.Free;
- end;
- end;
- procedure TTBItemEditForm.Paste;
- var
- CompList: TDesignerSelectionList;
- begin
- if FSelParentItem = nil then Exit;
- CompList := CreateSelectionList;
- PasteComponents(FParentComponent.Owner, FSelParentItem, CompList);
- if CompList.Count <> 0 then
- Designer.Modified;
- end;
- procedure TTBItemEditForm.DeleteItem(const Item: TTBCustomItem);
- begin
- if csAncestor in Item.ComponentState then
- raise EInvalidOperation.Create('Items introduced in an ancestor form cannot be deleted');
- Item.Free;
- Designer.Modified;
- end;
- procedure TTBItemEditForm.Delete;
- var
- List: TList;
- Item: TTBCustomItem;
- ListItem: TListItem;
- begin
- List := TList.Create;
- try
- List.Add(FSelParentItem);
- SelectInObjectInspector(List);
- finally
- List.Free;
- end;
- FSelParentItem.ViewBeginUpdate;
- try
- while Assigned(ListView.Selected) do begin
- Item := ListView.Selected.Data;
- if Item = nil then
- Break;
- DeleteItem(Item);
- end;
- finally
- FSelParentItem.ViewEndUpdate;
- end;
- { After deleting the items, select the item with the focus }
- ListItem := ListView.GetNextItem(nil, sdAll, [isFocused]);
- if Assigned(ListItem) then
- ListItem.Selected := True;
- end;
- procedure TTBItemEditForm.MoveItem(CurIndex, NewIndex: Integer);
- var
- WasFocused: Boolean;
- begin
- WasFocused := ListView.Items[CurIndex].Focused;
- FSelParentItem.Move(CurIndex, NewIndex);
- Designer.Modified;
- if WasFocused then
- ListView.Items[NewIndex].Focused := True;
- ListView.Items[NewIndex].Selected := True;
- end;
- procedure TTBItemEditForm.TreeViewChange(Sender: TObject; Node: TTreeNode);
- var
- NewSelectedParentItem: TTBCustomItem;
- begin
- if (FRebuildingTree > 0) or (FSettingSel > 0) then Exit;
- if Node = nil then
- NewSelectedParentItem := nil
- else
- NewSelectedParentItem := Node.Data;
- SetSelParentItem(NewSelectedParentItem);
- end;
- procedure TTBItemEditForm.TreeViewEnter(Sender: TObject);
- { When the tree view gets the focus, act as if the currently selected item
- was clicked. }
- begin
- ListView.Selected := nil;
- SetSelParentItem(FSelParentItem);
- end;
- procedure TTBItemEditForm.ListViewChange(Sender: TObject; Item: TListItem;
- Change: TItemChange);
- begin
- if (FRebuildingList > 0) or (FSettingSel > 0) or (Change <> ctState) or
- (csDestroying in ListView.ComponentState) then
- Exit;
- SetSelParentItem(FSelParentItem);
- end;
- procedure TTBItemEditForm.ListViewEnter(Sender: TObject);
- begin
- { When list view gets the focus, update the toolbar }
- SetSelParentItem(FSelParentItem);
- end;
- procedure TTBItemEditForm.ListViewDblClick(Sender: TObject);
- var
- SelItem: TTBCustomItem;
- PropCount, I: Integer;
- Props: PPropList;
- PropInfo: PPropInfo;
- MethodName: String;
- Method: TMethod;
- begin
- SelItem := nil;
- if Assigned(ListView.Selected) then
- SelItem := ListView.Selected.Data;
- if SelItem = nil then Exit;
- if IsSubmenuItem(SelItem) then begin
- SetSelParentItem(SelItem);
- Exit;
- end;
- PropCount := GetPropList(SelItem.ClassInfo, [tkMethod], nil);
- GetMem(Props, PropCount * SizeOf(PPropInfo));
- try
- GetPropList(SelItem.ClassInfo, [tkMethod], Props);
- for I := PropCount-1 downto 0 do begin
- PropInfo := Props[I];
- if CompareText({MP}string(PropInfo.Name), 'OnClick') = 0 then begin
- Method := GetMethodProp(SelItem, PropInfo);
- MethodName := Designer.GetMethodName(Method);
- if MethodName = '' then begin
- MethodName := SelItem.Name + 'Click';
- Method := Designer.CreateMethod(MethodName, GetTypeData(PropInfo.PropType^));
- SetMethodProp(SelItem, string(PropInfo.Name), Method);
- Designer.Modified;
- end;
- if Designer.MethodExists(MethodName) then
- Designer.ShowMethod(MethodName);
- Break;
- end;
- end;
- finally
- FreeMem(Props);
- end;
- end;
- procedure TTBItemEditForm.ListViewKeyDown(Sender: TObject; var Key: Word;
- Shift: TShiftState);
- begin
- case Key of
- VK_RETURN: begin
- Key := 0;
- ActivateInspector(#0);
- end;
- VK_INSERT: begin
- Key := 0;
- if ssCtrl in Shift then
- NewSubmenuButtonClick(Sender)
- else
- NewItemButtonClick(Sender);
- end;
- VK_DELETE: begin
- Key := 0;
- Delete;
- end;
- end;
- end;
- procedure TTBItemEditForm.TreeViewKeyDown(Sender: TObject; var Key: Word;
- Shift: TShiftState);
- begin
- case Key of
- VK_RETURN: begin
- Key := 0;
- ActivateInspector(#0);
- end;
- VK_DELETE: begin
- Key := 0;
- DeleteButtonClick(Sender);
- end;
- end;
- end;
- procedure TTBItemEditForm.TreeViewKeyPress(Sender: TObject; var Key: Char);
- begin
- if {MP} CharInSet(Key, [#33..#126]) then begin
- ActivateInspector(Key);
- Key := #0;
- end
- else if Key = #13 then
- Key := #0; { suppress beep }
- end;
- procedure TTBItemEditForm.ListViewKeyPress(Sender: TObject; var Key: Char);
- begin
- if Key = '-' then begin
- NewSepButtonClick(Sender);
- Key := #0;
- end
- else if {MP} CharInSet(Key, [#33..#126]) then begin
- ActivateInspector(Key);
- Key := #0;
- end;
- end;
- procedure TTBItemEditForm.ListViewDragOver(Sender, Source: TObject; X,
- Y: Integer; State: TDragState; var Accept: Boolean);
- { List item dragged over the list view }
- var
- Item: TListItem;
- begin
- Accept := False;
- if (Sender = ListView) and (Source = ListView) and (ListView.SelCount = 1) then begin
- Item := ListView.GetItemAt(X, Y);
- if Assigned(Item) and (Item <> ListView.Selected) then
- Accept := True;
- end;
- end;
- procedure TTBItemEditForm.ListViewDragDrop(Sender, Source: TObject; X,
- Y: Integer);
- { List item dropped onto another list item }
- var
- ListItem: TListItem;
- Item: TTBCustomItem;
- NewIndex: Integer;
- begin
- if (Sender = ListView) and (Source = ListView) and (ListView.SelCount = 1) then begin
- ListItem := ListView.GetItemAt(X, Y);
- if Assigned(ListItem) and (ListItem <> ListView.Selected) and Assigned(FSelParentItem) then begin
- NewIndex := FSelParentItem.IndexOf(ListItem.Data);
- if NewIndex <> -1 then begin
- ListView.Items.BeginUpdate;
- { For good performance and to prevent Object Inspector flicker, increment
- FSettingSel to prevent calls to SetSelParentItem while moving items }
- Inc(FSettingSel);
- try
- Item := ListView.Selected.Data;
- MoveItem(FSelParentItem.IndexOf(Item), NewIndex);
- finally
- Dec(FSettingSel);
- ListView.Items.EndUpdate;
- end;
- { After decrementing FSettingSel, now call SetSelParentItem, to update
- the toolbar buttons }
- SetSelParentItem(FSelParentItem);
- end;
- end;
- end;
- end;
- function TTBItemEditForm.TreeViewDragHandler(Sender, Source: TObject;
- X, Y: Integer; Drop: Boolean): Boolean;
- var
- Node: TTreeNode;
- ListItem: TListItem;
- Item, NewParentItem: TTBCustomItem;
- ItemList: TList;
- I: Integer;
- NeedRebuildTree: Boolean;
- begin
- Result := False;
- if (Sender = TreeView) and (Source = ListView) then begin
- Node := TreeView.GetNodeAt(X, Y);
- if Assigned(Node) and (Node <> TreeView.Selected) then begin
- NewParentItem := Node.Data;
- ItemList := TList.Create;
- try
- ListItem := nil;
- while True do begin
- ListItem := ListView.GetNextItem(ListItem, sdAll, [isSelected]);
- if ListItem = nil then
- Break;
- Item := ListItem.Data;
- if Assigned(Item) and (Item <> NewParentItem) and
- not Item.ContainsItem(NewParentItem) and
- not(Item is TTBControlItem) then begin
- Result := True;
- ItemList.Add(Item);
- end;
- end;
- if Drop then begin
- NeedRebuildTree := False;
- for I := 0 to ItemList.Count-1 do begin
- Item := ItemList[I];
- Item.Parent.Remove(Item);
- NewParentItem.Add(Item);
- Designer.Modified;
- if IsSubmenuItem(Item) then
- NeedRebuildTree := True;
- end;
- if NeedRebuildTree then
- RebuildTree;
- end;
- finally
- ItemList.Free;
- end;
- end;
- end;
- end;
- procedure TTBItemEditForm.TreeViewDragOver(Sender, Source: TObject; X,
- Y: Integer; State: TDragState; var Accept: Boolean);
- { List item dragged over the tree view }
- begin
- Accept := TreeViewDragHandler(Sender, Source, X, Y, False);
- end;
- procedure TTBItemEditForm.TreeViewDragDrop(Sender, Source: TObject; X,
- Y: Integer);
- { List item dropped onto the tree view }
- begin
- TreeViewDragHandler(Sender, Source, X, Y, True);
- end;
- procedure TTBItemEditForm.CreateNewItem(const AClass: TTBCustomItemClass);
- var
- NewIndex: Integer;
- NewItem: TTBCustomItem;
- ListItem: TListItem;
- begin
- if FSelParentItem = nil then Exit;
- NewIndex := -1;
- if (GetKeyState(VK_SHIFT) >= 0) and Assigned(ListView.Selected) then
- NewIndex := FSelParentItem.IndexOf(ListView.Selected.Data);
- if NewIndex = -1 then
- NewIndex := FSelParentItem.Count;
- NewItem := AClass.Create(FParentComponent.Owner{Designer.Form});
- try
- NewItem.Name := Designer.UniqueName(NewItem.ClassName);
- FSelParentItem.Insert(NewIndex, NewItem);
- except
- NewItem.Free;
- raise;
- end;
- Designer.Modified;
- ListView.Selected := nil;
- ListItem := ListView.FindData(0, NewItem, True, False);
- if Assigned(ListItem) then begin
- ListItem.Selected := True;
- ListItem.Focused := True;
- ListItem.MakeVisible(False);
- ListView.SetFocus;
- end;
- end;
- procedure TTBItemEditForm.NewSubmenuButtonClick(Sender: TObject);
- begin
- CreateNewItem(TTBSubmenuItem);
- end;
- procedure TTBItemEditForm.NewItemButtonClick(Sender: TObject);
- begin
- CreateNewItem(TTBItem);
- end;
- procedure TTBItemEditForm.NewSepButtonClick(Sender: TObject);
- begin
- CreateNewItem(TTBSeparatorItem);
- end;
- procedure TTBItemEditForm.MoreItemClick(Sender: TObject);
- begin
- CreateNewItem(TTBCustomItemClass((Sender as TTBItem).Tag));
- end;
- procedure TTBItemEditForm.CutButtonClick(Sender: TObject);
- begin
- Cut;
- end;
- procedure TTBItemEditForm.CopyButtonClick(Sender: TObject);
- begin
- Copy;
- end;
- procedure TTBItemEditForm.PasteButtonClick(Sender: TObject);
- begin
- Paste;
- end;
- procedure TTBItemEditForm.DeleteButtonClick(Sender: TObject);
- begin
- if ActiveControl = ListView then
- Delete
- else if (ActiveControl = TreeView) and (FSelParentItem <> FRootItem) then
- DeleteItem(FSelParentItem);
- end;
- procedure TTBItemEditForm.MoveUpButtonClick(Sender: TObject);
- var
- SelList: TList;
- I, J: Integer;
- Item: TTBCustomItem;
- ListItem: TListItem;
- begin
- if FSelParentItem = nil then Exit;
- SelList := TList.Create;
- try
- GetSelItemList(SelList);
- if SelList.Count = 0 then Exit;
- ListView.Items.BeginUpdate;
- FSelParentItem.ViewBeginUpdate;
- { For good performance and to prevent Object Inspector flicker, increment
- FSettingSel to prevent calls to SetSelParentItem while moving items }
- Inc(FSettingSel);
- try
- for I := 0 to SelList.Count-1 do begin
- Item := SelList[I];
- J := FSelParentItem.IndexOf(Item);
- if J <> -1 then
- MoveItem(J, J-1);
- end;
- ListItem := ListView.FindData(0, SelList[0], True, False);
- if Assigned(ListItem) then
- ListItem.MakeVisible(False);
- finally
- Dec(FSettingSel);
- FSelParentItem.ViewEndUpdate;
- ListView.Items.EndUpdate;
- end;
- { After decrementing FSettingSel, now call SetSelParentItem, to update
- the toolbar buttons }
- SetSelParentItem(FSelParentItem);
- finally
- SelList.Free;
- end;
- end;
- procedure TTBItemEditForm.MoveDownButtonClick(Sender: TObject);
- var
- SelList: TList;
- I, J: Integer;
- Item: TTBCustomItem;
- ListItem: TListItem;
- begin
- if FSelParentItem = nil then Exit;
- SelList := TList.Create;
- try
- GetSelItemList(SelList);
- if SelList.Count = 0 then Exit;
- ListView.Items.BeginUpdate;
- FSelParentItem.ViewBeginUpdate;
- { For good performance and to prevent Object Inspector flicker, increment
- FSettingSel to prevent calls to SetSelParentItem while moving items }
- Inc(FSettingSel);
- try
- for I := SelList.Count-1 downto 0 do begin
- Item := SelList[I];
- J := FSelParentItem.IndexOf(Item);
- if J <> -1 then
- MoveItem(J, J+1);
- end;
- ListItem := ListView.FindData(0, SelList[SelList.Count-1], True, False);
- if Assigned(ListItem) then
- ListItem.MakeVisible(False);
- finally
- Dec(FSettingSel);
- FSelParentItem.ViewEndUpdate;
- ListView.Items.EndUpdate;
- end;
- { After decrementing FSettingSel, now call SetSelParentItem, to update
- the toolbar buttons }
- SetSelParentItem(FSelParentItem);
- finally
- SelList.Free;
- end;
- end;
- procedure TTBItemEditForm.TConvertMenuClick(Sender: TObject);
- begin
- if FSelParentItem = nil then Exit;
- DoConvert(FSelParentItem, FParentComponent.Owner);
- end;
- { TTBItemsEditor }
- procedure TTBItemsEditor.Edit;
- var
- Intf: ITBItems;
- begin
- if Assigned(Component) and Component.GetInterface(ITBItems, Intf) then
- ShowEditForm(Component, Intf.GetItems, Designer);
- end;
- procedure TTBItemsEditor.ExecuteVerb(Index: Integer);
- begin
- case Index of
- 0: Edit;
- 1: ShowVersion;
- end;
- end;
- function TTBItemsEditor.GetVerbCount: Integer;
- begin
- Result := 2;
- end;
- function TTBItemsEditor.GetVerb(Index: Integer): String;
- begin
- case Index of
- 0: Result := 'Edit...';
- 1: Result := 'Version...';
- else
- Result := '';
- end;
- end;
- { TTBItemsPropertyEditor }
- procedure TTBItemsPropertyEditor.Edit;
- var
- Editor: IComponentEditor;
- begin
- if PropCount <> 1 then Exit;
- Editor := GetComponentEditor(GetComponent(0) as TComponent, Designer);
- Editor.Edit;
- end;
- function TTBItemsPropertyEditor.GetAttributes: TPropertyAttributes;
- begin
- Result := inherited GetAttributes + [paDialog, paReadOnly];
- end;
- function TTBItemsPropertyEditor.GetValue: String;
- begin
- Result := '(TB2000 Items)';
- end;
- procedure TBRegisterDsgnEditorHook(Hook: TTBDsgnEditorHook);
- var
- H: ^TTBDsgnEditorHook;
- begin
- New(H);
- H^ := Hook;
- EditFormHooks.Add(H);
- end;
- procedure TBUnregisterDsgnEditorHook(Hook: TTBDsgnEditorHook);
- var
- H: ^TTBDsgnEditorHook;
- I: Integer;
- begin
- for I := EditFormHooks.Count - 1 downto 0 do
- begin
- H := EditFormHooks[I];
- if (TMethod(H^).Code = TMethod(Hook).Code) and
- (TMethod(H^).Data = TMethod(Hook).Data) then
- begin
- Dispose(H);
- EditFormHooks.Delete(I);
- // Break;
- end;
- end;
- end;
- initialization
- ItemImageList := TImageList.Create(nil);
- ItemImageList.Handle := ImageList_LoadImage(HInstance, 'TB2_DSGNEDITORIMAGES',
- 16, 0, clFuchsia, IMAGE_BITMAP, 0);
- ItemClasses := TList.Create;
- EditFormHooks := TList.Create;
- AddModuleUnloadProc(UnregisterModuleItemClasses);
- finalization
- RemoveModuleUnloadProc(UnregisterModuleItemClasses);
- FreeItemClasses;
- FreeAndNil(ItemImageList);
- FreeAndNil(EditFormHooks);
- end.
|