BorlandTalk.com Forum Index BorlandTalk.com
Borland discussion newsgroups
 
Archives   FAQFAQ   SearchSearch   MemberlistMemberlist   UsergroupsUsergroups   RegisterRegister 
 ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

How to mix components context menu

 
Post new topic   Reply to topic    BorlandTalk.com Forum Index -> Delphi VCL Components Writing
View previous topic :: View next topic  
Author Message
Dietmar Brueckmann
Guest





PostPosted: Tue Nov 18, 2003 8:07 am    Post subject: How to mix components context menu Reply with quote



Hi,

I've written a descendent from TClientdataset.
Now I want to add one new Item to the context menu.
I've read in TFM how to make my own context Items:
____________________________________________
function TdbCDS_Editor.GetVerbCount: Integer;
begin
Result := 1;
end;
function TdbCDS_Editor.GetVerb(Index: Integer): string;
begin
case Index of
0 : Result := 'Do This';
else Result := IntToStr(Index)+'?';
end;
end;
procedure TdbCDS_Editor.ExecuteVerb(Index: Integer);
begin
inherited;
case Index of
0 : DoThis;
else assert(false,'Tdb_dbCDS_Editor.ExecuteVerb:');
end;
end;
____________________________________________
But in this way the existing 5 entries (especially the fields-editor from
TDataset) of TClientdataset disappear.
I've looked at CDSEdit but I didn't found the point where EditClientDataSet
is called.
And where it is mixed into the TDataset-menu.
I've looked at DBReg, it is instructive but I didn't see an entrypoint to do
what I want.

Possibly someone could show me a way to do it

Best regards
Dietmar


Back to top
Constantine Yannakopoulos
Guest





PostPosted: Tue Nov 18, 2003 8:41 am    Post subject: Re: How to mix components context menu Reply with quote



Author := "Dietmar Brueckmann";

Quote:
Possibly someone could show me a way to do it

Unfortunately the component editor for TClientDataset is not available,
but you can get an instance of it before you register your component
editor by creating a TClientDataset on the fly and calling
DesignEditors.GetComponentEditor(). Then save its class in a global
variable and in your component editor create an instance of Borland's
component editor and use its methods to put the standard menuitems in
the popup-menu.

--
Constantine

Back to top
Maris Janis Vasilevskis
Guest





PostPosted: Tue Nov 18, 2003 10:11 am    Post subject: Re: How to mix components context menu Reply with quote



To keep all previous items and have the new item on top, do the following:

function TdbCDS_Editor.GetVerbCount: Integer;
begin
Result := inherited GetVerbCount + 1;
end;
function TdbCDS_Editor.GetVerb(Index: Integer): string;
begin
case Index of
0 : Result := 'Do This';
else Result := inherited GetVerb(Index-1);
end;
end;
procedure TdbCDS_Editor.ExecuteVerb(Index: Integer);
begin
case Index of
0 : DoThis;
else inherited ExecuteVerb(Index-1);
end;
end;


If not on top, use GetVerbCount in GetVerb and ExecuteVerb
(or direct number)

Mahris

Dietmar Brueckmann wrote:

Quote:
Hi,

I've written a descendent from TClientdataset.
Now I want to add one new Item to the context menu.
I've read in TFM how to make my own context Items:
____________________________________________
function TdbCDS_Editor.GetVerbCount: Integer;
begin
Result := 1;
end;
function TdbCDS_Editor.GetVerb(Index: Integer): string;
begin
case Index of
0 : Result := 'Do This';
else Result := IntToStr(Index)+'?';
end;
end;
procedure TdbCDS_Editor.ExecuteVerb(Index: Integer);
begin
inherited;
case Index of
0 : DoThis;
else assert(false,'Tdb_dbCDS_Editor.ExecuteVerb:');
end;
end;
____________________________________________
But in this way the existing 5 entries (especially the fields-editor from
TDataset) of TClientdataset disappear.
I've looked at CDSEdit but I didn't found the point where EditClientDataSet
is called.
And where it is mixed into the TDataset-menu.
I've looked at DBReg, it is instructive but I didn't see an entrypoint to do
what I want.

