dzMdbViewer 1.0.2 released

 Delphi  Comments Off on dzMdbViewer 1.0.2 released
Sep 302016
 

dzMdbViewer is a small tool I wrote, when I was stuck without a MS Access installation but needed to have a look into a .MDB file (and later .ACCDB file, if the Access Database Engine 2012 is installed).

It can open these files and display a list of queries and tables stored in them as well as the data they contain.

Table Data

Also, for tables, it can show the field definitions.

Table Definition

Today I added support for command line parameters, so it can be used as the default program for opening these kind of files. Download it from OSDN. The source code is available too. (I got tired of the inconveniences of Mercurial, so I moved this project to Subversion.)

 Posted by on 2016-09-30 at 17:29

First steps with REST and JSON

 Delphi  Comments Off on First steps with REST and JSON
Sep 252016
 

I must admit that I haven’t done much programming regarding the web. There was an attempt to write an RSS reader some time back and there is my virtual radio alarm clock (with which I’m currently listening to SWR3). But this is my first try to do something with REST and JSON. The server side is provided by the Delphi Dabbler SWAG archive the client is written with Delphi 10.1 Berlin.

At first I tried to make sense from the tutorial provided by Embarcadero but I found it rather confusing and it stops exactly when actually trying to access the data returned in a meaningful way.

So, I threw away the TRESTxxx components I had put on the form and went back to some actual programming rather than dropping components and setting properties without understanding what I am doing. Here is what I ended up with:

swagbrowser

The program itself consists of two parts: Requesting data from the server and interpreting its answers. Requests are sent via http using a TidHttp object which is dynamically created and destroyed for each request.

procedure Tf_DelphiDabblerSwag.doRequest(const _Command: string; out _Response: TJSONObject);
var
  HTTP: TIdHTTP;
  JSON: string;
begin
  HTTP := TIdHTTP.Create(nil);
  try
    JSON := HTTP.Get('http://swag.delphidabbler.com/api/v1/' + _Command);
//    m_Result.Lines.text := JSON;
  finally
    FreeAndNil(HTTP);
  end;
  _Response := TJSONObject.ParseJSONValue(JSON) as TJSONObject;
end;

It expects a Command which is simply sent to the server by appending it to the API url as described in the documentation.

It returns a TJSONObject which is then interpreted by the caller. (I don’t do much error handling here, it’s merely a learning experiment.)

The API is simple, it knows only 4 different commands:

  • categories
  • snippet
  • snippet-count
  • snippets

I implemented each of them as a method:

categories

procedure Tf_DelphiDabblerSwag.RequestCategories(_Categories: TObjectList<TIdTitleObj>);
var
  JObj: TJSONObject;
  JCategories: TJSONArray;
  i: Integer;
  JCategory: TJSONObject;
  Category: TIdTitleObj;
begin
  doRequest('categories', JObj);
  try
    m_Result.Lines.Add('status: ' + JObj.GetValue('status').Value);
    m_Result.Lines.Add('command: ' + JObj.GetValue('command').Value);
    JCategories := JObj.Get('categories').JsonValue as TJSONArray;
    for i := 0 to JCategories.Count - 1 do begin
      JCategory := JCategories.Items[i] as TJSONObject;
//        m_Result.Lines.Add(Format('Category: (ID: %s, Title: %s', [JCategory.GetValue('id').Value, JCategory.GetValue('title').Value]));
      Category := TIdTitleObj.Create(JCategory.GetValue('id').Value, JCategory.GetValue('title').Value);
      _Categories.Add(Category);
    end;
  finally
    FreeAndNil(JObj);
  end;
end;

The first thing the program does is getting a list of all categories. For that it sends the “category” command to the server and interprets its response.

{
  "status":"ok",
  "command":"categories",
  "categories":[
    {
      "id":"ANSI",
      "title":"ANSI Control & Ouput"
    },
    {
      "id":"ARCHIVES",
      "title":"Archive Handling"
    },

    ... more category elements ...

  ]
}

All categories are stored in a TObjectList and returned to the caller. It took me a while to figure out how to access the array of categories: You access a name value entry and type cast it to TJSONArray. After I understood that, everything else was easy.

snippets

Next is getting a list of all snippets of a category.

procedure Tf_DelphiDabblerSwag.RequestSnippets(const _CategoryId: string; _Snippets: TObjectList<TIdTitleObj>);
var
  JObj: TJSONObject;
  i: Integer;
  JSnippets: TJSONArray;
  JSnippet: TJSONObject;
  Snippet: TIdTitleObj;
begin
  _Snippets.Clear;
  doRequest('snippets/' + _CategoryId + '?fields=id,title', JObj);
  m_Result.Lines.Add('status: ' + JObj.GetValue('status').Value);
  m_Result.Lines.Add('command: ' + JObj.GetValue('command').Value);
  JSnippets := JObj.Get('snippets').JsonValue as TJSONArray;
  for i := 0 to JSnippets.Count - 1 do begin
    JSnippet := JSnippets.Items[i] as TJSONObject;
    Snippet := TIdTitleObj.Create(JSnippet.GetValue('id').Value, JSnippet.GetValue('title').Value);
