1440 lines
41 KiB
ObjectPascal
1440 lines
41 KiB
ObjectPascal
unit TB2DsgnItemEditor;
|
|
|
|
{
|
|
Toolbar2000
|
|
Copyright (C) 1998-2008 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:
|
|
http://www.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:
|
|
http://www.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.63 2008/09/25 18:49:31 jr Exp $
|
|
}
|
|
|
|
interface
|
|
|
|
{$I TB2Ver.inc}
|
|
|
|
uses
|
|
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
|
|
{$IFDEF CLR} System.ComponentModel, {$ENDIF}
|
|
StdCtrls, ExtCtrls, Buttons, ComCtrls, ImgList, Menus,
|
|
TB2Item, TB2Toolbar, TB2Dock,
|
|
{$IFDEF JR_D6}
|
|
DesignIntf, DesignWindows, DesignEditors;
|
|
{$ELSE}
|
|
DsgnIntf, DsgnWnds, LibIntf;
|
|
{$ENDIF}
|
|
|
|
const
|
|
CM_DEFERUPDATE = WM_USER + 100;
|
|
|
|
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 CMDeferUpdate(var Message: TMessage); message CM_DEFERUPDATE;
|
|
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;
|
|
{$IFDEF JR_D6}
|
|
function EditAction(Action: TEditAction): Boolean; override;
|
|
{$ELSE}
|
|
procedure EditAction(Action: TEditAction); override;
|
|
{$ENDIF}
|
|
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);
|
|
|
|
implementation
|
|
|
|
{$R *.DFM}
|
|
|
|
uses
|
|
{$IFDEF CLR} System.Drawing, System.IO, System.Reflection, {$ENDIF}
|
|
TypInfo, CommCtrl, TB2Version, TB2Common, TB2DsgnConverter;
|
|
|
|
type
|
|
{$IFNDEF JR_D5}
|
|
TDesignerSelectionList = TComponentList;
|
|
{$ENDIF}
|
|
{$IFDEF JR_D6}
|
|
TDesignerSelectionList = IDesignerSelections;
|
|
{$ENDIF}
|
|
|
|
TItemClassInfo = class
|
|
ItemClass: TTBCustomItemClass;
|
|
Caption: String;
|
|
ImageIndex: Integer;
|
|
end;
|
|
|
|
var
|
|
ItemClasses: TList;
|
|
ItemImageList: TImageList;
|
|
|
|
{$IFNDEF JR_D6}
|
|
function CreateSelectionList: TDesignerSelectionList;
|
|
begin
|
|
Result := TDesignerSelectionList.Create;
|
|
end;
|
|
{$ENDIF}
|
|
|
|
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
|
|
TItemClassInfo(IC[I]).Free;
|
|
IC.Free;
|
|
end;
|
|
|
|
{ Note: AFAIK, there is no need for a similar function on .NET since assemblies
|
|
can't be unloaded. When a design-time package is uninstalled, it remains
|
|
loaded until the IDE is restarted. }
|
|
{$IFNDEF CLR}
|
|
procedure UnregisterModuleItemClasses(AModule: {$IFDEF JR_D5} LongWord {$ELSE} Integer {$ENDIF});
|
|
var
|
|
I: Integer;
|
|
Info: TItemClassInfo;
|
|
begin
|
|
I := 0;
|
|
while I < ItemClasses.Count do begin
|
|
Info := TItemClassInfo(ItemClasses[I]);
|
|
if FindClassHInstance(Info.ItemClass) = AModule then begin
|
|
ItemClasses.Delete(I);
|
|
Info.Free;
|
|
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;
|
|
{$ENDIF}
|
|
|
|
{$IFNDEF CLR}
|
|
function LoadItemImage(Instance: HINST; const ResName: String): Integer;
|
|
var
|
|
Bmp: TBitmap;
|
|
begin
|
|
Bmp := TBitmap.Create;
|
|
try
|
|
Bmp.Handle := LoadBitmap(Instance, {$IFNDEF CLR}PChar{$ENDIF}(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;
|
|
{$ELSE}
|
|
function LoadItemImage(const AAssembly: System.Reflection.Assembly;
|
|
const ResName: String): Integer;
|
|
var
|
|
Bmp: TBitmap;
|
|
ResStream: System.IO.Stream;
|
|
ResBmp: System.Drawing.Bitmap;
|
|
begin
|
|
Bmp := TBitmap.Create;
|
|
try
|
|
ResStream := AAssembly.GetManifestResourceStream(ResName);
|
|
if ResStream = nil then begin
|
|
Result := -1;
|
|
Exit;
|
|
end;
|
|
try
|
|
ResBmp := System.Drawing.Bitmap.Create(ResStream);
|
|
try
|
|
Bmp.LoadFromBitmap(ResBmp);
|
|
finally
|
|
ResBmp.Dispose;
|
|
end;
|
|
finally
|
|
ResStream.Close;
|
|
end;
|
|
Result := ItemImageList.AddMasked(Bmp, Bmp.Canvas.Pixels[0, Bmp.Height-1]);
|
|
finally
|
|
Bmp.Free;
|
|
end;
|
|
end;
|
|
{$ENDIF}
|
|
|
|
procedure TBRegisterItemClass(AClass: TTBCustomItemClass;
|
|
const ACaption: String; ResInstance: HINST);
|
|
var
|
|
I: Integer;
|
|
Info: TItemClassInfo;
|
|
begin
|
|
{ Hack for Delphi.NET 2006 bug:
|
|
If you start Delphi, open & rebuild the tb2k_dn10 package only, then open
|
|
the Demo project, the IDE calls the Register procedure on tb2kdsgn_d10 a
|
|
second time, without reloading either of the two packages. As a result,
|
|
the TBRegisterItemClass calls are repeated. To avoid doubled items on the
|
|
editor form's More menu, check if the class was already registered. }
|
|
for I := 0 to ItemClasses.Count-1 do
|
|
if TItemClassInfo(ItemClasses[I]).ItemClass = AClass then
|
|
Exit;
|
|
Info := TItemClassInfo.Create;
|
|
Info.ItemClass := AClass;
|
|
Info.Caption := ACaption;
|
|
{$IFNDEF CLR}
|
|
Info.ImageIndex := LoadItemImage(ResInstance,
|
|
Uppercase(AClass.ClassName {$IFDEF JR_D9} , loInvariantLocale {$ENDIF}));
|
|
{$ELSE}
|
|
Info.ImageIndex := LoadItemImage(Assembly.GetCallingAssembly,
|
|
AClass.ClassName + '.bmp');
|
|
{$ENDIF}
|
|
ItemClasses.Add(Info);
|
|
end;
|
|
|
|
function GetItemClassImage(AClass: TTBCustomItemClass): Integer;
|
|
var
|
|
I: Integer;
|
|
Info: TItemClassInfo;
|
|
begin
|
|
for I := ItemClasses.Count-1 downto 0 do begin
|
|
Info := TItemClassInfo(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: {$IFDEF JR_D6} IDesigner {$ELSE} IFormDesigner {$ENDIF});
|
|
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;
|
|
{$IFDEF JR_D9}
|
|
EditForm.PopupMode := pmExplicit;
|
|
{$ENDIF}
|
|
EditForm.Show;
|
|
except
|
|
EditForm.Free;
|
|
raise;
|
|
end;
|
|
end;
|
|
|
|
function IsSubmenuItem(Item: TTBCustomItem): Boolean;
|
|
begin
|
|
Result := tbisSubitemsEditable in Item.GetItemStyle;
|
|
end;
|
|
|
|
procedure ShowVersion;
|
|
const
|
|
AboutText =
|
|
'%s'#13#10 +
|
|
'Copyright (C) 1998-2008 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 +
|
|
'http://www.jrsoftware.org/';
|
|
begin
|
|
MessageDlg(Format(AboutText, [Toolbar2000VersionPropText]), mtInformation,
|
|
[mbOK], 0);
|
|
end;
|
|
|
|
|
|
{ TTBItemEditForm }
|
|
|
|
constructor TTBItemEditForm.Create(AOwner: TComponent);
|
|
var
|
|
I: Integer;
|
|
Info: TItemClassInfo;
|
|
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 := TItemClassInfo(ItemClasses[I]);
|
|
Item := TTBItem.Create(Self);
|
|
Item.Caption := Info.Caption;
|
|
Item.ImageIndex := GetItemClassImage(Info.ItemClass);
|
|
Item.Tag := {$IFNDEF CLR}Integer{$ELSE}TTag{$ENDIF}(Info.ItemClass);
|
|
Item.OnClick := MoreItemClick;
|
|
MoreMenu.Add(Item);
|
|
end;
|
|
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;
|
|
|
|
{$IFDEF JR_D6}
|
|
function TTBItemEditForm.EditAction(Action: TEditAction): Boolean;
|
|
{$ELSE}
|
|
procedure TTBItemEditForm.EditAction(Action: TEditAction);
|
|
{$ENDIF}
|
|
begin
|
|
{$IFDEF JR_D6}
|
|
Result := True;
|
|
{$ENDIF}
|
|
case Action of
|
|
eaCut: Cut;
|
|
eaCopy: Copy;
|
|
eaPaste: Paste;
|
|
eaDelete: Delete;
|
|
{$IFDEF JR_D6}
|
|
else
|
|
Result := False;
|
|
{$ENDIF}
|
|
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 := TComponent(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
|
|
{$IFNDEF JR_D6}
|
|
CompList1.Free;
|
|
CompList2.Free;
|
|
{$ENDIF}
|
|
end
|
|
else begin
|
|
Designer.SetSelections(CompList1);
|
|
{ Note: Never pass an empty list to SetSelection or Delphi will crash }
|
|
{ History here:
|
|
- 1.34: SetSelection call remarked out because it fixed Delphi 6 issue
|
|
with random AV's after the editor was closed.
|
|
- 1.38: SetSelection call restored because without it, Ctrl+X/C/V didn't
|
|
work.
|
|
- 1.40: SetSelection call disabled on Delphi 6 only because AV problem
|
|
still seems to exist despite another change which I thought fixed it.
|
|
On D6 it isn't necessary to call SetSelection for Ctrl+X/C/V to work.
|
|
Note: Using "ComponentDesigner.SetSelection(Designer, nil, CompList2);"
|
|
instead seems to fix the AV problem, but for consistency with Delphi's
|
|
TMainMenu editor (which only selects items when its parent form is
|
|
focused), I decided not to call SetSelection at all on D6.
|
|
}
|
|
{$IFNDEF JR_D6}
|
|
SetSelection(CompList2);
|
|
{$ENDIF}
|
|
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(TTBCustomItem(List.First)) > 0);
|
|
MoveDownButton.Enabled := ItemIsSelected and
|
|
(FSelParentItem.IndexOf(TTBCustomItem(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 := TTBCustomItem(SelList[I]);
|
|
if Item is TTBControlItem then
|
|
raise EInvalidOperation.Create('Cannot cut or copy TTBControlItems');
|
|
CompList.Add(Item);
|
|
end;
|
|
CopyComponents(FParentComponent.Owner, CompList);
|
|
finally
|
|
{$IFNDEF JR_D6}
|
|
CompList.Free;
|
|
{$ENDIF}
|
|
SelList.Free;
|
|
end;
|
|
end;
|
|
|
|
procedure TTBItemEditForm.Paste;
|
|
var
|
|
CompList: TDesignerSelectionList;
|
|
begin
|
|
if FSelParentItem = nil then Exit;
|
|
CompList := CreateSelectionList;
|
|
try
|
|
PasteComponents(FParentComponent.Owner, FSelParentItem, CompList);
|
|
if CompList.Count <> 0 then
|
|
Designer.Modified;
|
|
finally
|
|
{$IFNDEF JR_D6}
|
|
CompList.Free;
|
|
{$ENDIF}
|
|
end;
|
|
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');
|
|
//Designer.ValidateRename(Item, Item.Name, '');
|
|
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 := TTBCustomItem(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 := TTBCustomItem(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.CMDeferUpdate(var Message: TMessage);
|
|
begin
|
|
SetSelParentItem(FSelParentItem);
|
|
end;
|
|
|
|
procedure TTBItemEditForm.ListViewChange(Sender: TObject; Item: TListItem;
|
|
Change: TItemChange);
|
|
var
|
|
Msg: TMsg;
|
|
begin
|
|
if (FRebuildingList > 0) or (FSettingSel > 0) or (Change <> ctState) or
|
|
(csDestroying in ListView.ComponentState) then
|
|
Exit;
|
|
if not PeekMessage(Msg, Handle, CM_DEFERUPDATE, CM_DEFERUPDATE,
|
|
PM_NOREMOVE or PM_NOYIELD) then
|
|
PostMessage(Handle, CM_DEFERUPDATE, 0, 0);
|
|
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: {$IFNDEF CLR} PPropList {$ELSE} TPropList {$ENDIF};
|
|
PropInfo: {$IFNDEF CLR} PPropInfo {$ELSE} TPropInfo {$ENDIF};
|
|
MethodName: String;
|
|
Method: TMethod;
|
|
begin
|
|
SelItem := nil;
|
|
if Assigned(ListView.Selected) then
|
|
SelItem := TTBCustomItem(ListView.Selected.Data);
|
|
if SelItem = nil then Exit;
|
|
if IsSubmenuItem(SelItem) then begin
|
|
SetSelParentItem(SelItem);
|
|
Exit;
|
|
end;
|
|
{$IFNDEF CLR}
|
|
PropCount := GetPropList(SelItem.ClassInfo, [tkMethod], nil);
|
|
GetMem(Props, PropCount * SizeOf(PPropInfo));
|
|
try
|
|
GetPropList(SelItem.ClassInfo, [tkMethod], Props);
|
|
{$ELSE}
|
|
Props := GetPropList(SelItem.ClassInfo, [tkMethod]);
|
|
PropCount := Length(Props);
|
|
{$ENDIF}
|
|
for I := PropCount-1 downto 0 do begin
|
|
PropInfo := Props[I];
|
|
{$IFNDEF CLR}
|
|
if CompareText(String(PropInfo.Name), 'OnClick') = 0 then begin
|
|
{$ELSE}
|
|
if SameText(PropInfo.Name, 'OnClick', loInvariantLocale) then begin
|
|
{$ENDIF}
|
|
Method := GetMethodProp(SelItem, PropInfo);
|
|
MethodName := Designer.GetMethodName(Method);
|
|
if MethodName = '' then begin
|
|
MethodName := SelItem.Name + 'Click';
|
|
Method := Designer.CreateMethod(MethodName, GetTypeData(
|
|
{$IFNDEF CLR} PropInfo.PropType^ {$ELSE} PropInfo.TypeInfo {$ENDIF}));
|
|
SetMethodProp(SelItem, PropInfo, Method);
|
|
Designer.Modified;
|
|
end;
|
|
if Designer.MethodExists(MethodName) then
|
|
Designer.ShowMethod(MethodName);
|
|
Break;
|
|
end;
|
|
end;
|
|
{$IFNDEF CLR}
|
|
finally
|
|
FreeMem(Props);
|
|
end;
|
|
{$ENDIF}
|
|
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 (Key >= #33) and (Key <= #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 (Key >= #33) and (Key <= #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(TTBCustomItem(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 := TTBCustomItem(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 := TTBCustomItem(Node.Data);
|
|
ItemList := TList.Create;
|
|
try
|
|
ListItem := nil;
|
|
while True do begin
|
|
ListItem := ListView.GetNextItem(ListItem, sdAll, [isSelected]);
|
|
if ListItem = nil then
|
|
Break;
|
|
Item := TTBCustomItem(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 := TTBCustomItem(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(TTBCustomItem(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 := TTBCustomItem(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 := TTBCustomItem(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
|
|
Item: TTBCustomItem;
|
|
begin
|
|
if Assigned(Component) then begin
|
|
Item := TBGetItems(Component);
|
|
if Assigned(Item) then
|
|
ShowEditForm(Component, Item, Designer);
|
|
end;
|
|
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: {$IFDEF JR_D6} IComponentEditor {$ELSE} TComponentEditor {$ENDIF};
|
|
begin
|
|
if PropCount <> 1 then Exit;
|
|
Editor := GetComponentEditor(GetComponent(0) as TComponent, Designer);
|
|
try
|
|
Editor.Edit;
|
|
finally
|
|
{$IFNDEF JR_D6}
|
|
Editor.Free;
|
|
{$ENDIF}
|
|
end;
|
|
end;
|
|
|
|
function TTBItemsPropertyEditor.GetAttributes: TPropertyAttributes;
|
|
begin
|
|
Result := inherited GetAttributes + [paDialog, paReadOnly];
|
|
end;
|
|
|
|
function TTBItemsPropertyEditor.GetValue: String;
|
|
begin
|
|
Result := '(TB2000 Items)';
|
|
end;
|
|
|
|
initialization
|
|
ItemImageList := TImageList.Create(nil);
|
|
{$IFNDEF CLR}
|
|
ItemImageList.Handle := ImageList_LoadImage(HInstance, 'TB2_DSGNEDITORIMAGES',
|
|
16, 0, clFuchsia, IMAGE_BITMAP, 0);
|
|
{$ELSE}
|
|
{ Initialize the image list as plain ILC_COLOR (4-bit), because on Windows
|
|
2000, at color depths > 16 (what TImageList's ILC_COLORDDB would give us
|
|
when running on a true-color display), selected images are drawn with an
|
|
ugly dithering effect }
|
|
ItemImageList.Handle := ImageList_Create(16, 16, ILC_COLOR or ILC_MASK, 4, 4);
|
|
LoadItemImage(Assembly.GetExecutingAssembly, 'TB2DsgnEditorImages.bmp');
|
|
{$ENDIF}
|
|
ItemClasses := TList.Create;
|
|
{$IFNDEF CLR}
|
|
AddModuleUnloadProc(UnregisterModuleItemClasses);
|
|
{$ENDIF}
|
|
finalization
|
|
{$IFNDEF CLR}
|
|
RemoveModuleUnloadProc(UnregisterModuleItemClasses);
|
|
{$ENDIF}
|
|
FreeItemClasses;
|
|
FreeAndNil(ItemImageList);
|
|
end.
|