Possibly someone could show me a way to do it

Best regards
Dietmar




Back to top
Dietmar Brueckmann
Guest





PostPosted: Tue Nov 18, 2003 11:11 am    Post subject: Re: How to mix components context menu Reply with quote

"Constantine Yannakopoulos" <kyan (AT) deltasingular (DOT) remove.this.gr> schrieb im
Newsbeitrag news:3fb9e953 (AT) newsgroups (DOT) borland.com...
Quote:
Author := "Dietmar Brueckmann";

| Possibly someone could show me a way to do it

Unfortunately the component editor for TClientDataset is not available,
but you can get an instance of it before you register your component
editor by creating a TClientDataset on the fly and calling
DesignEditors.GetComponentEditor(). Then save its class in a global
variable and in your component editor create an instance of Borland's
component editor and use its methods to put the standard menuitems in
the popup-menu.

Thanks for that.


But sorry I've to bother you with some questions

1. GetComponentEditor gives me a created Editor - can I use it?
2. If not how to get the Class from it
the Create I could do with
Result := EditorClass.Create(Component, Designer) as IComponentEditor;
3. I've never before worked with Interfaces.
Have I to free the aIComponentEditor in finally/destroy

The following example is using the Result of GetComponentEditor as the
editor.
Is this the way?

Best regards
Dietmar
________________________________________________________________
{ TdbCDS_Editor }
(*
TdbCDS_Editor = class(TComponentEditor)
protected
aIComponentEditor: IComponentEditor;
...
end;
*)
constructor TdbCDS_Editor.Create(AComponent: TComponent;
ADesigner: IDesigner);
var
cds : TClientDataSet;
begin
inherited;
cds := TClientDataSet.Create(nil);
try
aIComponentEditor := DesignEditors.GetComponentEditor(cds,ADesigner);
finally
FreeAndNil(cds);
end;
end;
function TdbCDS_Editor.GetVerbCount: Integer;
begin
Result := aIComponentEditor.GetVerbCount+1;
end;
function TdbCDS_Editor.GetVerb(Index: Integer): string;
begin
if Index=0 then Result := 'DoSomething'
else aIComponentEditor.GetVerb(Index-1);
end;
procedure TdbCDS_Editor.ExecuteVerb(Index: Integer);
begin
if Index=0 then DoSomething
else aIComponentEditor.ExecuteVerb(Index-1);
end;
___________________________________________________



Back to top
Constantine Yannakopoulos
Guest





PostPosted: Tue Nov 18, 2003 11:35 am    Post subject: Re: How to mix components context menu Reply with quote

Author := "Dietmar Brueckmann";

Quote:
2. If not how to get the Class from it

Oops! You are right, i'm afraid you can't, at least not without some
ugly hack.

So my suggestion cannot work. I am sorry for misleading you but this
technique used to work in D5 (when GetComponentEditor returned an
object and not an interface pointer) but apparently it does not work
anymore.

--
Constantine

Back to top
Maris Janis Vasilevskis
Guest





PostPosted: Tue Nov 18, 2003 4:24 pm    Post subject: Re: How to mix components context menu Reply with quote

Constantine Yannakopoulos wrote:
Quote:
So my suggestion cannot work. I am sorry for misleading you but this
technique used to work in D5 (when GetComponentEditor returned an
object and not an interface pointer) but apparently it does not work
anymore.

Hi Constantine,

The Dietmar question really contained two parts, from what to inherit,
and how to inherit. I answered the easiest, second part.

Your exciting idea of the first part answer was really new for me.
I regret that starting from D6 it cannot be implemented in the
original form.

So, I added Hallvard Vassbotn function from
http://groups.google.com/groups?hl=en&lr=&ie=UTF-8&oe=UTF-8&selm=3c887a0d_1%40dnews

It gives a solution for D6 and D7.

Mahris



implementation

uses SysUtils,DesignIntf,DesignEditors,DSDesign,DBReg,DesignMenus,Dialogs;

type

