Abap code to add a check box for each record when a list is displayed

by Pramita Singh on Tuesday 30 September 2008


REPORT ZSACHIN2.

TYPE-POOLS: slis.

*—internal tables

DATA: BEGIN OF it_flight OCCURS 0,
SEL, ” add a single character field in the final output table
carrid LIKE sflight-carrid,
connid LIKE sflight-connid,
fldate LIKE sflight-fldate,
seatsmax LIKE sflight-seatsmax,
seatsocc LIKE sflight-seatsocc,
END OF it_flight,

*–internal tables for alv

it_fieldcat TYPE slis_t_fieldcat_alv,
wa_fcat LIKE LINE OF it_fieldcat,
layout TYPE slis_layout_alv,
it_sort type slis_t_sortinfo_alv,
wa_sort like line of it_sort.

DATA: BEGIN OF it_flight_sel OCCURS 0,
SEL,
carrid LIKE sflight-carrid,
connid LIKE sflight-connid,
fldate LIKE sflight-fldate,
seatsmax LIKE sflight-seatsmax,
seatsocc LIKE sflight-seatsocc,
END OF it_flight_sel.

data: wa_flight like it_flight.

* In the layout set give the name of the field
* whose checkbox will be created ( SEL as it has 1 char only )

layout-box_fieldname = ‘SEL’.

*—start-of-selection .

START-OF-SELECTION.

CALL FUNCTION ‘REUSE_ALV_FIELDCATALOG_MERGE’

EXPORTING
i_program_name = sy-repid
i_internal_tabname = ‘IT_FLIGHT’
i_inclname = sy-repid
CHANGING
ct_fieldcat = it_fieldcat
EXCEPTIONS
inconsistent_interface = 1
program_error = 2.

*—-get data

SELECT carrid
connid
fldate
seatsmax
seatsocc
FROM sflight
INTO CORRESPONDING FIELDS OF TABLE it_flight
UP TO 20 ROWS.

wa_fcat-do_sum = ‘X’.
MODIFY it_fieldcat FROM wa_fcat TRANSPORTING do_sum
WHERE fieldname = ‘SEATSOCC’ .

wa_sort-fieldname = ‘CARRID’.
wa_sort-group = ‘UL’.
wa_sort-up = ‘X’.
APPEND wa_sort TO it_sort.
clear wa_sort.

wa_sort-fieldname = ‘CONNID’.
wa_sort-subtot = ‘X’.
wa_sort-up = ‘X’.
APPEND wa_sort TO it_sort.
clear wa_sort.

CALL FUNCTION ‘REUSE_ALV_LIST_DISPLAY’
EXPORTING
i_callback_program = sy-repid
I_CALLBACK_USER_COMMAND = ‘USER_COMMAND’
is_layout = layout
it_fieldcat = it_fieldcat
it_sort = it_sort
TABLES
t_outtab = it_flight
EXCEPTIONS
program_error = 1.

FORM user_command USING r_ucomm LIKE sy-ucomm
rs_selfield TYPE slis_selfield.

* Check function code
CASE r_ucomm.

* WHEN ‘&IC1′.
** Check field clicked on within ALVgrid report
* IF rs_selfield-fieldname = ‘EBELN’.
** Read data table, using index of row user clicked on
* READ TABLE it_ekko INTO wa_ekko INDEX rs_selfield-tabindex.
** Set parameter ID for transaction screen field
* SET PARAMETER ID ‘BES’ FIELD wa_ekko-ebeln.
** Sxecute transaction ME23N, and skip initial data entry screen
* CALL TRANSACTION ‘ME23N’ AND SKIP FIRST SCREEN.
* ENDIF.

WHEN ‘&IC1′. “‘&DATA_SAVE’. “user presses SAVE
loop at it_flight into wa_flight.

if wa_flight-Sel EQ ‘X’.

* collecting records in table it_flight_sel to process further
append wa_flight to it_flight_sel.
clear wa_flight.

endif.
endloop.
ENDCASE.

ENDFORM.



Example ABAP Code to colour Selected row in ALV

by Pramita Singh on Tuesday 30 September 2008


