views:

172

answers:

3

I have a form with most of its functionality implemented using standard TAction. I have a menu, a toolbar, and some toobuttons. I have implemented clipboard copy/paste with no code at all, just using TEditCopy and TEditPaste actions. It works perfect in the TEdit and TMemo boxes I have.

Now, I want it to work with TListBox, too. Specifically, I want to be able to copy the selected list item in a TListBox using the very same menuitems, key shortcuts and toolbuttons.

So, I believe I will need to extend the TEditCopy Action. But it doesn't seem very straight forward to me. In particular, the TEditAction checks for the focused control to be a TCustomEdit control, which a TListBox it is not. I am a little afraid that it will be just too much work.

The obvious alternative is to just forget about the standard actions and implement the copy to clipbard in the OnExecute method of a generic TAction.

But, before giving up, do you have some idea, hint or trick that would help me extend the standard TEditCopy action?

A: 

Hi,

I remember having read something on the web about it, but I can't find the link back. If I find it back, I'll tell you more precisely about it.

What I remember, though, is that an action checks wether it can be applied (or not) to a particular target using the "TBasiAction.HandlesTarget" method - which is virtual. You should check how the methods "HandlesTarget", "UpdateTarget" and "ExecuteTarget" (all members of TBasicAction) are used when executing an Action.

Again, more about this if I find the link back.

[Edit]

This wasn't the post I was looking for, but it seems to describe exactly what you want : etutorials : Defining Custom Actions

LeGEC
Thanks, I had also found this link. Although it provides complete description of what is needed to implement a brand new TAction, it is not applicable to my case. In my case, I already use the standard TEditCopy action, I want to keep, and extend to cope with the case when the focused control is a TListbox.
PA
A: 

You should either override the event handlers of a TAction or create a new descendant that combines the code from TEditAction/TEditCopy with the extra handling for TListBox.

The extension point for actions is setting the OnExecute/OnUpdate event handlers, and that won't work here because it would disable the existing TEdit handling. You could descend from TEditCopy and override the methods, but it would probably be as much code as a new class that descended straight from TAction. There might be some other low-level hack that would work, but I don't see it, and even if there were, it's guaranteed to be less maintainable than the documented approach.

Craig Peterson
Thanks for the answer, this is exactly what I thought I needed, and what I was affraid to do. Reimplementing the complete TEditAction and TEditCopy in a new TEditCopyAction of my own to handle TListBox as well.
PA
I have come out with a solution, see below for my own answer. To thank you four your interest, you deserve that I accepts your answer. Thanks-
PA
+1  A: 

Here is the hack I came out to implement.

It does not require to manually change the ActionList or the MenuItems and ToolButtons I already have, because I keep the same name TEditCopy for the class.

type
 TEditCopy = class(StdActns.TEditCopy)
  public
   function HandlesTarget(Target: TObject): Boolean; override;
   procedure ExecuteTarget(Target: TObject); override;
   procedure UpdateTarget(Target: TObject); override;
  end;

It extends the standard TEditCopy action with the required functionality of supporting TListBox as well.

function TEditCopy.HandlesTarget(Target: TObject): Boolean;
 begin
  result:=(inherited handlesTarget(Target)) or (target is TListbox);
 end;

procedure TEditCopy.ExecuteTarget(Target: TObject);
 begin
  if (target is TListBox) and (TListBox(Target).ItemIndex<>-1) then
    clipboard.AsText:=TListBox(Target).Items[TListBox(Target).ItemIndex]
  else
    inherited;
 end;

procedure TEditCopy.UpdateTarget(Target: TObject);
 begin
  if target is TListbox then
    Enabled := true
  else
    inherited;
 end;

The rest of the application is unchanged. All the copy/paste functionalit is still implemented with no code at all.

PA
You should change UpdateTarget so your Enabled statement is `Enabled := TListBox(Target).ItemIndex <> -1)`. With your current code it will be enabled even if there's no selection, but ExecuteTarget will call the inherited handler and will crash because it's expecting an edit.
Craig Peterson
Yes, you are right! In fact this will never happen in my production code, (I have two IFs instead of a single IF with a just one ELSE) it is only the code I copied here that has the bug.
PA