// Class author - Constantine Yannakopoulos
TExClientDataSetEditor = class(TDataSetEditor)
private
FOldEditor: TDataSetEditor;
protected
function GetDSDesignerClass: TDSDesignerClass; override;
public
constructor Create(AComponent: TComponent; ADesigner: IDesigner); override;
destructor Destroy; override;
procedure ExecuteVerb(Index: Integer); override;
function GetVerb(Index: Integer): string; override;
function GetVerbCount: Integer; override;

procedure Edit; override;
procedure Copy; override;
procedure PrepareItem(Index: Integer; const AItem: IMenuItem); override;
end;

var
PrevEditorClass: TClass;

// Function author - Hallvard Vassbotn
function GetImplementingObject(const I: IInterface): TObject;
const
AddByte = $04244483; // opcode for ADD DWORD PTR [ESP+4], Shortint
AddLong = $04244481; // opcode for ADD DWORD PTR [ESP+4], Longint
type
PAdjustSelfThunk = ^TAdjustSelfThunk;
TAdjustSelfThunk = packed record
case AddInstruction: longint of
AddByte : (AdjustmentByte: shortint);
AddLong : (AdjustmentLong: longint);
end;
PInterfaceMT = ^TInterfaceMT;
TInterfaceMT = packed record
QueryInterfaceThunk: PAdjustSelfThunk;
end;
TInterfaceRef = ^PInterfaceMT;
var
QueryInterfaceThunk: PAdjustSelfThunk;
begin
Result := Pointer(I);
if Assigned(Result) then
try
QueryInterfaceThunk := TInterfaceRef(I)^.QueryInterfaceThunk;
case QueryInterfaceThunk.AddInstruction of
AddByte: Inc(PChar(Result), QueryInterfaceThunk.AdjustmentByte);
AddLong: Inc(PChar(Result), QueryInterfaceThunk.AdjustmentLong);
else Result := nil;
end;
except
Result := nil;
end;
end;

procedure Register;
var
CDS: TClientDataset;
PrevEditor: TComponentEditor;
ComponentEditor:IComponentEditor;
begin
// First get the class pointer of the previously registered
// component editor for TClientDataset (TClientDatasetEditor).
CDS := TClientDataset.Create(nil);
try
ComponentEditor:=GetComponentEditor(CDS, nil);
PrevEditor := TComponentEditor(
GetImplementingObject(ComponentEditor));
PrevEditorClass := PrevEditor.ClassType;
finally
CDS.Free;
end;

// Now register our component editor.
RegisterComponents('Samples',[TMyClientDataSet]);
RegisterComponentEditor(TClientDataset, TExClientDataSetEditor);
end;

{ TExClientDataSetEditor }

procedure TExClientDataSetEditor.Copy;
begin
FOldEditor.Copy;
end;

constructor TExClientDataSetEditor.Create(AComponent: TComponent; ADesigner: IDesigner);
begin
inherited;
FOldEditor :=
TComponentEditorClass(PrevEditorClass).Create(AComponent, ADesigner)
as TDatasetEditor;
end;

destructor TExClientDataSetEditor.Destroy;
begin
FreeAndNil(FOldEditor);
inherited;
end;

procedure TExClientDataSetEditor.Edit;
begin
FOldEditor.Edit;
end;

procedure TExClientDataSetEditor.ExecuteVerb(Index: Integer);
var
I: Integer;
begin
I := Index - FOldEditor.GetVerbCount;
case I of
0: ShowMessage('My Verb 1');
1: ShowMessage('My Verb 2');
else
FOldEditor.ExecuteVerb(Index)
end;
end;

function TExClientDataSetEditor.GetDSDesignerClass: TDSDesignerClass;
begin
Result := TExClientDataSetEditor(FOldEditor).GetDSDesignerClass;
// hack to access protected method
end;

function TExClientDataSetEditor.GetVerb(Index: Integer): string;
var
I: Integer;
begin
I := Index - FOldEditor.GetVerbCount;
case I of
0: Result := 'My Verb 1';
1: Result := 'My Verb 2';
else
Result := FOldEditor.GetVerb(Index)
end;
end;