*&———————————————————————*
*& Report ZSACHIN_ALV_DEEP32

REPORT ZSACHIN_ALV_DEEP32.

TABLES: MARA.

TYPE-POOLS: SLIS.

DATA: BEGIN OF ITAB OCCURS 0,
MATNR TYPE MARA-MATNR,
ERSDA TYPE MARA-ERSDA,
ERNAM TYPE MARA-ERNAM,

* create a field of 4 char to fill the color
WA_COLOR(4) TYPE C,

END OF ITAB.

DATA: GT_FIELDCAT TYPE SLIS_T_FIELDCAT_ALV,
WA_FIELDCAT TYPE SLIS_FIELDCAT_ALV.

* create a field symbol to add color for the selected row
FIELD-SYMBOLS: LIKE ITAB.

DATA: gd_layout type slis_layout_alv.

START-OF-SELECTION.

SELECT MATNR ERSDA ERNAM FROM MARA INTO TABLE ITAB UP TO 100 ROWS.

WA_FIELDCAT-SELTEXT_L = ‘MATERIAL NUMBER’.
WA_FIELDCAT-COL_POS = ‘1′.
WA_FIELDCAT-TABNAME = ‘MARA’.
WA_FIELDCAT-hotspot = ‘X’.
WA_FIELDCAT-no_zero = ‘X’.
WA_FIELDCAT-FIELDNAME = ‘MATNR’.

APPEND WA_FIELDCAT TO GT_FIELDCAT.
CLEAR WA_FIELDCAT.

WA_FIELDCAT-SELTEXT_L = ‘Created On’.
WA_FIELDCAT-COL_POS = ‘2′.
WA_FIELDCAT-TABNAME = ‘MARA’.
WA_FIELDCAT-FIELDNAME = ‘ERSDA’.
WA_FIELDCAT-emphasize = ‘C110′.

APPEND WA_FIELDCAT TO GT_FIELDCAT.
CLEAR WA_FIELDCAT.

WA_FIELDCAT-SELTEXT_L = ‘Name of Person’.
WA_FIELDCAT-COL_POS = ‘3′.
WA_FIELDCAT-TABNAME = ‘MARA’.
WA_FIELDCAT-FIELDNAME = ‘ERNAM’.
WA_FIELDCAT-just = ‘R’.
*WA_FIELDCAT-emphasize = ‘C600′.

APPEND WA_FIELDCAT TO GT_FIELDCAT.
CLEAR WA_FIELDCAT.

* loop through thetable to update the color forthe selected row
LOOP AT ITAB ASSIGNING .

IF SY-TABIX = ‘5′.
-WA_COLOR = ‘C311′.
ENDIF.

ENDLOOP.

*PERFORM GET_EVENTS.

* Give the name field in which we have filled the color code
gd_layout-info_fieldname = ‘WA_COLOR’.
gd_layout-zebra = ‘X’.

*GD_LAYOUT-edit = ‘X’. ” this will make the alv editable
” and for each record make a box on left side
GD_LAYOUT-no_vline = ‘X’.

CALL FUNCTION ‘REUSE_ALV_GRID_DISPLAY’
EXPORTING
* I_INTERFACE_CHECK = ‘ ‘
I_BYPASSING_BUFFER = ‘X’
* I_BUFFER_ACTIVE = ‘ ‘
I_CALLBACK_PROGRAM = sy-repid
* I_CALLBACK_PF_STATUS_SET = ‘ZSACHIN1111′
I_CALLBACK_USER_COMMAND = ‘FRM_USR_COMMAND’
I_CALLBACK_TOP_OF_PAGE = ‘TOP_OF_PAGE’
* I_CALLBACK_HTML_TOP_OF_PAGE = ‘ ‘
* I_CALLBACK_HTML_END_OF_LIST = ‘ ‘
* I_STRUCTURE_NAME = MARA etc
* I_BACKGROUND_ID = ‘ ‘
I_GRID_TITLE = ‘TITLE OF THE GRID’
* I_GRID_SETTINGS =
IS_LAYOUT = GD_LAYOUT
IT_FIELDCAT = GT_FIELDCAT
* IT_EXCLUDING =
* IT_SPECIAL_GROUPS =
* IT_SORT =
* IT_FILTER =
* IS_SEL_HIDE =
* I_DEFAULT = ‘X’
I_SAVE = ‘A’
* IS_VARIANT = i_varient1
* IT_EVENTS =
* IT_EVENT_EXIT =
* IS_PRINT =
* IS_REPREP_ID =
* I_SCREEN_START_COLUMN = 0
* I_SCREEN_START_LINE = 0
* I_SCREEN_END_COLUMN = 0
* I_SCREEN_END_LINE = 0
* I_HTML_HEIGHT_TOP = 0
* I_HTML_HEIGHT_END = 0
* IT_ALV_GRAPHICS =
* IT_HYPERLINK =
* IT_ADD_FIELDCAT =
* IT_EXCEPT_QINFO =
* IR_SALV_FULLSCREEN_ADAPTER =
* IMPORTING
* E_EXIT_CAUSED_BY_CALLER =
* ES_EXIT_CAUSED_BY_USER =
TABLES
t_outtab = ITAB
EXCEPTIONS

