Wednesday, 16 October 2013

Removing old public Interactive Reports

By saving public Apex Interactive Reports you can offer various custom reports to users without programming. The user opens the page and can choose the reports from the Reports drop down list.
New reports can be added by defining the new report and then exporting the application and importing it in the production environment. Changing existing reports can in some cases cause double entries in the Reports drop down list. This is because the changed report has received a new ID and therefor the original report is not overwritten.
The following procedure can be run for each relevant page before importing the application. It deletes the existing public reports for a specific application and page.

create or replace 
  procedure delete_public_ir_report
                ( p_app_id      in  number
                , p_page_id     in  number
                ) is
begin
  dbms_output.put_line('Deleting public IR reports for application '||p_app_id||' page '||p_page_id);
  for r in ( select * 
             from   apex_application_page_ir_rpt
             where  application_id = p_app_id
               and  page_id        = p_page_id
               and  report_type    = 'PUBLIC'
           ) 
  loop
    dbms_output.put_line('Deleting report '||nvl(r.report_name,'with id '||r.report_id));
    apex_util.ir_delete_report(r.report_id);
  end loop;
end;
/


This procedure works in my situation but each situation is different. Be careful to apply this procedure to your environment and test the results thoroughly before applying it to a production environment.

Happy apexing

Monday, 2 September 2013

Automatically generating images for styles

Lately I have been developing a kind of SaaS website with Apex. Several companies were to be represented in this website and each company wanted to have its own logo and colors. Should be a piece of cake with CSS, shouldn’t it?

But the requirements said rounded corners for tabs and buttons, and support for IE7. That rules out HTML5 :-(.
Using plugins for rounded corners I was not able to get a stable result, so I turned to the good old sliding windows solution using background images. This way the website was stable and reliable. Below two examples of look-and-feel using the same HTML.

The only drawback of this was that a set of 12 images was needed for each company. Creating these images manually using drawing software is a time consuming, tedious and error-prone process.
So I created a webpage containing SVG-images. The webmaster could enter the colors and generate the images. Then these images could be grabbed and cut on the surrounding dotted lines in GIMP. Sounds a lot like kindergarten, doesn’t it? This was already better, but still a tedious and error-prone.

Then my 15 year old son –who is a computer programming addict like myself ;-)- came up with a solution. The open source program ImageMagick is able to convert images including SVG to PNG. The only challenge was that it runs on the command line and Apex is webbased!

The solution is to generate a Windows BAT-file that can be run on a client where ImageMagick is installed. In the BAT-file the SVG images are generated with ECHO-statements. After this ImageMagick is called to do the conversion to PNG. With this solution the neccesary images can be generated in a few minutes, just the time needed to enter the colors and to execute the BAT-file. Below is an example of the generation of the image for a button background.

echo <svg height="22px" version="1.1" width="400px" xmlns="http:www.w3.org2000svg">                  >button.svg
echo </svg>      >>button.svg

convert button.svg button.png
convert button.png -transparent white button.png

The echo statements generate the 2 lines SVG file. The first convert statement converts the SVG file to a PNG. The second convert command changes the white background to transparent in order to use the button on other than white backgrounds.

Happy Apexing! (but you can use this for any kind of website)

Friday, 20 April 2012

Weekday Numbers in Apex sensitive to Application Primary Language

The weekday in Apex is dependent on of the language set in the Application Properties. For that you cannot rely on TO_CHAR(datevalue,’d’), but should use TRUNC(datevalue)-TRUNC(datevalue,'iw')+1 to get ISO weekdays, that are independent of the language set. SQL Workshop did not show differences because the language for SQL Workshop remained the same. This made the analysis more difficult as the results of queries in Apex and SQL Workshop were inconsistent.

I noticed this after having changed the language from English (us) to Dutch(nl) in an application for registering the hours spent and declared on assignments. The screen for registering the declared shows an enterable fields for each day of week to accept the hours worked that day. This screen is showed in the picture below.
Before the change of language this page worked flawlessly. After having set the language to dutch the page did not function like I did before.
At the moment I have the luxury of working four days a week ;-), so I had filled in 8 hours for Monday up to Thursday. After saving this data the application returns to the menu. When I retrieved the page once more, I noticed that the screen showed Sunday up to Wednesday as days.
The data was stored using an offset from the first day of the ISO week. As the ISO week returns the same value regardless of the language the right data were saved. To retrieve the data a view is used in which I used SUM(DECODE(TO_CHAR(datefield,’d’)),2,hours) AS hours_monday to determine the number of hours worked on Monday. With the language set to English, this yielded the correct result. After the language was changed to Dutch, the value for Tuesday was retrieved, as tuesday is the second day in the ISO week.
The number of the weekday differs on the basis of the language. This may not be a surprise, but it was hard to find, because as it was a remote site I was using SQL Workshop to perform SQL statements to check. And apparently SQL Workshop is set to English, regardless of the language of the application (sounds logical). This meant that in SQL Workshop I still got the right results, while in the application, the days were shifted.
The solution was to calculate the weekday number by referring to the start of the ISO-week. The latter number is independent of the language used. We subtract the start of the ISO-week from a given date (use TRUNC to eliminate the time fraction) and add 1 to get the weekday number. The query

