File Drop Target for SAP GUI Apps

This year (I wanted to say “This Christmas”, but that is still a long way away) surprise your users with something nice: A file drop target for your ABAP applications. It’s easy – I’ll show you how.


UPDATE (25 Jan 2010): There is now a SAPLink Nugget containing the class at the end of this post.

You know how you normally write those programs for users to upload files from their desktop? You normally put a field on the selection screen, and if you are kind enough, provide a dropdown that opens the Windows Explorer File Open dialog. Using this nice and easy technique, however, you can let users drag files from Explorer on to the SAP GUI and upload the files that way instead.

The first thing we will do is to create a new class, so head over to SE24 already.

I originally intended to inherit from CL_GUI_TEXTEDIT, but I decided instead to have an attribute of this type, together with a CL_GUI_CUSTOM_CONTAINER. The program developer (you) will only have to instantiate the class with the name of the control on the screen (and a callback routine name, but we’ll get to that further on). The reason I used CL_GUI_TEXTEDIT is that it implements file-drop behaviour, and we can customize it to look like a fairly decent drop target with minimal effort.

Next, we will declare the methods. There is only a Constructor, and an event handler for the text edit control for when a file is dropped on it.

The DROP_HANDLER method has no parameters (like the event for which it caters). To set it as an event handler, open up the properties for the method and set it as an event handler for event FILEDROP of class CL_GUI_TEXTEDIT.

The constructor takes as its parameters the name of the container on the dynpro screen, and optionally (although it would be senseless without it) the name of the callback subroutine in your program that will receive the names of the files dropped on the editor control.

Now we can get on to the coding. First, we will take a look at the constructor method:

method constructor.
  data: drop_message type
        string value '*** DROP FILE HERE ***'.              "TODO: I18N
  data: msg_len type i.
  data: event_tab type cntl_simple_events,
        event     type cntl_simple_event.

* Save the callback routine name
  me->callback_routine = callback_routine.

  msg_len = strlen( drop_message ).

* Set up container on dynpro
  create object container
    exporting container_name = container_name.
  create object editor
    exporting parent = container
              filedrop_mode = cl_gui_textedit=>dropfile_event_multiple
              max_number_chars = msg_len.

* For the callback, get the calling program from the call stack
  data: lt_call type sys_callst.
  data: ls_call type sys_calls.
  call function 'SYSTEM_CALLSTACK'
    exporting
      max_level    = 2
    importing
      et_callstack = lt_call.
  read table lt_call into ls_call index 2.
  if sy-subrc = 0.
    callback_program = ls_call-progname.
  endif.

* Set editor features to disallow edit, but allow drop
  editor->set_toolbar_mode( ).
  editor->set_statusbar_mode( ).
  editor->set_textstream( drop_message ).
  editor->protect_lines( from_line = 1 to_line = 200 ).

* Set events
  event-eventid = cl_gui_textedit=>event_multiplefilesdropped.
  event-appl_event = ' '.
  append event to event_tab.
  call method: editor->set_registered_events
               exporting events = event_tab.
  set handler drop_handler for editor.
endmethod.

Let’s break down what is going on in this method:

* Set up container on dynpro
  create object container
    exporting container_name = container_name.
  create object editor
    exporting parent = container
              filedrop_mode = cl_gui_textedit=>dropfile_event_multiple
              max_number_chars = msg_len.

Our first course of action is to instantiate the necessary controls for the screen, namely the container and the text edit control. We enable the text edit control to respond to file drop events (we are catering for the possibility that the user may want to upload multiple files). The maximum number of characters is determined from the drop_message variable. You will probably want to make this text language-dependent.

* For the callback, get the calling program from the call stack
  data: lt_call type sys_callst.
  data: ls_call type sys_calls.
  call function 'SYSTEM_CALLSTACK'
    exporting
      max_level    = 2
    importing
      et_callstack = lt_call.
  read table lt_call into ls_call index 2.
  if sy-subrc = 0.
    callback_program = ls_call-progname.
  endif.

To save the developer from having to specify the name of the program from which they are invoking this class, we interrogate the call stack to get the program name, just as a courtesy to them.

* Set editor features to disallow edit, but allow drop
  editor->set_toolbar_mode( ).
  editor->set_statusbar_mode( ).
  editor->set_textstream( drop_message ).
  editor->protect_lines( from_line = 1 to_line = 200 ).

Now we disable the toolbar and status bar, because they would serve no purpose other than looking ugly. We set the text to our message, telling the user that this is a drop target for their file(s). Also, we protect the text, thereby preventing the user from entering or changing text. If we completely disabled the text editor, the drop event would not be handled.

* Set events
  event-eventid = cl_gui_textedit=>event_multiplefilesdropped.
  event-appl_event = ' '.
  append event to event_tab.
  call method: editor->set_registered_events
               exporting events = event_tab.
  set handler drop_handler for editor.

Lastly, we register the multiple file drop event so that the control actually handles it. The very last line sets our DROP_HANDLER method as the handler for the event.

Next, let us look at the handler event:

* Get the paths of the file(s) droppen on the editor
  data: path type char100.
  data: paths like table of path.
  editor->get_path_of_dropped_files( importing table = paths ).

* Call the callback subroutine, if it exists
  perform (callback_routine) in program (callback_program)
    tables paths
    if found.

This method calls the GET_PATH_OF_DROPPED_FILES on the text edit control to obtain the names of the dropped files. It then passed it back to the calling program via the callback routine specified in the constructor.

Well, that was easy! Now, let’s look at a program that makes use of this class. The first thing to do is define a screen with an area on it that will hold the drop target control. You can simply add this to a report program if you wish. (That’s what I did).

The code of your program is very simple:

data: drop_target type ref to zcl_gui_file_drop_target.

call screen 100.
*&---------------------------------------------------------------------*
*&      Module  STATUS_0100  OUTPUT
*&---------------------------------------------------------------------*
module status_0100 output.
  set TITLEBAR '0100'.
  if drop_target is initial.
    create object drop_target
      exporting
        container_name = 'DROPTARGET'
        callback_routine = 'DROP_CALLBACK'.
  endif.
endmodule.                 " STATUS_0100  OUTPUT
*&---------------------------------------------------------------------*
*&      Module  USER_COMMAND_0100  INPUT
*&---------------------------------------------------------------------*
module user_command_0100 input.
  if sy-ucomm = 'BACK'.
    leave program.
  endif.
endmodule.                 " USER_COMMAND_0100  INPUT

*&---------------------------------------------------------------------*
*&      Form  drop_callback
*&---------------------------------------------------------------------*
form drop_callback tables files type standard table.
* Here you receive the list of files dropped on the drop target
* The rest is up to you...
endform.                    "drop_callback

In the PBO module, we simply instantiate the class once, passing it the name of the container on our screen, and the name of the callback subroutine. The PAI module simply has a method for getting out of the screen for demo purposes.

In the callback routine, you receive a list of the files (or just one file) that were dropped on the edit area of the control. Now you can upload the files from the user’s desktop. (I could have done that for you too, but you need to do some coding yourself!)

Download the following nugget to get the code:
NUGG_ZCL_GUI_FILE_DROP_TARGET.nugg

Tags: , ,