PROGRAM_ERROR = 1
OTHERS = 2
.
IF sy-subrc <> 0.
MESSAGE ID SY-MSGID TYPE SY-MSGTY NUMBER SY-MSGNO
WITH SY-MSGV1 SY-MSGV2 SY-MSGV3 SY-MSGV4.
ENDIF.

*FORM SAC_LAYOUT.

*ENDFORM.

FORM FRM_USR_COMMAND USING OK_CODE TYPE SY-UCOMM RS_SELFIELD TYPE SLIS_SELFIELD .

CASE OK_CODE.

WHEN ‘PICK’.

READ TABLE ITAB INDEX RS_SELFIELD-TABINDEX.

PERFORM CALL_TRANS USING ITAB-MATNR.

ENDCASE.

ENDFORM.

FORM CALL_TRANS USING MATNR.

SET PARAMETER ID ‘MAT’ FIELD MATNR. “Global memory sap memory.

CALL TRANSACTION ‘MM02′ AND SKIP FIRST SCREEN.

ENDFORM.

form PFSTATUS.

*SET PF-STATUS ‘ZSACHIN1111′.

ENDFORM.

FORM TOP_OF_PAGE.

WRITE: ‘SACHIN THE BOND’.

ENDFORM.



Example ABAP Code to colour individual box in ALV

by Pramita Singh on Tuesday 30 September 2008

REPORT ZSACHIN_ALV_DEEP33.


TABLES: MARA.

TYPE-POOLS: SLIS.

DATA: BEGIN OF ITAB OCCURS 0,
MATNR TYPE MARA-MATNR,
ERSDA TYPE MARA-ERSDA,
ERNAM TYPE MARA-ERNAM,
* Create a field CELL of type SLIS_T_SPECIALCOL_ALV
CELL TYPE SLIS_T_SPECIALCOL_ALV,
END OF ITAB.

DATA: GT_FIELDCAT TYPE SLIS_T_FIELDCAT_ALV,
WA_FIELDCAT TYPE SLIS_FIELDCAT_ALV.
* Create a work area of type SLIS_T_SPECIALCOL_ALV
DATA: FS_CELL LIKE LINE OF ITAB-CELL.

* Create a layout
DATA: gd_layout type slis_layout_alv.

*—————————————————————–*
* START OF SELECTION *
*—————————————————————–*

START-OF-SELECTION.

SELECT MATNR
ERSDA
ERNAM
FROM MARA
INTO CORRESPONDING FIELDS OF
TABLE ITAB UP TO 100 ROWS.

*—————————————————————–*
* Creating field catalog *
*—————————————————————–*

WA_FIELDCAT-SELTEXT_L = ‘MATERIAL NUMBER’.
WA_FIELDCAT-COL_POS = ‘1′.
WA_FIELDCAT-TABNAME = ‘MARA’.
WA_FIELDCAT-hotspot = ‘X’.
WA_FIELDCAT-no_zero = ‘X’.
WA_FIELDCAT-FIELDNAME = ‘MATNR’.