SELECT TRUNC(sysdate)-TRUNC(sysdate,'iw')+1 FROM dual

will yield the correct (ISO) day of the week.

As you may have noticed I am developing an Apex application for iPhone. For this I use iWebkit, which results in really nice and usable mobile applications. I hope to blog more about this in the near future.

Having fun Apexing

Saturday, 23 July 2011

Retaining session state with disabled items

This morning I was developing a page on which some input items could be prefilled from a Before Region Process and should be disabled if containing a value. After some Googling I soon found out that this could be accomplished by setting the disabled attribute.
And indeed, the items with a value appeared correctly with a gray background and non-enterable. But when I submitted the form, the value of the items appeared to be empty.

After half an hour of trying all kinds of things I, examining session state and going through the debug output, I finally found the solution:
- when an item is disabled it's value is set to empty...

So the solution was not to use the attribute disable, but the attribute readonly in combination with the style "background-color:#CCCCCC".

With this solution, the session state is retained.
Visually the result is the same, the only difference is that the cursor can be placed inside the item, but no changes to the content can be made.

Happy Apexing

Wednesday, 1 June 2011

User-controlled font size in Apex

In my current assignment I was requested to create a means for the user to control the font size in Apex, looking something like:

A A A


The font would have to change to the size of the A that was clicked on. This is meant to support people who have a hard time reading websites in the 'normal' font size.
The question can be broken down to two questions:
  • How can the font size be controlled?

  • How can it be controled within Apex


The first question is rather easy. The general font-size can be set using CSS. The entry ' * {font-size 12px; } sets the default font size to 12 px. This is overruled by more specific CSS entries like ' h1 { font-size: 15px; }'.
It is however possible to express the font size relative to the 'default' font-size. This is done by using the unit 'em', for example ' h1 { font-size:1.25em; }. This way the font size of the H1 elements is relative to the default font and changes accordingly when the default font is changed. So make sure all the font size in the CSS are expressed in em.


The second question took some more thinking. It is not so very hard to change a css property programmatically, when a button or link is clicked. But when a new page is rendered I want the change in font size to be persistent.
For this an Application Item G_FONT_SIZE is used. The following line is entered in a style section in the page template behind the CSS inclusions:

* { font-size:&G_FONT_SIZE.px; }

This makes sure that the ´default´ font size is set to the value in G_FONT_SIZE (make sure this item always has a value!).
To make this font size work for all the elements on your page make sure that the other font-size declarations are expressed in em's.

The biggest challenge is to change the value of G_FONT_SIZE once a font size is chosen. This means that the session state of Apex needs to be changed. I have given the use of Dynamic Actions a thought because it is very easy to change the session state by calling a PL/SQL process. But this would imply that I would have to create three items that I should put on Page Zero with Dynamic Actions etc... in other words a quite complex solution with lots of elements.
In the end I came up with a more simple solution with less 'moving' parts. Clicking on one of the font size selectors resends the URL to the browser with a request FONTSIZExx in which xx is the font size. So a request FONTSIZE18 will result in a font size of 18px. The request is handled by an Application Process, that fires OnLoad before Header on the PL/SQL condition v('REQUEST') like 'FONTSIZE%'.
The source of the Process is:

declare
l_request varchar2(250) := v('REQUEST');
lc_fontsize varchar2(100) := null;
ln_fontsize number;
begin
if l_request like 'FONTSIZE%' THEN
lc_fontsize := replace(l_request,'FONTSIZE');
begin
ln_fontsize := trunc(to_number(lc_fontsize));
if ln_fontsize between 5 and 100 then
:G_FONT_SIZE := ltrim(to_char(ln_fontsize))||'px';
end if;
exception
when others then null;
end;
end if;
end;

As you can see the script does not just sets the application item but is also checks whether the size is a valid number that is between 5 and 100.

The font size selectors link to:
f?p=&APP_ID.:&APP_PAGE_ID.:&APP_SESSION.:FONTSIZEfont size:&DEBUG.
in which the desired font size in pixels should replace font size.

Happy Apexing

Tuesday, 4 May 2010

Oracle and unicode characters. Part 1 Content length

