Thursday, November 29, 2012

Uncle once more!


The last few weeks haven't been too good on a personal level; I seem to develop a dull headache on a daily basis, and the hour that the headache starts seems to be earlier every day. Coincidentally, I was asked to monitor my blood pressure a few days before the headaches started, and the high levels that I am seeing may have something to do with the headaches. Acupuncture helps relieve the ache but only for a few hours at most. My family doctor can be very elusive: I was supposed to see him today but now will only see him on Tuesday.

But there is good news - my sister in law gave birth to twins (a boy and a girl) two days ago! Here is a picture of the girl who weighed about 2.8 kg at birth. So far she hasn't shown much

enthusiasm for eating but hopefully that will change shortly. Her brother weighed only 1.9kg at birth and is currently with the premature/under-weight babies, although he's not in an incubator.

This is the sister-in-law which I wrote about five years ago when she gave birth for the first time to a premature baby who died after a week. The odds seem much better this time around! In the mean time, she has also married my brother in law (my wife's brother).

Sunday, November 18, 2012

Warming up for DBA exam

I see that I've hardly written anything about the first course in the DBA degree - Introduction to Business Research 1. This course gives an introduction to the structure of the doctoral degree then concentrates on the first piece of work that the candidate (we are no longer students!) has to produce - the research proposal. Chapters in the course discuss the background of the proposal (including a very interesting chapter on the philosophy of research), culminating in a chapter on the structure of the research proposal itself.

I had been reading the course material with great interest, always considering how the material applies to my chosen area (what is my research question? what are my hypotheses?). But as there are only six chapters to read, I found that I had read the whole course twice two months before the exam. As a result, I almost totally ignored the course for a month. A week ago, I awoke with a start and realised that soon I am to be examined on this material. It's time to get hard core.

The most important thought which I had a few days ago was that I am not to be examined on my research proposal but rather on how well I have learned the course: two completely different things. My first step, then, was to download a few previous exams and check both the examiners' solutions and selected students' solutions. After reading a few of these, I went back in time to the final stages of the Strategic Planning course, in which the lecturer would hand us an old exam and ask us for the solution, which was according to a template that he devised.

After examining a few papers, it became clear that the exam always consists of three questions: the first (50%) presents a research proposal and the examinee is to critique it. The other two questions (25% each) require essays on subjects such as research methodology, philosophy and time planning. The research proposal question can be answered by creating a template and then following it; the proposal consists of fourteen different sections (abstract, research question, research methodology, timetable, ethics, deliverables et al.) and most of these sections have a pre-defined structure. Thus it should be fairly easy to deliver a critique after memorising which points should be referenced in which section (the ethics, deliverables and appendix sections are particularly easy).

I spent most of my study time yesterday creating such a template and then answering - writing out in full - one such exam question according to the template. I intend to answer a few more questions in the next few days in order to fix the template in my mind. Writing the answer out in full hand is a very important aid to fixing the answer; I very rarely write anything by hand these days and certainly not two page essays. As opposed to the MBA courses, I don't attend lectures and write notes on the coursework, so at the moment I have no muscle memory; I consider this to be very important.

When I need some variety, I will look at the other questions in the exams and try to prepare answers in advance - for example, the course text devotes a few pages to the advantages and disadvantages of the positivism and phenomenology approaches (I will have to practice writing phenomenology and methodology!) and I imagine that there will be a need to discuss them at some point in the exam.

That said, there are some subjects which seem fairly obvious: I am sure that I could write a competent essay about time planning (Gantt charts, etc) without having to read the material again; I did achieve a high mark in Project Management, after all!

Thursday, November 15, 2012

Inside the DOCU program (3) - Saving screenshots

Whilst discussing the DOCU program last week, the Occupational Psychologist asked why she can't store screenshots along with the written documentation. I wasn't about to tell her that the program was implemented with a RichEdit component, which implies very strongly that only rich text can be saved, so I said that I would consider the options.

The simple part of the option which I found was to add a field in the database of 'blob' type; such a field can store anything as a sequence of bytes. Theoretically I know how to display jpg images stored in a database as one of our programs displays images, and even more theoretically I know how to save such an image into the database.

The solution actually required several items
  • adding a blob field to the database
  • learning how to save an image from the clipboard to a picture component in Delphi
  • saving that picture to the database
  • clearing a picture from the database
  • loading the contents of a blob field to a picture
  • creating a suitable form from the 'entry' form and closing it appropriately
From the outset, I decided that each entry in the database could have only one picture assigned to it; otherwise this would add complexity (Should the user choose which picture to display? Should all pictures be displayed for this entry? How to manage the pictures?). Thus I was able to add one icon to the toolbar (see yesterday's blog) instead of having to add an image choosing dialog.

My logic was as follows: if the entry has an assigned picture, then open a son form and display the picture. Otherwise, open a son form, copy into it whatever graphic is in the clipboard's memory, display it and save it to the database. There also should be an option to clear the picture in case a wrong graphic was saved.

Here's the code which does all of the above.


Procedure TDoPicture.Execute (const s: string; aleft, atop: longint);
var
 empty: boolean;
 bmp: TBitmap;
 ms: TMemoryStream;
 j: TJPEGImage;

begin
 caption:= s;
 left:= aleft;
 top:= atop;
 with qGetPicture do
  begin
   params[0].asinteger:= myentry;
   open;
   empty:= isempty;
   if not empty then
    begin
     j:= TJPEGImage.Create;
     try
      j.Assign (qGetPicturePIC);
      OnAssign (j)
     finally
      j.Free;
     end;
    end;
   close
  end;

 if empty and Clipboard.HasFormat (CF_PICTURE) then
  begin
   bmp:= TBitmap.Create;
   j:= TJPEGImage.Create;
   try
    bmp.Assign (Clipboard);
    j.Assign (bmp);
    OnAssign (j);
   finally
    bmp.Free;
    j.free
   end;

   ms:= TMemoryStream.Create;
   try
    Image1.Picture.Graphic.SaveToStream (ms);
    ms.Position:= 0;
    with qSavePicture do
     begin
      parambyname ('p1').asinteger:= myentry;
      ParamByName('p2').LoadFromStream (ms, ftGraphic);
      execsql
     end;
   finally
    ms.Free;
   end
  end;
 show
end;

procedure TDoPicture.OnAssign (j: TJPEGImage);
begin
 Image1.picture.assign (j);
 image1.autosize:= true;
 // resize the form to be slightly larger than the stored image
 width:= image1.Width + 16;
 height:= image1.Height + 48;
end;
Looking at the above now, it all seems so obvious, but it wasn't when I was writing the program! Taking it bit by bit:
  • the first few lines are concerned with setting up the form with the correct caption; the form is placed at the same height and to the right of the calling form
  • a query is then opened which checks whether there is an assigned picture. If the query is empty, then the 'empty' variable becomes true. If not empty, then the next few lines show how to read a blob from the database, store it in a temporary variable and then cause the blob to be displayed as a jpg image. The 'OnAssign' procedure resizes the form to be slightly larger than the image.
  • If there is no assigned picture, then the program checks to see whether the clipboard holds graphic data. If so, the image is first saved in a temporary bitmap (bmp) and then converted into jpg format, which is then displayed. Afterwards, the image is saved to the database, an action which requires the use of a stream.
As I wanted to have the user interface as simple as possible (ie no user interface at all), I was stumped at first how I was going to allow the user to remove the stored graphic. Then I remembered that I have been using the system menu frequently for such actions; the code became very simple to write.
At the beginning of the form, the following adds an option to the system menu
const
 SC_Original = WM_USER + 2;

procedure TDoPicture.FormCreate (Sender: TObject);
var
 SysMenu: HMenu;

begin
 SysMenu:= GetSystemMenu (Handle, FALSE);
 AppendMenu (SysMenu, MF_STRING, SC_Original, 'Clear picture');
end;

And this is how a click on that menu option is handled

procedure TDoPicture.WMSysCommand (var Msg: TWMSysCommand);
begin
 if Msg.CmdType = SC_Original then
  begin
   qClear.params[0].asinteger:= myentry;
   qClear.ExecSQL;
   image1.picture:= nil;
   close
  end
 else inherited;
end;
In an MDI application, the program 'knows' about its child forms because they are 'stored' in the MDIChildren array. As DOCU is not an MDI program, another solution is required; Delphi stores all on screen forms in the 'forms' property of the 'screen' variable. So closing the picture form when its parent form is closed requires the following code
 for i:= 1 to screen.FormCount do
  if screen.forms[i-1] is TDoPicture
   then if TDoPicture (screen.forms[i-1]).myentry = entry
    then screen.forms[i-1].close;
Here's a pretty useless screenshot of an entry form along with its graphic; what would seem to be WinAmp playing in a window is actually a screenshot of WinAmp captured and stored in Docu.

Inside the DOCU program (2) - saving and loading rich text

Yesterday I discussed the gross structure of the DOCU program; today I am going to concentrate on the 'entry' form.
Originally, the form contained a dbMemo component whose font was fixed at compile time. Obviously at some stage I received a request to change the component so that coloured and or bolded text could be stored. The dbMemo component doesn't allow this but the dbRichEdit component does. Fortunately for me, one of the demo programs which comes with Delphi is an editor based around a rich edit component, so I was able to extract from this demo most of the necessary interface code. With the use of the tool buttons, the user is able to choose type face, font size, bolding, italics, underlining and colour as well as numeration.

If everything were as easy as this, then I would be out of a job. The problems began when I wrote the code to store the text in the database; when the saved text was restored from the database, all the richness (ie fonts and colours) had been lost!

The answer is to be found here; unfortunately, there is no real explanation of why the code succeeds whereas the naive code fails. 

For loading the rtf text:

//Get the data from the database as AnsiString
rtfString:= sql.FieldByName ('rtftext').AsAnsiString;

//Write the string into a stream
stream:= TMemoryStream.Create;
stream.Clear;
stream.Write (PAnsiChar(rtfString)^, Length(rtfString));
stream.Position:= 0;

//Load the stream into the RichEdit
RichEdit.PlainText:= False;
RichEdit.Lines.LoadFromStream (stream);

stream.Free;

For saving the rtf text:
//Save to stream
stream:= TMemoryStream.Create;

stream.Clear;

RichEdit.Lines.SaveToStream (stream);
stream.Position:= 0;

//Read from the stream into an AnsiString (rtfString)
if (stream.Size >= 0) then
 begin
   SetLength(rtfString, stream.Size);
   if (stream.Read(rtfString[1], stream.Size) <= 0) then
   raise EStreamError.CreateFmt('End of stream reached with %d bytes left to read.', [stream.Size]);
end;

stream.Free;

//Save to database
sql.FieldByName('rtftext').AsAnsiString := rtfString;

Wednesday, November 14, 2012

Inside the DOCU program (1)

I haven't abandoned this blog; I've simply been going through a few weeks of nothing much interesting happening so there's been little to write about. Over the weekend, I added an interesting twist to an existing program of mine, so I've going to devote a few blog entries to this program.

A year or so ago, the Occupational Psychologist (OP) with whom I work and I had a discussion about program documentation, probably after she asked for some feature and I had told her that I had already added that feature and explained to her how it worked (this happened again a few weeks ago when I was asked to add a feature which I had added in March). Out of this discussion was born the DOCU (as in documentation) program.

From a bottom up point of view, this program can store 'entries' which are connected to 'subjects' which are connected to 'programs'. From the top down point of view, a program - such as the management program - might have several subjects (such as customer calls), and each subject can have several entries (printing the text of a call, creating a linked call, etc). The main form of the program is simply a dialog box with three different grids (one grid per table) which are of course synchronised. There is nothing revolutionary about this so far.

The first interesting twist in the program came as an attempt to find a solution which utilised the Stack Overflow gurus' dislike of MDI programs (such as the management program). It turns out that this was simpler than I had expected. Whilst the main program has two modal sub-forms (one for adding programs to the database and one for adding subjects; under the hood, they're the same form), the 'add entry' form is non-modal. This means that any number of such forms can be displayed on the screen at the same time, when each form can be derived from a different subject. The main form's size is fixed (because it is built on three grids); had I used MDI, then the 'add entry' forms would have been constrained to the area of the main window (which in practical terms means that the main window has to be maximised). Using a non-MDI main form, the non-modal 'add entry' forms can appear anywhere on the screen.

As per the maxim that one picture is worth a thousand words, here is a compressed screenshot of my computer screen with the program running and three 'add entry' forms displayed. As most readers won't be able to read Hebrew, it may be difficult to recognise which is the main form and which are the child forms; the form with three grids is the main form.