APPEND WA_FIELDCAT TO GT_FIELDCAT.
CLEAR WA_FIELDCAT.

WA_FIELDCAT-SELTEXT_L = ‘Created On’.
WA_FIELDCAT-COL_POS = ‘2′.
WA_FIELDCAT-TABNAME = ‘MARA’.
WA_FIELDCAT-FIELDNAME = ‘ERSDA’.
WA_FIELDCAT-emphasize = ‘C611′.

APPEND WA_FIELDCAT TO GT_FIELDCAT.
CLEAR WA_FIELDCAT.

WA_FIELDCAT-SELTEXT_L = ‘Name of Person’.
WA_FIELDCAT-COL_POS = ‘3′.
WA_FIELDCAT-TABNAME = ‘MARA’.
WA_FIELDCAT-FIELDNAME = ‘ERNAM’.
WA_FIELDCAT-just = ‘R’.
*WA_FIELDCAT-emphasize = ‘C600′.

APPEND WA_FIELDCAT TO GT_FIELDCAT.
CLEAR WA_FIELDCAT.

* Fill the workarea with the field to be colored,
* the color to be appeared
* and give NOKEYCOL = ‘X’.

FS_CELL-FIELDNAME = ‘ERSDA’.
FS_CELL-COLOR-COL = 3.
FS_CELL-NOKEYCOL = ‘X’.
APPEND FS_CELL TO ITAB-CELL.

* To the specific row modify the contents of the CELL
MODIFY ITAB INDEX 8 TRANSPORTING CELL.

*PERFORM GET_EVENTS.

gd_layout-info_fieldname = ‘WA_COLOR’.
gd_layout-zebra = ‘X’.

* Give the name field in which we have filled the color code
gd_LAYOUT-COLTAB_FIELDNAME = ‘CELL’.

*GD_LAYOUT-edit = ‘X’. ” this will make the alv editable
” and for each record make a box on left side
GD_LAYOUT-no_vline = ‘X’.

CALL FUNCTION ‘REUSE_ALV_GRID_DISPLAY’
EXPORTING
* I_INTERFACE_CHECK = ‘ ‘
I_BYPASSING_BUFFER = ‘X’
* I_BUFFER_ACTIVE = ‘ ‘
I_CALLBACK_PROGRAM = sy-repid
* I_CALLBACK_PF_STATUS_SET = ‘ZSACHIN1111′
I_CALLBACK_USER_COMMAND = ‘FRM_USR_COMMAND’
I_CALLBACK_TOP_OF_PAGE = ‘TOP_OF_PAGE’
* I_CALLBACK_HTML_TOP_OF_PAGE = ‘ ‘
* I_CALLBACK_HTML_END_OF_LIST = ‘ ‘
* I_STRUCTURE_NAME = MARA etc
* I_BACKGROUND_ID = ‘ ‘
I_GRID_TITLE = ‘TITLE OF THE GRID’
* I_GRID_SETTINGS =
IS_LAYOUT = GD_LAYOUT
IT_FIELDCAT = GT_FIELDCAT
* IT_EXCLUDING =
* IT_SPECIAL_GROUPS =
* IT_SORT =
* IT_FILTER =
* IS_SEL_HIDE =
* I_DEFAULT = ‘X’
I_SAVE = ‘A’
* IS_VARIANT = i_varient1
* IT_EVENTS =
* IT_EVENT_EXIT =
* IS_PRINT =
* IS_REPREP_ID =
* I_SCREEN_START_COLUMN = 0
* I_SCREEN_START_LINE = 0
* I_SCREEN_END_COLUMN = 0
* I_SCREEN_END_LINE = 0
* I_HTML_HEIGHT_TOP = 0
* I_HTML_HEIGHT_END = 0
* IT_ALV_GRAPHICS =
* IT_HYPERLINK =
* IT_ADD_FIELDCAT =
* IT_EXCEPT_QINFO =
* IR_SALV_FULLSCREEN_ADAPTER =
* IMPORTING
* E_EXIT_CAUSED_BY_CALLER =
* ES_EXIT_CAUSED_BY_USER =
TABLES
t_outtab = ITAB
EXCEPTIONS