In the application I am working on we came across the need to display non-latin characters. We needed to display both Russian and Chinese characters. The Oracle 10g R2 database is configured for UTF-8. Our application is built in Application Express 3.1. Our charts are generated by outputting SVG from PL/SQL. Also PowerPoint presentations are generated through a Java servlet using Apache POI. This servlet is called from PL/SQL.

The non-latin character should be shown in the Apex application, the SVG charts and the PowerPoint output. The Apex application turned out to be no problem. The other forms of output however have cost me a considerable amount of time to solve. During this quest I stumbled over several problems for which I could not easily find the answers using Google. This surprised me, I expected that more people would have had the same problems already.
But this gives me more reason to writes these posts adressing several problems I encountered.
This postwill deal with the content-length of a stream with multi byte from PL/SQL. The next post will discuss which font to use and how to use it. The last post will be about the XML encoding of UTF-8 characters from PL/SQL.

The database is configured for UTF-8 so there is no problem storing the characters in unicode. The data is delivered in UTF-8 files and these characters are loaded into the database using SQL*Loader without any problem.
Sometimes the data is delivered as an Excel file. Then the file can be opened in Excel and saved as Unicode Text. To edit the file we use the Notepad++ editor that supports UTF-8 very well. Do not forget to set the encoding to UTF8 without BOM before saving.

Application Express supports UTF-8 natively. No modification was needed to show the non-latin characters. However in our application we use SVG for charting and a Java servlet for generating PowerPoint presentations. These two have caused me some headaches and a few sleepless nights.

I will discuss the solution for the SVG chart in this post, the generation of the PowerPoint through a servlet will be the subject of my next post.

The SVG charting is coded in PL/SQL. The SVG is built in a CLOB that is output through the HTP package. In the XML header of the SVG the UTF-8 encoding should be specified:


<?xml version="1.0" encoding="utf-8"?>


The UTF-8 characters are added to the SVG without modification. When we generated the first charts with UTF-8 we got errors of incorrect XML. After a lot of searching it turned out that the wrong content length was specified in the download header. We used the value returned by the function DBMS_LOB.GETLENGTH. This function returns however the number of characters in a CLOB. The content-length in the download header should contain the number of bytes.
When all the characters are ASCII characters these numbers are equal. However all of the non-ASCII characters in UTF-8 use more than one byte per character. When there are mutli byte characters in the CLOB the length of the CLOB will be less than the number of characters so the browser will expect less bytes than the total length of the SVG hence it receives not well formed XML. A solution for this problem is to determine the length of the clob in bytes using the following function that utilises the function LENGTHB to determine the length in bytes of a varchar2.


function get_clob_length
( p_clob clob
) return number is
l_no_of_pieces number := null;
l_bufsize number := 2000;
l_string varchar2(10000) := null;
l_start number := 1;
l_length number := null;
l_amount number := null;
l_return number := 0;
begin
l_length := dbms_lob.getlength(p_clob);
l_no_of_pieces := trunc(l_length/l_bufsize) + sign(mod(l_length,l_bufsize));
for i in 1..l_no_of_pieces loop
l_amount := least(l_bufsize,l_length-l_start+1);
l_string := dbms_lob.substr(p_clob,l_amount,l_start);
l_return := l_return + lengthb(l_string);
l_start := l_start + l_bufsize;
end loop;
return(l_return);
end;

Using this function to determine the right value of content-length solved the problem of the not well formed XML. The SVG charts showed, with Russian characters! However, the Chinese characters showed as small squares. Read the next post to find out about the mystery of the missing Chinese characters.


Friday, 25 September 2009

Default value for check box in Application Express

High time to create a new post. Something not too complicated but which still took me some time to figure out. It surprised me that I did not find information on this subject, but maybe I did not look well enough ;-).
In a page I have made with Apex there is check box. The users want this check box to be checked by default. So the check box was created with a static LOV: STATIC2:;Y. To ensure that the check box was checked by default the default value 'Y' was entered.
This did not function as expected. When the check box was unchecked it returned checked after submitting the page. So the users could not uncheck the check box and so in fact it was useless because it always had but one state: checked.
What happens? When a check box is not checked, its value is not posted to the webserver. Because Apex gets no value for the check box item, it sets the value of this item to null. But when the value is null and a default value exists, the item should be set to the default value. Ergo, once checked, always checked.
Once I realised this the solution is quite simple:
  • create a hidden item Px_FIRST_TIME with no default value
  • create a pre-region process, that checks on the content of Px_FIRST_TIME. When the item value is null, it is the first time this page is called and the check box should be set to checked. Furthermore the Px_FIRST_TIME should receive a value to signal, that after this time it is not the call to this page (in this session).
Happy Apexing