lazarus/components/synedit/design/synpropertyeditobjectlist.pas
mattias 88ba0ca4c8 synedit: less notes
git-svn-id: trunk@48160 -
2015-03-07 10:11:02 +00:00

647 lines
19 KiB
ObjectPascal

{ PropertyEditor
Copyright (C) <year> <name of author> <contact>
This library is free software; you can redistribute it and/or modify it
under the terms of the GNU Library General Public License as published by
the Free Software Foundation; either version 2 of the License, or (at your
option) any later version.
This program is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License
for more details.
You should have received a copy of the GNU Library General Public License
along with this library; if not, write to the Free Software Foundation,
Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
}
unit SynPropertyEditObjectList;
{$mode objfpc}{$H+}
interface
uses
Classes, SysUtils, LCLProc,
SynEdit, SynGutterBase, SynEditMiscClasses, SynEditMouseCmds, SynEditKeyCmds,
SynDesignStringConstants,
PropEdits, PropEditUtils, Forms, StdCtrls, ComCtrls, Dialogs, ComponentEditors,
ObjInspStrConsts, Controls, IDEImagesIntf, typinfo, FormEditingIntf;
type
{ TSynEdOptionsPropertyEditor }
TSynEdOptionsPropertyEditor = class(TSetPropertyEditor)
public
procedure GetProperties(Proc: TGetPropEditProc); override;
end;
{ TSynPropertEditClassList }
TSynPropertyEditObjectList = class(TListPropertyEditor)
protected
function ReadElementCount: integer; override;
function ReadElement(Index: integer): TPersistent; override;
class function ClassList: TStringList; virtual; abstract;
public
function GetAttributes: TPropertyAttributes; override;
procedure Edit; override;
class function ShowClassListEditor(AClassList: TSynObjectList;
OwnerPersistent: TPersistent; const PropName: String): TCustomForm;
end;
{ TSynPropertyEditGutterPartList }
TSynPropertyEditGutterPartList = class(TSynPropertyEditObjectList)
protected
class function ClassList: TStringList; override;
end;
{ TSynObjectPartListPropertyEditorForm }
TSynObjectPartListPropertyEditorForm = class(TForm)
SynObjectPartsListBox: TListBox;
ToolBar1: TToolBar;
AddButton: TToolButton;
ClassComboBox: TComboBox;
DeleteButton: TToolButton;
ToolButton3: TToolButton;
MoveUpButton: TToolButton;
MoveDownButton: TToolButton;
procedure AddButtonClick(Sender: TObject);
procedure SynObjectPartsListBoxClick(Sender: TObject);
procedure DeleteButtonClick(Sender: TObject);
procedure FormCreate(Sender: TObject);
procedure FormDestroy(Sender: TObject);
procedure MoveDownButtonClick(Sender: TObject);
procedure MoveUpButtonClick(Sender: TObject);
private
FSynObjectPartList: TSynObjectList;
FOwnerPersistent: TPersistent;
FPropertyName: String;
FClassesList: TStringList;
protected
procedure UpdateCaption;
procedure UpdateButtons;
procedure ComponentRenamed(AComponent: TComponent);
procedure PersistentDeleting(APersistent: TPersistent);
procedure RefreshPropertyValues;
public
procedure FillSynObjectPartsListBox;
procedure SelectInObjectInspector(UnselectAll: Boolean);
procedure SetSynObjectPartList(NewSynObjectPartList: TSynObjectList;
NewClassesList: TStringList;
NewOwnerPersistent: TPersistent; const NewPropName: String);
procedure Modified;
public
property SynObjectPartList: TSynObjectList read FSynObjectPartList;
property OwnerPersistent: TPersistent read FOwnerPersistent;
property PropertyName: String read FPropertyName;
end;
{ TSynKeyCommandPropertyEditor }
TSynKeyCommandPropertyEditor = class(TIntegerPropertyEditor)
public
function GetAttributes: TPropertyAttributes; override;
function OrdValueToVisualValue(OrdValue: longint): string; override;
procedure GetValues(Proc: TGetStrProc); override;
procedure SetValue(const NewValue: ansistring); override;
end;
{ TSynMouseCommandPropertyEditor }
TSynMouseCommandPropertyEditor = class(TIntegerPropertyEditor)
public
function GetAttributes: TPropertyAttributes; override;
function OrdValueToVisualValue(OrdValue: longint): string; override;
procedure GetValues(Proc: TGetStrProc); override;
procedure SetValue(const NewValue: ansistring); override;
end;
{ TSynEditComponentEditor }
TSynEditComponentEditor = class(TDefaultComponentEditor)
public
function GetVerbCount: Integer; override;
function GetVerb(Index: Integer): string; override;
procedure ExecuteVerb(Index: Integer); override;
end;
procedure RegisterGutterPartClass(AClass: TSynGutterPartBaseClass; AName: String);
implementation
{$R *.lfm}
const
SynObjectPartListForm: TSynObjectPartListPropertyEditorForm = nil;
KnownSynGutterPartClasses: TStringList = nil;
procedure RegisterGutterPartClass(AClass: TSynGutterPartBaseClass; AName: String);
begin
if KnownSynGutterPartClasses = nil then
KnownSynGutterPartClasses := TStringList.Create;
KnownSynGutterPartClasses.AddObject(AName, TObject(Pointer(AClass)));
end;
{ TSynEditComponentEditor }
function TSynEditComponentEditor.GetVerbCount: Integer;
begin
Result := inherited GetVerbCount;
Result := Result + 1;
end;
function TSynEditComponentEditor.GetVerb(Index: Integer): string;
begin
case Index - (inherited GetVerbCount) of
0: Result := syndsResetMouseActions;
else
Result := inherited GetVerb(Index);
end;
end;
procedure TSynEditComponentEditor.ExecuteVerb(Index: Integer);
var
Hook: TPropertyEditorHook;
begin
case Index - (inherited GetVerbCount) of
0: begin
if (Component <> nil) and (Component is TCustomSynEdit) then
TCustomSynEdit(Component).ResetMouseActions;
Modified;
GetHook(Hook);
if Assigned(Hook) then Hook.Modified(Self);
end;
else
inherited ExecuteVerb(Index);
end;
end;
{ TSynEdOptionsPropertyEditor }
procedure TSynEdOptionsPropertyEditor.GetProperties(Proc: TGetPropEditProc);
var
I: Integer;
begin
with GetTypeData(GetTypeData(GetPropType)^.CompType)^ do
for I := MinValue to MaxValue do
if not(TSynEditorOption(I) in SYNEDIT_UNIMPLEMENTED_OPTIONS)
then
Proc(TSetElementPropertyEditor.Create(Self, I));
end;
{ TSynKeyCommandPropertyEditor }
function TSynKeyCommandPropertyEditor.GetAttributes: TPropertyAttributes;
begin
Result := [paMultiSelect, paValueList, paRevertable];
if GetDefaultOrdValue <> NoDefaultValue then
Result := Result + [paHasDefaultValue];
end;
function TSynKeyCommandPropertyEditor.OrdValueToVisualValue(OrdValue: longint): string;
begin
Result:='';
if not EditorCommandToIdent(OrdValue, Result) then
Result := inherited OrdValueToVisualValue(OrdValue);
end;
procedure TSynKeyCommandPropertyEditor.GetValues(Proc: TGetStrProc);
var
CValue: Integer;
begin
CValue:=0;
if not IdentToSynMouseCmd(GetVisualValue, CValue) then Proc(GetVisualValue);
GetEditorCommandValues(Proc);
end;
procedure TSynKeyCommandPropertyEditor.SetValue(const NewValue: ansistring);
var
CValue: Integer;
begin
CValue:=0;
if IdentToEditorCommand(NewValue, CValue) then SetOrdValue(CValue)
else inherited SetValue(NewValue);
end;
{ TSynMouseCommandPropertyEditor }
function TSynMouseCommandPropertyEditor.GetAttributes: TPropertyAttributes;
begin
Result := [paMultiSelect, paValueList, paRevertable];
if GetDefaultOrdValue <> NoDefaultValue then
Result := Result + [paHasDefaultValue];
end;
function TSynMouseCommandPropertyEditor.OrdValueToVisualValue(OrdValue: longint): string;
begin
Result:='';
if not SynMouseCmdToIdent(OrdValue, Result) then
Result := inherited OrdValueToVisualValue(OrdValue);
end;
procedure TSynMouseCommandPropertyEditor.GetValues(Proc: TGetStrProc);
var
CValue: Integer;
CName: String;
i: TSynEditorMouseCommand;
begin
CValue:=0;
CName:='';
if not IdentToSynMouseCmd(GetVisualValue, CValue) then Proc(GetVisualValue);
for i := 0 to emcMax do
if SynMouseCmdToIdent(i, CName) then Proc(CName);
end;
procedure TSynMouseCommandPropertyEditor.SetValue(const NewValue: ansistring);
var
CValue: Integer;
begin
CValue:=0;
if IdentToSynMouseCmd(NewValue, CValue) then SetOrdValue(CValue)
else inherited SetValue(NewValue);
end;
{ TSynObjectPartListPropertyEditorForm }
procedure TSynObjectPartListPropertyEditorForm.AddButtonClick(Sender: TObject);
var
i: Integer;
NewPart: TSynObjectListItem;
begin
if (SynObjectPartList = nil) or (FClassesList = nil) then Exit;
i := ClassComboBox.ItemIndex;
if (i < 0) or (i >= FClassesList.Count) then
exit;
NewPart := TSynObjectListItemClass(Pointer(FClassesList.Objects[i])).Create(SynObjectPartList);
NewPart.Name := FormEditingHook.CreateUniqueComponentName(NewPart.ClassName, SynObjectPartList);
FillSynObjectPartsListBox;
if SynObjectPartsListBox.Items.Count > 0 then
SynObjectPartsListBox.ItemIndex := SynObjectPartsListBox.Items.Count - 1;
SelectInObjectInspector(False);
UpdateButtons;
UpdateCaption;
Modified;
end;
procedure TSynObjectPartListPropertyEditorForm.SynObjectPartsListBoxClick(Sender: TObject);
begin
UpdateButtons;
UpdateCaption;
SelectInObjectInspector(False);
end;
procedure TSynObjectPartListPropertyEditorForm.DeleteButtonClick(Sender: TObject);
var
I : Integer;
NewItemIndex: Integer;
begin
if SynObjectPartList = nil then Exit;
I := SynObjectPartsListBox.ItemIndex;
if (I >= 0) and (I < SynObjectPartList.Count) then
begin
if MessageDlg(oisConfirmDelete,
Format(oisDeleteItem, [SynObjectPartList.BaseItems[I].DisplayName]),
mtConfirmation, [mbYes, mbNo], 0) = mrYes then
begin
// select other item, or unselect
NewItemIndex := I + 1;
while (NewItemIndex < SynObjectPartsListBox.Items.Count)
and (SynObjectPartsListBox.Selected[NewItemIndex]) do Inc(NewItemIndex);
if NewItemIndex = SynObjectPartsListBox.Items.Count then
begin
NewItemIndex := 0;
while (NewItemIndex < Pred(I))
and not (SynObjectPartsListBox.Selected[NewItemIndex]) do Inc(NewItemIndex);
if NewItemIndex = I then NewItemIndex := -1;
end;
SynObjectPartsListBox.ItemIndex := -1;
if NewItemIndex > I then Dec(NewItemIndex);
// unselect all items in OI
SelectInObjectInspector(True);
// now delete
SynObjectPartList.BaseItems[I].Free;
// update listbox after whatever happened
FillSynObjectPartsListBox;
// set NewItemIndex
if NewItemIndex < SynObjectPartsListBox.Items.Count then
begin
SynObjectPartsListBox.ItemIndex := NewItemIndex;
SelectInObjectInspector(False);
end;
Modified;
end;
end;
UpdateButtons;
UpdateCaption;
end;
procedure TSynObjectPartListPropertyEditorForm.FormCreate(Sender: TObject);
begin
ToolBar1.Images := IDEImages.Images_16;
AddButton.Caption := oiColEditAdd;
DeleteButton.Caption := oiColEditDelete;
MoveUpButton.Caption := oiColEditUp;
MoveDownButton.Caption := oiColEditDown;
AddButton.ImageIndex := IDEImages.LoadImage(16, 'laz_add');
DeleteButton.ImageIndex := IDEImages.LoadImage(16, 'laz_delete');
MoveUpButton.ImageIndex := IDEImages.LoadImage(16, 'arrow_up');
MoveDownButton.ImageIndex := IDEImages.LoadImage(16, 'arrow_down');
end;
procedure TSynObjectPartListPropertyEditorForm.FormDestroy(Sender: TObject);
begin
if GlobalDesignHook <> nil then
GlobalDesignHook.RemoveAllHandlersForObject(Self);
end;
procedure TSynObjectPartListPropertyEditorForm.MoveDownButtonClick(Sender: TObject);
var
I: Integer;
begin
if SynObjectPartList = nil then Exit;
I := SynObjectPartsListBox.ItemIndex;
if I >= SynObjectPartList.Count - 1 then Exit;
SynObjectPartList.BaseItems[I].Index := I + 1;
SynObjectPartsListBox.ItemIndex := I + 1;
FillSynObjectPartsListBox;
SelectInObjectInspector(False);
Modified;
end;
procedure TSynObjectPartListPropertyEditorForm.MoveUpButtonClick(Sender: TObject);
var
I: Integer;
begin
if SynObjectPartList = nil then Exit;
I := SynObjectPartsListBox.ItemIndex;
if I < 0 then Exit;
SynObjectPartList.BaseItems[I].Index := I - 1;
SynObjectPartsListBox.ItemIndex := I - 1;
FillSynObjectPartsListBox;
SelectInObjectInspector(False);
Modified;
end;
procedure TSynObjectPartListPropertyEditorForm.UpdateCaption;
var
NewCaption: String;
begin
//"Editing ComponentName.PropertyName[Index]"
if OwnerPersistent is TComponent then
NewCaption := TComponent(OwnerPersistent).Name
else
if OwnerPersistent <> nil then
NewCaption := OwnerPersistent.GetNamePath
else
NewCaption := '';
if NewCaption <> '' then NewCaption := NewCaption + '.';
NewCaption := oiColEditEditing + ' ' + NewCaption + PropertyName;
if SynObjectPartsListBox.ItemIndex > -1 then
NewCaption := NewCaption + '[' + IntToStr(SynObjectPartsListBox.ItemIndex) + ']';
Caption := NewCaption;
end;
procedure TSynObjectPartListPropertyEditorForm.UpdateButtons;
var
I: Integer;
begin
if SynObjectPartList = nil then begin
AddButton.Enabled := False;
DeleteButton.Enabled := False;
MoveUpButton.Enabled := False;
MoveDownButton.Enabled := False;
exit;
end;
I := SynObjectPartsListBox.ItemIndex;
AddButton.Enabled := True;
DeleteButton.Enabled := I > -1;
MoveUpButton.Enabled := I > 0;
MoveDownButton.Enabled := (I >= 0) and (I < SynObjectPartList.Count - 1);
end;
procedure TSynObjectPartListPropertyEditorForm.ComponentRenamed(AComponent: TComponent);
begin
if AComponent = OwnerPersistent then UpdateCaption;
end;
procedure TSynObjectPartListPropertyEditorForm.PersistentDeleting(APersistent: TPersistent);
var
OldSynObjectPartList: TSynObjectList;
I: Integer;
begin
debugln(['TSynObjectPartListPropertyEditorForm.PersistentDeleting ']);
if APersistent = OwnerPersistent then
begin
OldSynObjectPartList := SynObjectPartList;
SetSynObjectPartList(nil, nil, nil, '');
GlobalDesignHook.Unselect(OldSynObjectPartList);
for I := 0 to OldSynObjectPartList.Count - 1 do
GlobalDesignHook.Unselect(OldSynObjectPartList.BaseItems[I]);
if GlobalDesignHook.LookupRoot = OldSynObjectPartList then
GlobalDesignHook.LookupRoot := nil;
Hide;
end;
end;
procedure TSynObjectPartListPropertyEditorForm.RefreshPropertyValues;
begin
FillSynObjectPartsListBox;
Modified;
end;
procedure TSynObjectPartListPropertyEditorForm.FillSynObjectPartsListBox;
var
I: Integer;
CurItem: String;
Cnt: Integer;
begin
SynObjectPartsListBox.Items.BeginUpdate;
try
if SynObjectPartList <> nil then Cnt := SynObjectPartList.Count
else Cnt := 0;
// add or replace list items
for I := 0 to Cnt - 1 do
begin
CurItem := IntToStr(I) + ' - ' + SynObjectPartList.BaseItems[I].DisplayName;
if I >= SynObjectPartsListBox.Items.Count then
SynObjectPartsListBox.Items.Add(CurItem)
else
SynObjectPartsListBox.Items[I] := CurItem;
end;
// delete unneeded list items
if Cnt > 0 then
begin
while SynObjectPartsListBox.Items.Count > Cnt do
begin
SynObjectPartsListBox.Items.Delete(SynObjectPartsListBox.Items.Count - 1);
end;
end
else
begin
SynObjectPartsListBox.Items.Clear;
end;
finally
SynObjectPartsListBox.Items.EndUpdate;
UpdateButtons;
UpdateCaption;
end;
end;
procedure TSynObjectPartListPropertyEditorForm.SelectInObjectInspector(UnselectAll: Boolean);
var
I: Integer;
NewSelection: TPersistentSelectionList;
begin
if SynObjectPartList = nil then Exit;
// select in OI
NewSelection := TPersistentSelectionList.Create;
try
if not UnselectAll then
begin
for I := 0 to SynObjectPartsListBox.Items.Count - 1 do
if SynObjectPartsListBox.Selected[I] then
NewSelection.Add(SynObjectPartList.BaseItems[I]);
end;
GlobalDesignHook.SetSelection(NewSelection);
GlobalDesignHook.LookupRoot := GetLookupRootForComponent(OwnerPersistent);
finally
NewSelection.Free;
end;
end;
procedure TSynObjectPartListPropertyEditorForm.SetSynObjectPartList
(NewSynObjectPartList: TSynObjectList; NewClassesList: TStringList;
NewOwnerPersistent: TPersistent; const NewPropName: String);
begin
if (FSynObjectPartList = NewSynObjectPartList)
and (FClassesList = NewClassesList)
and (FOwnerPersistent = NewOwnerPersistent)
and (FPropertyName = NewPropName) then Exit;
FSynObjectPartList := NewSynObjectPartList;
FClassesList := NewClassesList;
if assigned(FClassesList) then
ClassComboBox.Items.Assign(FClassesList)
else
ClassComboBox.Clear;
if ClassComboBox.Items.Count >0 then
ClassComboBox.ItemIndex := 0;
// Can not use NewOwnerPersistent since it points to the SynGutter
if NewSynObjectPartList <> nil then
FOwnerPersistent := NewSynObjectPartList.Owner // The SynEdit
else
FOwnerPersistent := nil;
FPropertyName := NewPropName;
//debugln('TSynObjectPartListPropertyEditorForm.SetSynObjectPartList A SynObjectPartList=',dbgsName(FSynObjectPartList),' OwnerPersistent=',dbgsName(OwnerPersistent),' PropName=',PropertyName);
if GlobalDesignHook <> nil then
begin
if FOwnerPersistent <> nil then
begin
GlobalDesignHook.AddHandlerComponentRenamed(@ComponentRenamed);
GlobalDesignHook.AddHandlerPersistentDeleting(@PersistentDeleting);
GlobalDesignHook.AddHandlerRefreshPropertyValues(@RefreshPropertyValues);
end
else
begin
GlobalDesignHook.RemoveAllHandlersForObject(Self);
end;
end;
FillSynObjectPartsListBox;
UpdateCaption;
end;
procedure TSynObjectPartListPropertyEditorForm.Modified;
begin
GlobalDesignHook.Modified(Self);
//SelectInObjectInspector(False);
end;
{ TSynPropertyEditObjectList }
function TSynPropertyEditObjectList.ReadElementCount: integer;
var
SynObjectList: TObject;
begin
SynObjectList := GetObjectValue;
if (SynObjectList <> nil) and (SynObjectList is TSynObjectList) then
Result := TSynObjectList(SynObjectList).Count
else
Result:=0;
end;
function TSynPropertyEditObjectList.ReadElement(Index: integer): TPersistent;
var
SynObjectList: TSynObjectList;
begin
SynObjectList := TSynObjectList(GetObjectValue);
Result := SynObjectList.BaseItems[Index];
end;
function TSynPropertyEditObjectList.GetAttributes: TPropertyAttributes;
begin
Result := [paDialog, paReadOnly];
end;
procedure TSynPropertyEditObjectList.Edit;
var
TheSynObjectList: TSynObjectList;
begin
TheSynObjectList := TSynObjectList(GetObjectValue);
if TheSynObjectList = nil then
raise Exception.Create('ObjectPartList=nil');
ShowClassListEditor(TheSynObjectList, GetComponent(0), GetName);
end;
class function TSynPropertyEditObjectList.ShowClassListEditor(AClassList: TSynObjectList;
OwnerPersistent: TPersistent; const PropName: String): TCustomForm;
begin
if SynObjectPartListForm = nil then
SynObjectPartListForm := TSynObjectPartListPropertyEditorForm.Create(Application);
SynObjectPartListForm.SetSynObjectPartList(AClassList, ClassList, OwnerPersistent, PropName);
SynObjectPartListForm.EnsureVisible;
Result := SynObjectPartListForm;
end;
{ TSynPropertyEditGutterPartList }
class function TSynPropertyEditGutterPartList.ClassList: TStringList;
begin
Result := KnownSynGutterPartClasses;
end;
initialization
if KnownSynGutterPartClasses = nil then
KnownSynGutterPartClasses := TStringList.Create;
finalization
FreeAndNil(KnownSynGutterPartClasses);
end.