PROGRAM_ERROR = 1
OTHERS = 2
.
IF sy-subrc <> 0.
MESSAGE ID SY-MSGID TYPE SY-MSGTY NUMBER SY-MSGNO
WITH SY-MSGV1 SY-MSGV2 SY-MSGV3 SY-MSGV4.
ENDIF.

*FORM SAC_LAYOUT.

*ENDFORM.

FORM FRM_USR_COMMAND USING OK_CODE TYPE SY-UCOMM RS_SELFIELD TYPE SLIS_SELFIELD .

CASE OK_CODE.

WHEN ‘PICK’.

READ TABLE ITAB INDEX RS_SELFIELD-TABINDEX.

PERFORM CALL_TRANS USING ITAB-MATNR.

ENDCASE.

ENDFORM.

FORM CALL_TRANS USING MATNR.

SET PARAMETER ID ‘MAT’ FIELD MATNR. “Global memory sap memory.

CALL TRANSACTION ‘MM02′ AND SKIP FIRST SCREEN.

ENDFORM.

form PFSTATUS.

*SET PF-STATUS ‘ZSACHIN1111′.

ENDFORM.

FORM TOP_OF_PAGE.

WRITE: ‘SACHIN THE BOND’.

ENDFORM.



How to put Logo or photo in ALV Report

by Pramita Singh on Tuesday 30 September 2008


Logo should be uploaded into application server using transaction ‘OAER’.
1. Go to Transaction OAER,
2. Give Class Name as PICTURES
3. Class type as OT
4. Object Key is the name you want to search or you want to upload.
5. Then select the Document from below after double click on it .Choose in screen for logos.
6. Upon execution you would be prompted to give the file path details. Just upload which ever logo u want to display
7. Now you can use the same name in your ALV FM.
In your ALV program, you need to have event for TOP_OF_PAGE, and also this works only in case of Grid not in ALV LIST.

Look at the sample code to display LOGO.

**********************

call function ‘REUSE_ALV_GRID_DISPLAY’
exporting
i_callback_program = i_repid
it_fieldcat = header
is_layout = gt_layout
i_callback_top_of_page = ‘TOP-OF-PAGE1′
i_grid_title = xyz
it_sort = gt_sort[]
i_default = ‘X’
i_save = ‘U’
is_variant = gt_variant
it_events = gt_events
tables
t_outtab = t_output.

*****************

*——————————————————————-*

* Form TOP-OF-PAGE1

*——————————————————————-*

form top-of-page1.

data: header type slis_t_listheader,
wa type slis_listheader.

* TITLE AREA

wa-typ = ‘S’.
wa-info = text-h04.
append wa to header.

wa-typ = ‘S’.
write sy-datum to wa-info mm/dd/yyyy.

concatenate text-h03 wa-info into wa-info separated by space.
append wa to header.

wa-typ = ‘S’.
concatenate text-h02 sy-uname into wa-info separated by space.
append wa to header.

wa-typ = ‘S’.
concatenate text-h01 sy-repid into wa-info separated by space.
append wa to header.

********” LOGO

call function ‘REUSE_ALV_COMMENTARY_WRITE’

exporting

it_list_commentary = header

i_logo = ‘ENJOYSAP_LOGO’.

*********” LOGO

endform.

Here in TOP-OF-PAGE form it will show you the Prog name,Date, User Name



Implementing flash.events.EventDispatcher in C++

by LiraNuna on Saturday 27 September 2008

Call me crazy, but I really like Flash’s EventDispatcher class – it’s simple, powerful and most of all relatively fast.

I felt the need to take EventDispatcher outside of my flash projects to my more advanced C++ ones. This turned out to be quite an easy task.

Instead of a boring ‘download code’ link, I will write the steps of implementing it using C++’s STLs, just because I feel like writing.

I would like to start by noting that I will only implement the EventDispatcher class, and not flash.events.Event. I will have a very basic and dull Event class. Another note would be the Object class, which isn’t reimplemented for performance (RTTI hacks are expensive).

Let’s start by examining our situation:

  • Events are identified as strings
  • An event can have several listeners
  • Event functions have priority from -2M to 2M (32bit signed)
  • Events have phases