function TExClientDataSetEditor.GetVerbCount: Integer;
begin
Result := FOldEditor.GetVerbCount + 2;
end;

procedure TExClientDataSetEditor.PrepareItem(Index: Integer;
const AItem: IMenuItem);
var
I: Integer;
begin
I := Index - FOldEditor.GetVerbCount;
case I of
0: AItem.Caption := 'My Verb 1 - prepared' ;
1: AItem.Caption := 'My Verb 2 - prepared' ;
else
FOldEditor.PrepareItem(Index, AItem);
end;
end;

end.


Back to top
Maris Janis Vasilevskis
Guest





PostPosted: Tue Nov 18, 2003 4:30 pm    Post subject: Re: How to mix components context menu Reply with quote

Sorry, the last line in Register, of course, should be
RegisterComponentEditor(TMyClientDataset, TExClientDataSetEditor);

Mahris

Back to top
Dietmar Brueckmann
Guest





PostPosted: Wed Nov 19, 2003 8:57 am    Post subject: Done: How to mix components context menu Reply with quote

Hi,

It seems that I've implemented it 75% successfully.

Only the entry "assign local data" (translation from german. It is the 3rd
of the 4 original menu entries, the 4th of TDemoClientDataSet )
fails with an AV.
A pure TClientDataSet doesn't,
and if I do not "RegisterComponentEditor(TDemoClientDataSet,
TdbCDS_DemoEditor)"
its also ok)

But a second question is open:

what is to do with aIComponentEditor do in Destroy.

_____________________________________________
unit PropEdCdsDemoReg;

interface

uses Classes, DesignIntf, DesignEditors, DBClient;

type

TDemoClientDataSet = class(TClientDataSet)
end;

{ TdbCDS_DemoEditor }

TdbCDS_DemoEditor = class(TComponentEditor)
private
protected
cds : TClientDataSet;
aIComponentEditor : IComponentEditor;
procedure DoSomething;
public
constructor Create(AComponent: TComponent; ADesigner: IDesigner);
override;
procedure ExecuteVerb(Index: Integer); override;
function GetVerb(Index: Integer): string; override;
function GetVerbCount: Integer; override;
end;

procedure Register;

implementation

uses Dialogs;

procedure Register;
begin
RegisterComponents('DBrS', [TDemoClientDataSet]);
RegisterComponentEditor(TDemoClientDataSet, TdbCDS_DemoEditor);
end;
constructor TdbCDS_DemoEditor.Create(AComponent: TComponent;
ADesigner: IDesigner);
begin
inherited;
cds := TClientDataSet.Create(nil);
aIComponentEditor := DesignEditors.GetComponentEditor(cds,ADesigner);
end;
function TdbCDS_DemoEditor.GetVerbCount: Integer;
begin
Result := aIComponentEditor.GetVerbCount+1;
end;
function TdbCDS_DemoEditor.GetVerb(Index: Integer): string;
begin
if Index=0 then Result := 'DoSomething'
else Result := aIComponentEditor.GetVerb(Index-1);
end;
procedure TdbCDS_DemoEditor.ExecuteVerb(Index: Integer);
begin
if Index=0 then DoSomething
else aIComponentEditor.ExecuteVerb(Index-1);
end;
procedure TdbCDS_DemoEditor.DoSomething;
begin
ShowMessage('DoSomething for CDS');
end;

end.
______________________________________________________


Back to top
Maris Janis Vasilevskis
Guest





PostPosted: Wed Nov 19, 2003 12:54 pm    Post subject: Re: Done: How to mix components context menu Reply with quote

You should do nothing with aIComponentEditor. It is an interface, and
system destroys it, when needed. Of course, you should destroy cds.

But this solution will not work in inherited part.
Not only "assign local data", all other items are incorrect too.
They deal with your cds, not your component.

To work with your component, you need inherited editor created
specially for it. See my previous posting.

Mahris

Dietmar Brueckmann wrote:
Quote:
Hi,

It seems that I've implemented it 75% successfully.