//    m_Result.Lines.Add(Format('Snippet: (ID: %s, Title: %s', [JSnippet.GetValue('id').Value, JSnippet.GetValue('title').Value]));
    _Snippets.Add(Snippet);
  end;
end;

The “snippets” command needs a some parameters:

  • The id of the category
  • The fields we are interested in

They are appended to the command.

Then again, we simply parse the result and return it in a TObjectList.

{
  "status":"ok",
  "command":"snippets",
  "snippets":[
    {
      "id":491,
      "title":"Getting the Line number in a memo Field",
    },
    {
      "id":492,
      "title":"Capturing the Desktop to a form",
    },
    {
      "id":493,
      "title":"File Copying in DELPHI",
    },{
      "id":494,
      "title":"File Manager Drag\/Drop",
    }
  ]
}

snippet

The last part is getting a snippet’s text.

procedure Tf_DelphiDabblerSwag.RequestSnippetText(const _SnippetId: string; out _Text: string);
var
  JObj: TJSONObject;
  JSnippet: TJSONObject;
begin
  doRequest('snippet/' + _SnippetId + '?fields=source_code', JObj);
  try
    m_Result.Lines.Add('status: ' + JObj.GetValue('status').Value);
    m_Result.Lines.Add('command: ' + JObj.GetValue('command').Value);
    JSnippet := JObj.GetValue('snippet') as TJSONObject;
    m_Snippet.Lines.Text := JSnippet.GetValue('source_code').Value;
  finally
    FreeAndNil(JObj);
  end;
end;

The “snippet” command requires a snipped id and we also must specify the fields we want to get. In this case we only want the source_code.

{
  "status":"ok",
  "command":"snippet",
  "snippet":{
    "source_code":"\r\n{This way uses a File stream.}\r\nProcedure ..."
  }
}

The response is then parsed and returned as a string. Note that “snippet” is an object, so in order to get the source code we need to type cast the snippet value to a TJSONObject before we can access its source_code value.

That’s about it. The rest of the program is a few event handlers that call the methods described above and fill the result into the GUI. I won’t get into that, it’s boring.

The source code is available for download here and in case you simply want to browse the SWAG archive using that program, there is also a precompiled executable

As I already said in the title: These are my first steps. I’m pretty satisfied with the result, but I’m sure I made some mistakes and there are probably easier ways to implement this.

 Posted by on 2016-09-25 at 17:52

Hotfix for GExperts crashing with Delphi 10.1 update 1

 Delphi, GExperts  Comments Off on Hotfix for GExperts crashing with Delphi 10.1 update 1
Sep 242016
 

GExperts 1.38 experimental twm 2016-09-18 has a few issues with Delphi / Rad Studio 10.1 Berlin Update 1. Simply recompiling the DLL made them go away for me, so I provide the recompiled DLL as a hotfix for this release. Go the release page to get it.

 Posted by on 2016-09-24 at 20:06

GExperts 1.38 experimental twm 2016-09-18 released

 Delphi, GExperts  Comments Off on GExperts 1.38 experimental twm 2016-09-18 released
Sep 182016
 

Since apparently Erik needs more time for the official GExperts 1.39 release, here is another experimental test release. Please report any bugs you may find (preferentially in the GExperts community on Google+ or the bug tracker on SourceForge)

Again, I have built installers for each Delphi version. These installers should install everything that is necessary, including the files for the Code Formatter.

Apart from several bugfixes I have added three new experts:

  • There is the Warn Directives Expert which allows you to select a warn directive like SYMBOL_PLATFORM and insert it as {$WARN SYMBOL_PLATFORM OFF}, {$WARN SYMBOL_PLATFORM ON}, {$WARN SYMBOL_PLATFORM DEFAULT} or {$WARN SYMBOL_PLATFORM ERROR}.
  • Then there is the IfDEF Expert which alows you to insert various IFDEF, IF or IFOPT directives. It automatically scans for include files in the current unit and offers the conditional defines from there as well. You can also add another include file from the search path and if you add directives for conditional defines from it, the expert will automatically add an {$I <filename>} directive to the unit.
  • And last but not least there is the Add to Formatter Capitalization Expert which allows you to add the current identifier to the code formatter’s captitalization file without clicking your way through the various configuration dialog levels.

GExperts IFDEF Expert

Head over to the Experimental GExperts page to download it.

 Posted by on 2016-09-18 at 18:14

GExperts IFDEF Expert support for include files

 Delphi, GExperts  Comments Off on GExperts IFDEF Expert support for include files
Sep 162016
 

The GExperts IFDEF expert now supports include files.

GExperts IFDEF Expert

For each include file in the current unit it displays an additional tab containing all symbols defined in that include file with {$DEFINE }, {$UNDEF } and the usual disabled notation of these {.$DEFINE }, {.$UNDEF }. It searches for the include files in the search path of the project and – like the compiler – uses the first one it finds.

 Posted by on 2016-09-16 at 23:30