In this article, I will tackle those one by one.

Let’s starts with the basics, we know EventDispatcher::addEventListener takes functions as callbacks, so let’s define an event listener type. Before we can do that though, we also need to define an Event class to be passed when the event callback is called.

	// Event class
class Event
{
	public:
		Event(std::string type, bool bubbles = false, bool cancelable = false):
			type(type), bubbles(bubbles), cancelable(cancelable)
		{
 
		}
 
		const std::string type;
 
		const bool bubbles;
		const bool cancelable;
	/*
		const void* target;
		const unsigned int eventPhase;
		const void* currentTarget;
	*/
};
 
	// Event function callback pointer type
typedef void (*eventFunctionPtr)(const Event &);

The Event class does nothing important but emulating flash’s Event class and holding a const std::string for the type of the event.

The callback type, called eventFunctionPtr basically points to a function that returns nothing (void) and takes a const refrence to an Event as an argument, so the following AS3 code:

public function eventListener(event:Event):void
{
	// Listener code ...
}

Would become this code in C++:

void eventListener(const Event &event)
{
	// Listener code ...
}

Now that we have our Event class type and the function callback type, let’s implement the basics – mapping string to function callbacks. This can easily be done using std::map which stores data (in this case, a function pointer) that can later be retrieved by using a key (in this case, a string). This is a bit like using a primary key to refer to a record in a database table.

The code at the moment is quite simple, having only addEventListener coded:

class EventDispatcher
{
	public:
		void addEventListener(const std::string &type, eventFunctionPtr listener, bool useCapture = false, int priority = 0, bool useWeakReference = false)
		{
				// Set the event listener to the key
			eventHandlerList[type] = listener;
		}
 
	private:
		std::map<std::string, eventFunctionPtr > eventHandlerList;
};

Implementing the method hasEventListener is also effortless, since we are just checking to see if a key exists on the map:

bool hasEventListener(const std::string &type)
{
	return (eventHandlerList.find(type) != eventHandlerList.end());
}

Now for the heart of the EventDispatcher class – the dispatchEvent method, which will simply execute the function we get from the key:

void dispatchEvent(const Event &event)
{
	if(hasEventListener(event.type))
		eventHandlerList[event.type](event);
}

The reason we’re checking if the event listener exists for this event is because std::map will create a null function pointer, which will be slow, memory consuming and will report false positives when using hasEventListener when calling dispatchEvent with event type that is not registered with our EventDispatcher. This simple check makes sure we only execute the event listener if it has in fact, a callback.

When we try to implement the method removeEventListener, we come across a problem – we only have one callback for each event string. removeEventListener method takes a string and a function pointer which will not be used. If one callback per event is what you need, the following code will do the trick:

void removeEventListener(const std::string &type, eventFunctionPtr listener, bool useCapture = false)
{
	eventHandlerList.erase(type);
}

Since that’s not what we desire, we will move on to the next item on the list, which specifies that each event can have several listeners. We can easily do that by mapping a string to a list of function pointers using std::list.

Let’s start by redefining eventHandlerList to it’s new type:

std::map<std::string, std::list<eventFunctionPtr > > eventHandlerList;

However that requires us to change addEventListener and removeEventListener, although hasEventListener will remain unchanged.

addEventListener has the easiest ‘fix’, now instead of assigning the listener to the map’s key, we add it to the list we receive. This changes addEventListener to the following code:

void addEventListener(const std::string &type, eventFunctionPtr listener, bool useCapture = false, int priority = 0, bool useWeakReference = false)
{
		// Simply add the event listener to the list of listeners
	eventHandlerList[type].push_back(listener);
}

In removeEventHandler’s case, we remove all occurrences of the listener from the list, first checking if the map has this key registered:

void removeEventListener(const std::string &type, eventFunctionPtr listener, bool useCapture = false)
{
	if(hasEventListener(type))
		eventHandlerList[type].remove(listener);
}

The dispatchEvent method, however, gets a complete make over, because this time we have to iterate over the list of callbacks and execute them all:

void dispatchEvent(const Event &event)
{
		// Leave if no event registered
	if(!hasEventListener(event.type))
		return;
 
		// A reference to keep code clean
	std::list<eventFunctionPtr > &allFunctions = eventHandlerList[event.type];
 
		// Iterate through all functions in the event and execute them
	for(std::list<eventFunctionPtr >::iterator i=allFunctions.begin(); i!=allFunctions.end(); ++i)
		(*i)(event);
}

The function hasEventListener does not need to change, and still works with our new structure, since the base data structure is still std::map.

Now that we are done with that, we are facing a new problem – priorities. Flash enables you to give priorities to the function, letting them be closer to the time of the event was dispatched. However, Flash is so flexible that it lets us set the priorities as an signed 32bit integer. Imagine this – an array of 4,294,967,296 (2 to the power of 32 – 4 billion) lists residing on memory for each event we have – this is huge!

A neat solution would be to use another map to map integers to list, this time for the sole purpose of saving memory, not speed.

So this time our eventHandlerList evolved into this scary looking type:

std::map<std::string, std::map<int, std::list<eventFunctionPtr > > eventHandlerList;

In case you are lost, here is a quick description of what’s going on: this structure maps a string (event type) to another map, which maps a 32bit integer to a list of function pointers.

Again, we will start by modifying the simplest method, which is addEventListener. The change this time, will simply map the priority in addition to the type:

void addEventListener(const std::string &type, eventFunctionPtr listener, bool useCapture = false, int priority = 0, bool useWeakReference = false)
{
		// Simply add the event listener to the list of listeners for the selected priority
	eventHandlerList[type][priority].push_back(listener);
}

Dispatching an event now gets a little more interesting, since we have to iterate over two structures – first the map of priorities, then the list of callbacks. We will be iterating the map in reverse, since we want higher priority functions (higher keys) to be executed first as opposed to the way std::map iterates which is from lowest to highest (negative to positive).

void dispatchEvent(const Event &event)
{
		// Leave if no event registered
	if(!hasEventListener(event.type))
		return;
 
		// A reference to keep code clean
	std::map<int, std::list<eventFunctionPtr > > &allFunctions = eventHandlerList[event.type];
 
		// Iterate through all functions in the event, from high proproty to low
	for(std::map<int, std::list<eventFunctionPtr > >::reverse_iterator i=allFunctions.rbegin(); i!=allFunctions.rend(); ++i) {
		std::list &funcList = i->second;
			// Execute callbacks
		for(std::list::iterator f=funcList.begin(); f!=funcList.end(); ++f)
			(*f)(event);
	}
}

The real tricky method is removeEventListener – because we only receive the event type and the listener to remove, we have no information on what priority the callback has and where it’s located inside our structure, which means we will have to search for it.

Another problem is false positives – if we remove an event listener from the list, an empty list will stay in memory, meaning that hasEventListener will return true if the list is empty. A way to overcome this problem is to erase the list from the priority map whenever it’s empty AND remove the priority map from the event type map.

The following code will do both:

void removeEventListener(const std::string &type, eventFunctionPtr listener, bool useCapture = false)
{
		// Leave if no event registered
	if(!hasEventListener(type))
		return;
 
		// Reference to keep the code clean
	std::map<int, std::list<eventFunctionPtr > > &allFunctions = eventHandlerList[type];
 
		// Since we don't know the function's priority, we'll search for it
	for(std::map<int, std::list<eventFunctionPtr > >::iterator i=allFunctions.begin(); i!=allFunctions.end(); ++i) {
			// Saving a branch here: instead of checking if the callback exists let remove() do it for us
		i->second.remove(listener);
 
			// Remove object from the map if list gone empty to eliminate false positives
		if(i->second.empty())
			allFunctions.erase(i);
	}
 
		// Remove map to eliminate false positives
	if(allFunctions.empty())
		eventHandlerList.erase(type);
}

I could go on, but from here on, the class really starts integrating into the GUI code part (bubbling, phases…) which would require a GUI code.

I hope this would help someone, I just wanted to write something on my aging site.


Copyright © 2010 IT Knowledge Hub | Advertise | Contact | Privacy Policy | Terms of Use | Register