Only the entry "assign local data" (translation from german. It is the 3rd
of the 4 original menu entries, the 4th of TDemoClientDataSet )
fails with an AV.
A pure TClientDataSet doesn't,
and if I do not "RegisterComponentEditor(TDemoClientDataSet,
TdbCDS_DemoEditor)"
its also ok)

But a second question is open:

what is to do with aIComponentEditor do in Destroy.


Back to top
Dietmar Brueckmann
Guest





PostPosted: Thu Nov 20, 2003 6:46 am    Post subject: Re: How to mix components context menu Reply with quote


"Maris Janis Vasilevskis" <mahris (AT) myself (DOT) com> schrieb im Newsbeitrag
news:3fb9f060$1 (AT) newsgroups (DOT) borland.com...
Quote:
To keep all previous items and have the new item on top, do the following:

function TdbCDS_Editor.GetVerbCount: Integer;
begin
Result := inherited GetVerbCount + 1;
end;
function TdbCDS_Editor.GetVerb(Index: Integer): string;
begin
case Index of
0 : Result := 'Do This';
else Result := inherited GetVerb(Index-1);
end;
end;
procedure TdbCDS_Editor.ExecuteVerb(Index: Integer);
begin
case Index of
0 : DoThis;
else inherited ExecuteVerb(Index-1);
end;
end;


Sorry, possibly I've misunderstood you, but because of

TdbCDS_Editor = class(TComponentEditor)
"inherited GetVerbCount" results in 0.
I'd need something like this:
TdbCDS_Editor = class(TClientDatasetEditor)

Best regards
dietmar



Back to top
Dietmar Brueckmann
Guest





PostPosted: Thu Nov 20, 2003 7:39 am    Post subject: Re: Done: How to mix components context menu Reply with quote


"Maris Janis Vasilevskis" <mahris (AT) myself (DOT) com> schrieb im Newsbeitrag
news:3fbb67ff$1 (AT) newsgroups (DOT) borland.com...
Quote:
You should do nothing with aIComponentEditor. It is an interface, and
system destroys it, when needed. Of course, you should destroy cds.

But this solution will not work in inherited part.
Not only "assign local data", all other items are incorrect too.
They deal with your cds, not your component.

I've seen it too - after posting "done" before testing - foolish - only the
menuitems are there and the belong to the private cds. Nice but unusable.

I've tried to change
cds := TClientDataSet.Create(nil);
aIComponentEditor := DesignEditors.GetComponentEditor(cds,ADesigner);
in
cds := TClientDataSet(Component);
aIComponentEditor := DesignEditors.GetComponentEditor(cds,ADesigner);
but it goes into a stack overflow - and so I give up.

Quote:
To work with your component, you need inherited editor created
specially for it. See my previous posting.

Sorry but this all is far of that I've done previously.

Should I use "GetImplementingObject" - it looks quite horrible.

should I try

constructor TdbCDS_DemoEditor.Create(AComponent: TComponent;
ADesigner: IDesigner);
begin
inherited;
aIComponentEditor := GetImplementingObject(ADesigner);
end;

and all is ok?

Sorry for bothering you - but it would be a "nice to have" !

Best regards
Dietmar



Back to top
Maris Janis Vasilevskis
Guest





PostPosted: Thu Nov 20, 2003 12:22 pm    Post subject: Re: Done: How to mix components context menu Reply with quote

There is no easy way for your task.
I posted a working code made by mixing two other publications,
you can copy it and use.
About GetImplementingObject - see discussion in the mentioned link.
Of course, no warranty for D8, but OK for D6 and D7.

Mahris

Dietmar Brueckmann wrote:
Quote:
Sorry but this all is far of that I've done previously.
Should I use "GetImplementingObject" - it looks quite horrible.


Back to top
Display posts from previous:   
Post new topic   Reply to topic    BorlandTalk.com Forum Index -> Delphi VCL Components Writing All times are GMT
Page 1 of 1

 
Jump to:  
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum


Powered by phpBB © 2001, 2006 phpBB Group
SEO toolkit © 2004-2006 webmedic.