Quantcast
Viewing all 1008 articles
Browse latest View live

My Top 10 Aurelius Features - #8 Lazy Loading

The ability to lazy-load an association is placed at number 8 in the list of My Top 10 Aurelius Features.


Suppose you have a TContact class like the following:

type
  TContact = class
  private
    FId: integer;
    FName: string;
    FCountry: TCountry;
  public
    property Id: integer read FId write FId;
    property Name: string read FName write FName;
    property Country: TCountry read FCountry write FCountry;
  end;
And you use the following code to retrieve a list of contacts and get the name of the country of the first contact (to reduce size, the code doesn't check for potential errors or release memory):
// Get all contacts
MyContacts := Manager.Find<TContact>.List;

// Get name of country of first contact:
FirstContactCountryName := MyContacts[0].Country.Name;
By default, when the first line is executed, Aurelius builds and executes an SQL statement retrieving column values from Contact table and Country table, all at once, and all entities (contacts and countries) are created and instantiated:
SELECT A.ID AS A_ID, A.NAME AS A_NAME, A.COUNTRY_ID AS A_COUNTRY_ID, B.ID AS B_ID, B.NAME AS B_NAME
FROM CONTACT A LEFT JOIN COUNTRY B ON (B.ID = A.COUNTRY_ID)
When the second line is executed (when we retrieve the Country name), all data is already in memory. This is useful in many situations, but there might be cases where doing several LEFT JOIN for many associations and retrieving data for all records is not desired. If I'm not going to get the country name for all contacts I retrieve, for example, why would I want to retrieve all country names in advance?

The lazy-loading feature gives you that flexibility. You just reimplement your class using a special Proxy type:
type
  TContact = class
  private
    FId: integer;
    FName: string;
    FCountry: Proxy<TCountry>;
    function GetCountry: TCountry;
    procedure SetCountry(const Value: TCountry);
  public
    property Id: integer read FId write FId;
    property Name: string read FName write FName;
    property Country: TCountry read GetCountry write SetCountry;
  end;

function TContact.GetCountry: TCountry;
begin
  Result := FCountry.Value;
end;

procedure TContact.SetCountry(const Value: TCountry);
begin
  FCountry.Value := Value;
end;
If we execute the code that retrieve contacts again, this is the SQL executed by Aurelius:
SELECT A.ID AS A_ID, A.NAME AS A_NAME, A.COUNTRY_ID AS A_COUNTRY_ID 
FROM CONTACT A
No data from country was retrieved. Only when the second line is executed, Aurelius executes an extra SQL statement:
SELECT A.ID AS A_ID, A.NAME AS A_NAME
FROM COUNTRY A
and then the country object is populated. Now you have the two options and you can fine tune your application for the best situation. It's also worth note that even when you have mapped your class to lazy-load a specific association, in some queries you can force Aurelius to still load all objects at once. The following code will use LEFT JOIN and retrieve all countries in the same SQL statement:
// Get all contacts and countries at once,
// regardless of lazy-load mode in mapping
MyContacts := Manager.Find<TContact>
  .CreateAlias('Country', 'c', TFetchMode.Eager)
  .List;

// Get name of country of first contact:
FirstContactCountryName := MyContacts[0].Country.Name;
Don't forget to subscribe to our YouTube channel and receive notifications about upcoming videos!



Generating PDF files cross-platform with ease

With the new 1.7 release of the TMS FNC UI Pack we've added a completely new PDF library built from the ground up, that is capable of generating PDF files on all supported frameworks (FMX, VCL, LCL). Via all supported frameworks, you can easily target minimum 5 different operating systems: Windows, macOS, iOS, Android, Linux (&Raspbian),.. To introduce this new PDF library I've written a small tutorial to start generating your own PDF files.

Getting Started

To get started with the PDF library, add the FMX.TMSFNCPDFLib, VCL.TMSFNCPDFLib or LCLTMSFNCPDFLib depending on the chosen framework. The PDF library class is called TTMSFNCPDFLib, and the code is shareable between the three supported frameworks.

Starting a new document

Starting a new document can be file-based, or TMemoryStream-based. To start a new document, call the BeginDocument function. The BeginDocument always needs to be paired with EndDocument, which is responsible for writing the contents to a file or TMemoryStream. When the AFileName parameter in the BeginDocument call is empty, the contents will be written to a TMemoryStream, returned by the EndDocument call. The EndDocument call also has an additional parameter to allow opening the generated PDF file in the default PDF reader application.

procedure TForm1.GeneratePDF(AFileName: string);
var
  p: TTMSFNCPDFLib;
begin
  p := TTMSFNCPDFLib.Create;
  try
    p.BeginDocument(AFileName);
    p.EndDocument;
  finally
    p.Free;
  end;
end;

Adding pages

Adding pages can be done by calling the NewPage function. The NewPage is responsible for starting a new page content stream on which the graphics / text can be written. Each NewPage call will clear the content buffer and allow you to start with new text and graphics. Please note though that all appearance settings such as fill, stroke and font are stored for the entire document, so starting a new page will allow you to continue in the same appearance settings as the previous page.

procedure TForm1.GeneratePDF(AFileName: string);
var
  p: TTMSFNCPDFLib;
begin
  p := TTMSFNCPDFLib.Create;
  try
    p.BeginDocument(AFileName);
    p.NewPage;
    p.EndDocument;
  finally
    p.Free;
  end;
end;

Drawing content on a page

After adding a new page, the page can be filled with content such as HTML formatted text, plain text as well as some basic drawing primitives such as rectangles, circles and lines. To starting drawing content, the pdf library has a Graphics property that provides access to the drawing functionality. The following sample uses the Fill and Stroke properties to generate a PDF with a gradient rectangle and a dotted border.
procedure TForm1.GeneratePDF(AFileName: string);
var
  p: TTMSFNCPDFLib;
begin
  p := TTMSFNCPDFLib.Create;
  try
    p.BeginDocument(AFileName);
    p.NewPage;
    p.Graphics.Stroke.Color := gcRed;
    p.Graphics.Stroke.Width := 3;
    p.Graphics.Stroke.Kind := gskDashDotDot;
    p.Graphics.Fill.Kind := gfkGradient;
    p.Graphics.Fill.Color := gcBlue;
    p.Graphics.Fill.ColorTo := gcOrange;
    p.Graphics.DrawRectangle(RectF(10, 50, 100, 150));
    p.EndDocument(True);
  finally
    p.Free;
  end;
end;

Image may be NSFW.
Clik here to view.

Drawing Text

Drawing text on a PDF page is done via the DrawText function. The DrawText has a set of parameters to allow drawing wordwrapped text in a rectangle, or simply as-is at a specific position. The DrawText function has a set of overloads that also supports column drawing. Each call to DrawText returns a value that can either contain the calculated text rectangle or the amount of left-over characters after an overflow is detected when drawing text in a column. The font that is used when drawing text can be controlled separately via the Font property. With this property, the font name, size, color and style can be set.
procedure TForm1.GeneratePDF(AFileName: string);
var
    p: TTMSFNCPDFLib;
begin
    p := TTMSFNCPDFLib.Create;
  try
    p.BeginDocument(AFileName);
    p.NewPage;
    p.Graphics.Font.Name := 'Segoe UI';
    p.Graphics.Font.Size := 16;
    p.Graphics.Font.Color := gcRed;
    p.Graphics.Font.Style := [TFontStyle.fsBold];
    p.Graphics.DrawText('Hello World !', PointF(10, 50));
    p.EndDocument(True);
  finally
    p.Free;
  end;
end;

Image may be NSFW.
Clik here to view.

HTML formatted text

HTML formatted text is also supported by using the DrawHTMLText call. When passing a TMSFNCBitmapContainer reference it can even draw images referenced by the <IMG> tag. HTML support is based on the miniHTML reference.
procedure TForm1.GeneratePDF(AFileName: string);
var
  p: TTMSFNCPDFLib;
  s: string;
  r: TRectF;
begin
  p := TTMSFNCPDFLib.Create;
  try
    s := 'Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum     has been the industry''s standard dummy'+
'text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. '+
'It has survived not only five centuries, but also the leap into electronic typeset'+
'ting, 
Image may be NSFW.
Clik here to view.
remaining essentially unchanged. It'+ ' was popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with des'+ 'ktop publishing software like Aldus PageMaker including versions of Lorem Ipsum.'; p.BitmapContainer := TMSFNCBitmapContainer1; p.BeginDocument(AFileName); p.NewPage; p.Graphics.Font.Name := 'Arial'; p.Graphics.Font.Size := 10; p.Graphics.Fill.Color := gcNull; r := RectF(10, 50, 300, 400); p.Graphics.DrawHTMLText(s, r); p.EndDocument(True); finally p.Free; end; end;

Image may be NSFW.
Clik here to view.

The PDF library supports more than simple text and graphics. More information on the PDF library and the features can be found at the following page http://www.tmssoftware.com/site/tmsfncuipack.asp?s=fncpdf#features.

The PDF library is also available in the TMS FMX UI Pack and is coming to the TMS Component Pack at the beginning of 2017!

My Top 10 Aurelius Features - #7 Schema Update

When creating a database-based application, one of the tasks I always considered boring was to create the database structure, table, fields, foreign keys. Even using a tool to generate a SQL would require me to create a table, add columns, column types, foreign keys, etc.

That's why I consider the ability to automatically create and update the database schema to be the #7 feature of My Top 10 Aurelius Features. It's simply something I don't need to care about anymore.



Updating the database is as easy as doing this:

TDatabaseManager.Update(Connection);
That simple command will check the existing schema in the database and create the missing objects needed to persist all the objects you are dealing with: new tables, columns, foreign keys.

Note that I'm talking about updating, not creating the database. That makes application prototyping and development really fast. Create the database, change your application, add a new table, update the database, and it goes on.

Even though updating the database is as simple as using one line of code, Aurelius provides advanced features for the database update process, like validation. With a code like the following, you can check the differences between the schema of the existing database, and what is needed in the schema to hold the current entity model you have. It shows you the differences without requiring you to actually execute the SQL statements:
procedure TForm1.ValidateMyDatabaseSchema;
var
  DBManager: TDatabaseManager;
  Action: TSchemaAction;
  Warning: TSchemaWarning;
  Error: TSchemaError;
begin
  DBManager := TDatabaseManager.Create(Connection);
  try
    DBManager.ValidateDatabase;

    { Show SQL statements }
    mmStatements.Clear;
    for Statement in DBManager.SQLStatements do
    begin
      mmStatements.Lines.Add(Statement);
      mmStatements.Lines.Add('');
    end;

    { Show validation results }
    mmValidation.Clear;

    mmValidation.Lines.Add('----- Actions -----');
    for Action in DBManager.Actions do
      mmValidation.Lines.Add(Format('%s -> %s', [Action.ClassName, Action.Text]));
    mmValidation.Lines.Add('');

    mmValidation.Lines.Add('----- Warnings -----');
    for Warning in DBManager.Warnings do
      mmValidation.Lines.Add(Format('%s: %s', [Warning.ClassName, Warning.Text]));
    mmValidation.Lines.Add('');

    mmValidation.Lines.Add('----- Errors -----');
    for Error in DBManager.Errors do
      mmValidation.Lines.Add(Format('%s: %s', [Error.ClassName, Error.Text]));
  finally
    DBManager.Free;
  end;
end;
Please watch the video (closed captions available!) to see how schema update and validate in action. As usual, don't forget to subscribe to our YouTube channel and receive notifications about upcoming videos!

TMS Cryptography Pack 2016 Bug List and Feature Requests

To begin 2017, here is an update on TMS Cryptography Pack, that has now been available for six months. We received several bug reports and requests for new features that are listed in the Excel spreadsheet in the link.

The good news is that no bug related to one of the cryptographic engines was reported and that we only found a single pure cryptographic bug. This bug was identified in the SPECK 24 bit mode and escaped our detection because the test program returned " true " independently from the test result of this mode. Hopefully no user was impacted.

There is one critical bug left for users who don't want to use or ship VCRuntime140.dll required for Windows 64 bit applications. This requirement is due to the use of Visual Studio C++ to generate the object files for Windows 64 as Embarcadero doesn't provide the required object format to interoperate with Pascal Object code. A bug report has been sent to Embarcadero.

There are 4 feature requests that we will address in the upcoming releases of TMS CP. They are:
- ASN.1 (BER, DER, CER, OER encodings)
- XADES/CADES/PADES signatures
- Unicode support for file names
- Stream operations support

We are always open to new suggestions.

My Top 10 Aurelius Features - #6 Legacy Databases

The video series "My Top 10 Aurelius Features" continues. The #6 feature is the support for Legacy Databases, and the following video shows it in action. English and Portuguese subtitles available!



In my opinion, TMS Aurelius will be very limited if it required a very strict database schema/structure. It would be great for creating prototypes and new applications from scratch, but a no-no for existing applications and databases - and we all know that in Delphi world, what we have most is existing and legacy applications!

That's why Aurelius provides an extensive list of mapping attributes that makes it compatible with virtually any existing database structure you might have. Attributes like

Id
Allows you to use databases with different primary key, like GUID, String, UUID, or even Composite Id's

Column and JoinColumn
Allows you to specify how one table relates to another (foreign keys) even if it doesn't reference a primary key in parent table (an unique index might be used).

Those are just small examples. And the best part is that you don't need to map it yourself. You can use the TMS Data Modeler tool to import an existing database structure and generate all the mapping for you!

Please watch the video for more details and to see TMS Data Modeler source code generation in action.

As usual, don't forget to subscribe to our YouTube channel and receive notifications about upcoming videos!

TMS Component Pack v8.5 released with wave of new components

We have given up thinking that the TMS Component Pack will ever be complete. It is simple: It will never be complete! On a daily basis, we're in conversation with developers around the planet with interesting, useful and cool new ideas. Between waking up and going to sleep, we ponder all the time how to improve components, how to make developers write less code and do more, to design new controls for bringing functionalities that don't exist out of the box in Delphi & C++Builder. And yes, some nights while sleeping, we also dream about new cool stuff to do.
As we've now just released and reached a new milestone with TMS Component Pack v8.5, it's good to take a moment and bring to the attention all the new goodies that are packed in the new release, so, sit back, hold tight, here we go with the list:

New: TDBAdvSearchList
DB-aware version of the TAdvSearchList component
The TDBAdvSearchList is a DB-aware of TAdvSearchList. This means that the data in the list in the different columns can be automatically filled from a connected dataset via a datasource. Set TDBAdvSearchList.DataSource and DBAdvSearchList.Columns[x].DataField to specify binding of values in the columns of the list. When the DB field bound to a column is of the type TBlobFiled, the list control will try load the blob data as a picture.
Image may be NSFW.
Clik here to view.


New: TDBAdvSearchEdit
DB-aware version of the TAdvSearchEdit component
The TDBAdvSearchEdit is DB-aware version of the TAdvSearchEdit with respect to the value as well as with respect to the list of values. Set TDBAdvSearchEdit.DataSource and TDBAdvSearchEdit.DataField to define the DB-awareness of the value and use TDBAdvSearchEdit.ListSource in combination with TDBAdvSearchEdit.Columns[x].DataField to specify binding of values in the columns of the list.
Image may be NSFW.
Clik here to view.


New: TDBAdvResponsiveList
DB-aware version of the TAdvResponsiveList component
The TDBAdvResponsiveList is a DB-aware version of the TAdvResponsiveList. Header, content and footer of responsive list items can be loaded automatically from a dataset connected via a datasource. Set the datasource via TDBAdvResponsiveList.DataSource. The binding of values to items is done via item templates. The template placeholders are defined as (#FIELDNAME) and are dynamically rendered when the dataset is activated. Memo fields can be used as well as picture blob fields. For picture blob fields, specify the template value to render as picture as:

<IMG src="(#BLOBFIELDNAME)">

Image may be NSFW.
Clik here to view.



New: TAdvPDFLib
Standalone PDF library to generate PDF files easily on-the-fly.
Library that features PDF file generation with text, formatted text, rectangles, lines, polygons, images, ... header, footer access and custom drawing.


Image may be NSFW.
Clik here to view.

There is a new developers guide specifically covering the new PDF generation library.
This is also the library that is used under the hood to do out of the box PDF generation from our grids, richeditor, planner, memo!

New: TAdvPDFImageBook
Class that can on-the-fly generate PDF files from a list of images

TAdvResponsiveList
- New: HeaderTemplate capability added
Now also for the item header, a template can be specified. The template placeholders are just like for the content specified as (#VALUENAME). The template is rendered by using the TResponsiveListItem.Values['VALUENAME'] value and have specifiers like (#VALUENAME) replaced by these values.
- New: FooterTemplate capability added
Same as the header template but for the optional footer of the item
- New: Appearance.ItemContentMargin added
New property to specify the margin from left/right and top/bottom of the content with respect to the outline of the item.
- New: Filter capability
Items in the TAdvResponsiveList can now be easily filtered. The filter condition is set via TAdvResponsiveList.FilterCondition. Following properties are available:
FilterCondition.CaseSensitive: Boolean : when true, a case-sensitive match is performed

FilterCondition.FilterData: TResponsiveListItemFilterDataSet : defines on what data to filter : the header, the content or the footer.

TResponsiveListItemFilterData = (fdContent, fdHeader, fdFooter);
TResponsiveListItemFilterDataSet = set of TResponsiveListItemFilterData;

FilterCondition.FilterType: TResponsiveListItemFilterType : defines what match method to use:

TResponsiveListItemFilterType = (mText, mEntireWord, mStartWord, mEndWord);

mText: match of any part of the text
mEntireWord: match of text respecting word boundaries
mStartWord: match must be at start of a word
mEndWord: match must be at end of a word
FilterCondition.Text : string : holds the text to perform a match against
The filter operation is started by setting the filter condition and then call:

TAdvResponsiveList.UpdateFilter;

The filter operation is cancelled by calling:

TAdvResponsiveList.ClearFilter;

In addition to the filter condition, an event OnItemFilter() is also triggered for each item's filter match check and as such, via this event also custom filtering can be implemented. When this event is triggered, set the var parameter Retain to TRUE if the item needs to remain in the list after filtering.


TAdvDirectoryTreeView
- New: SortOrder: TAdvDirectoryTreeViewSortOrder to set sorting order to files first, folders first
TAdvDirectoryTreeViewSortOrder = (tvsoNone, tvsoFilesFirst, tvsoDirectoriesFirst);
Defines whether to display first files in the treeview, first directories or use the default order of returned files and directories by the shell.
- New: SystemContextMenu: Boolean;
When this property is true, the property shell context menu will be shown on right-click of a file/folder in the treeview.
Image may be NSFW.
Clik here to view.



TAdvGauge
- New: ExtraNeedles: TNeedleItems
This is an extra collection to add as many needles as desired to the gauge. The collection consists of TNeedleItem objects via which the needle color, position and width can be set.

Example:

var
  it: TNeedleItem;
  I: Integer;
begin
  for I := 0 to 10 do
  begin
    it := AdvGauge1.ExtraNeedles.Add;
    it.Position := i * 10;
    if odd(i) then
      it.Color := clLime
    else
      it.Color := clAqua;
  end;
end;
Image may be NSFW.
Clik here to view.


These are the bigger items that are new in TMS Component Pack v8.5, there are numerous smaller items and bug fixes that you can find in the full version history.
Enjoy the amazing array of functionality that is in the TMS Component Pack v8.5 now but moreover, don't hesitate to keep the conversation alive. Our team is eager to learn what you want in v8.6, we're impatiently waiting to hear your thoughts where we can improve components, what new functionality to add and what cool new components can make your job as developer of great Windows applications with Delphi or C++Builder even more enjoyable and exciting. Use your communication channel of preference and get in touch:

Image may be NSFW.
Clik here to view.
Image may be NSFW.
Clik here to view.
  Image may be NSFW.
Clik here to view.
   Image may be NSFW.
Clik here to view.
   Image may be NSFW.
Clik here to view.
   Image may be NSFW.
Clik here to view.
   Image may be NSFW.
Clik here to view.
  


Image may be NSFW.
Clik here to view.


TMS Aurelius and MVVM Design: an example

John Kouraklis has posted a 2-part article in his blog about using TMS Aurelius and MVVM. From the article: "Model-View-ViewModel (MVVM) design pattern allows developers to write software in a way that separates applications to layers that serve the business logic, the presentation logic and the elements of the user interface."

You can follow the links below to read the article:

http://www.kouraklis.com/2017/01/tms-aurelius-and-mvvm-design-an-example/
http://www.kouraklis.com/2017/01/tms-aurelius-and-mvvm-design-an-example-part-2/

He's also published the "MVVM in Delphi" book, you can purchase it from Amazon. More info about the book here.

Image may be NSFW.
Clik here to view.


My Top 10 Aurelius Features - #5 LINQ Expressions and Paging

Most examples and quick-start tutorials about ORM frameworks explain how to insert, update and retrieve single entities in the database. But not many of them go further and show how to perform a query in the database. Maybe because that's something that the developer will only need after many data is inserted, and it's something that is only heavily needed when the application development is at a more advanced stage. However, it's a very important feature, and that's why "LINQ Expressions and Paging" is my #5 feature of My Top 10 Aurelius Features.



The reason for that is because you can really query your entities in a object-oriented way. It's not some SQL-like string you build, or SQL WHERE statement that you simply inject. It's really about querying object properties, comparing their values in Pascal (not in database), and using Pascal syntax to build the queries. Take a look at this example:

  MyCustomers := Manager.Find<TCustomer>
    .Where(
      (
         (Linq['Birthday'] > EncodeDate(1981, 10, 10))
         and (Linq['Birthday'] < EncodeDate(1986, 2, 2))
      )
      or ((Linq['Sex'] = tsFemale) or Linq['Sex'].IsNull)
      or Linq['Name'].Contains('Walker')
      or Linq['Status']._In([TCustomerStatus.Active, TCustomerStatus.Prospect)
    )
    .OrderBy('Name')
  .List;
That's an example of filtering by Birthday property using logical operators "and", "or", how you can use parenthesis and have Delphi give you compile errors if expression is wrongly constructed. And of course you have extra expressions like "Contains", "In", etc.. All in Pascal.

Finally, a small feature of LINQ filtering that I enjoy a lot: paging. It's very simple to use and very handy:
  MyCustomers := Manager.Find<TCustomer>
    .Take(10).Skip(50)
    .OrderBy('Name')
    .List;
The code above in theory should bring all customers, but will only bring 10 customers, skipping the first 50 in the specified order. This is great for bringing a long list but in parts, page by page. And of course you can use it with any criteria you specify, like the complex one illustrated above in this post.

To see in details how LINQ expressions and paging works, watch the video above, and if you want to get notified about upcoming videos, subscribe to our YouTube channel!


TMS FNC Core

With the 1.7.1.0 release of the TMS FNC UI Pack we have introduced a TMS FNC Core separation. This means the TMS FNC Core needs to be installed as a prerequisite in order to successfully install the TMS FNC UI Pack. Apart from this separation, the new core setup will not introduce breaking changes in your application, as the file names for both the TMS FNC Core and TMS FNC UI Pack have remained the same. The separation gives us the benefit of writing components that all rely on a single core, instead of duplicating units that offer exactly the same features in multiple component sets. All current and future TMS FNC products will build upon this common core.

Custom Component Development for FNC

Now the TMS FNC Core is released, you'll have a series of units available that can be used to write custom components yourself for our FNC framework.
[FMX.][VCL.][LCL]TMSFNCBitmapContainer.pas
[FMX.][VCL.][LCL]TMSFNCCustomComponent.pas
[FMX.][VCL.][LCL]TMSFNCCustomControl.pas
[FMX.][VCL.][LCL]TMSFNCCustomScrollControl.pas
[FMX.][VCL.][LCL]TMSFNCGraphics.pas
[FMX.][VCL.][LCL]TMSFNCGraphicsTypes.pas
[FMX.][VCL.][LCL]TMSFNCHTMLEngine.pas
[FMX.][VCL.][LCL]TMSFNCStyles.pas
[FMX.][VCL.][LCL]TMSFNCTypes.pas
[FMX.][VCL.][LCL]TMSFNCURLBitmapContainer.pas
[FMX.][VCL.][LCL]TMSFNCUtils.pas

Note that with this set of units, you are able to write a custom component from scratch. A tutorial on writing a custom component can be found in this blog post: http://www.tmssoftware.com/site/blog.asp?post=346

One of our many commitments for 2017: more product demonstration videos

We already provide help and documentation in several ways: PDF developer guides for most complex components, a page with component specific tips and FAQ, a monthly knowledge base alert, ... . our TMS Support Forum with almost 10.000 forum members also offers a big help to many users. And of course our first-class support directly from our developers here at the office.

But we listened to your feedback and it was clear that many of you also wanted in addition to this videos explaining the products and offering step by step demos. So, we made it an action point and commitment for 2017 to significantly increase our offerings in videos.

With our video's we would like to show you step by step what great features our components are offering without the need to install trial versions or spend a lot of time reading through all our documentation. No hassle, just 1 click on the video and you can see our components in action, be it in VCL applications, cross-platform FMX applications, Cloud, Intraweb, ...

To show our commitment, here are already the first 3 videos we created this year in January and more will be following shortly:

Video 1 about how you can effortlessly generate pdf files from a VCL DB grid.



Video 2 about how you can use the mycloudData service which is a cloud service for structured cloud storage for data.



Video 3 about responsive design in VCL applications with the TDBAdvResponsiveList.



So we kindly invite you to get subscribed to our YouTube channel tmssoftwareTV and of course we wish you much fun in exploring our components and their possibilities!

More videos are coming in the near future.

My Top 10 Aurelius Features - #4 Aurelius Dataset

I consider Aurelius Dataset (TAureliusDataset) a hidden gem of TMS Aurelius. Well, not exactly "hidden" because it's a significant part of it to deserve its own chapter in the Aurelius documentation, but in the sense that it's different from the normal ORM "core" which is update, insert, delete, select, query, etc.. And for that it's #4 of My Top 10 Aurelius Features.



The first misunderstanding about the TAureliusDataset is confusing its usage with the regular way we use Delphi datasets. I've been in discussions in forums with people that were blaming the usage of dataset, because it's not "good practice", because logic should be in the controller/model, etc., etc..

The point is Aurelius Dataset is for data binding. It's not about retrieving data. You will retrieve data the same way with or without the dataset. Your logic, controller and model will still be isolated. But when it comes to show or edit data of an entity in a visual form, you don't have to manually do things like this:

edCustomerName.Text := Customer.Name;
edCustomerCity.Text := Customer.City;
or even worse, to populate a grid or list (pseudo-code):
Grid.Clear;
for Customer in Customers do
begin
  CurrentRow := Grid.AddRow;
  Grid.Columns[0, CurrentRow] := Customer.Name;
  Grid.Columns[1, CurrentRow] := Customer.City;
end;
that's tiresome, repetitive and not necessary with Aurelius Dataset. You just set the "data" of the dataset, which are your objects:
AureliusDataset1.SetSourceList(MyCustomerList);
or
AureliusDataset1.SetSourceObject(MyCustomer);
and you bind the dataset to data ware controls! Or to regular controls use live bindings. Or provide the dataset to some report tool.

The coolest thing about the Aurelius Dataset is that its minor features and high integration with Aurelius. It's not just a generic binder between Delphi objects and controls. But it handles smoothly a lot of specific Aurelius features like:

Nullable types
Associations and its sub-properties
Master-Detail (many-valued association as nested datasets)
Enumerated types

and provide the regular dataset mechanisms but adapted to the object-oriented approach, like:

Lookup fields
Calculated fields
Design-time support

And finally, it handles paging and fetching smoothly as well. You can have a criteria that is retrieved page by page on demand, avoiding all objects to be retrieved at once, and at the same time avoiding a cursor to be open to the database!

Watch the video above to see Aurelius Dataset in action, and if you want to get notified about upcoming videos, subscribe to our YouTube channel!

Cross platform messaging made easy with TMS MQTT

Last week we released a new product, TMS MQTT. MQTT is a standard lightweight machine 2 machine messaging protocol. This enables the instant exchange of binary or text messages between code running on various operating systems. To fully take advantage of this, we developed our TMS MQTT client to work in VCL Windows applications, FMX Windows, macOS, iOS and Android applications and also on Linux desktop or Linux variants such as Raspbian on Raspberry Pi via FPC/Lazarus.

On this 22th birthday of Delphi, I wanted to show you how our TMS MQTT component allows you to develop a messaging application in a real RAD way. I'll do this by implementing a chat application that allows you to chat between clients running on desktops or mobile devices. This effectively takes less than 40 lines of code using the TMS MQTT component of which 15 lines already go to inserting the chat text left and right in items of an FMX listbox and another +/- 10 lines detecting the origin of the chat text that is received to decide whether to show it left or right in the listbox. So, I'd say only about 15 lines of code effectively concern using the MQTT client to do the messaging.

For this demo, we use the Mosquitto MQTT test broker and connect to it with 2 lines of code:

begin
  TMSMQTTClient1.BrokerHostName := 'test.mosquitto.org';
  TMSMQTTClient1.Connect();
end;

Upon connecting, we subscribe to the topic /tms/chat/ that is the topic that will be used to exchange chat text between multiple clients. This takes 2 lines of code from the TMQTTClient.OnConnectedStatusChanged() event:
procedure TForm1.TMSMQTTClient1ConnectedStatusChanged(ASender: TObject;
  const AConnected: Boolean);
begin
  if AConnected then
    TMSMQTTClient1.Subscribe('/tms/chat/');
end;
To send a message, text entered in a memo control is published on this topic with one line of code:
  TMSMQTTClient1.Publish('/tms/chat/', TMSMQTTClient1.ClientID+'!'+ memo1.Lines.Text);
Here we add the unique ID of the app sending the chat text and the chat text itself.
Finally, incoming chat text on the subscribed topic is received via the TMQTTClient.OnPublishReceived() event. The unique client ID is retrieved to decide whether to put the chat text left or right of the message listbox and this is done via the code:
procedure TForm1.TMSMQTTClient1PublishReceived(ASender: TObject;
  APacketID: Word; ATopic: string; APayload: TArray);
var
  msg,orig: string;
  vp: integer;
  alright: boolean;
begin
  msg := TEncoding.UTF8.GetString(APayload);

  vp := pos('!', msg);

  if vp > 0 then
  begin
    orig := copy(msg,1,vp-1);
    alright := orig <> TMSMQTTClient1.ClientID;

    msg := copy(msg, vp + 1, Length(msg));
    AddMessage(msg, alright);
  end;
end;

And then comes the method to allows us to insert either left or right aligned text as items in an FMX listbox:
procedure TForm1.AddMessage(AMessage: string; AlignRight: boolean);
var
  li: Tlistboxitem;
begin
  li := Tlistboxitem.Create(self);
  li.StyledSettings := li.StyledSettings - [TStyledSetting.ssOther];
  li.Text := AMessage;
  li.Height := 22;
    li.VertTextAlign := TTextAlign.taTrailing;

  if AlignRight then
    li.TextAlign := TTextAlign.taTrailing
  else
    li.TextAlign := TTextAlign.taLeading;

  listbox1.AddObject(li);
end;

Compile and run this application on your operating system of choice. In my case, I did setup a small chat between the client compiled for Windows and the client deployed on an iPhone:
Image may be NSFW.
Clik here to view.

You can download the full source code of this FireMonkey application here.

I invite you to explore the numerous exciting capabilities of machine 2 machine messaging. Note that there are JS libs that facilitate to do MQTT messaging via websockets from a webbrowser. The demo included in the TMS MQTT download is based on messaging between a desktop or mobile client app and a web page application. With the TMS MQTT client, you can also use machine 2 machine messaging from your Raspberry Pi and send this way various sensor data captured by the Raspberry Pi to desktop or mobile apps. In a follow-up blog, we'll explain and offer such sample project.
Image may be NSFW.
Clik here to view.
Image may be NSFW.
Clik here to view.

I look forward to hear about how you will use MQTT machine 2 machine messaging in your apps or IoT projects!

Image may be NSFW.
Clik here to view.


My Top 10 Aurelius Features - #3 Inheritance

How to talk about object-oriented programming and not consider inheritance? In my opinion is a basic "feature" of OOP. And how to talk about an ORM without supporting inheritance? I consider it so important that the simply fact that Aurelius supports it makes it my #3 of My Top 10 Aurelius Features.



It's really nice to be able to model classes and build a class hierarchy, reference classes in that hierarchy from other properties, have a true model that is not just a bunch of plain classes that map properties to database columns. Inheritance support allows you to really think in an OOP way when using an ORM.

TMS Aurelius supports two ways of persisting objects in a class hierarchy in the database:

Joined-tables strategy
Where data from each class is saved in a different database. This is the more normalized way.

Single-table strategy
Where data from all classes are saved in a single table. This is the simplest and often offers better performance.

Regardless of your choice, the facts is that Aurelius allows you to do so! Watch the video above to see how class inheritance works with TMS Aurelius, and if you want to get notified about upcoming videos, subscribe to our YouTube channel!

Take your chance to win a #ILoveDelphi Mug

With the many positive responses on our Facebook post about #ILoveDelphi and thanks to the inspiration given by Szabó about 'the cup and can', we came up with the idea to bring the love between Delphi and TMS alive in a coffee cup!

Image may be NSFW.
Clik here to view.
mug


Like the mug?

We're going to give away 5 coffee mugs. To make a chance on winning a mug, just add your star rating on our Facebook page together with your review! We will pick 5 winners on Thursday, March 2 and we will send a mug your way!

Image may be NSFW.
Clik here to view.
mug

Good luck to all the participants and thank you in advance for your review! And while you're at our Facebook page, we also like to invite you to like our Facebook company page if you're not already following our latest news via this channel.

Raspberry Pi to Delphi messaging with MQTT

As promised in the blog about building a chat application with MQTT, here is a follow-up article on using the TMS MQTT client, this time to setup messaging between a Raspberry Pi and a Windows PC. The TMS MQTT client fully supports Lazarus and thus also targetting Linux and its variant Raspbian, so we can use the TMS MQTT Client from Raspberry Pi. For this short demo, we setup Lazarus on Raspberry Pi and installed the TMS MQTT client component in the IDE as well as our free Raspberry Pi hardware lib.

We'll use the component TMSLCLAdaADC12b to be able to use the 12bit ADC connected via i2c to the Raspberry Pi. The goal of the setup is to read-out noise meter values via the ADC and send the measurements via messaging to the channel 'tms/raspi'. A Windows Delphi application will then listen through this same MQTT client to the messages on channel 'tms/raspi' and will display the values in our TMS Instrumentation Workshop component TvrScope. Best of all, with the help of these components, this is not much more than a 15 minute project where most of the time will be spent to properly connect the ADC breakout board via a breadboard to the Raspberry Pi i2c port.

Image may be NSFW.
Clik here to view.


For the code, we use the same setup in the Windows Delphi application as on the Raspberry Pi Lazarus application to connect our client to the Mosquitto test broker:

begin
  TMSMQTTClient1.BrokerHostName := 'test.mosquitto.org';
  TMSMQTTClient1.Connect;
end;

On the Raspberry Pi Lazarus app, we add a timer that will get the ADC value every 200msec and send the value as a message to 'tms/raspi'. For reason of simplicity, we'll send the value as a text message via MQTT. The code to do this is added to the timer OnTimer() event handler:

var
  i: integer;
begin
  // get value from the 4 channel ADC channel 0 to which the analog noise meter output is connected
  i := TMSLCLAdaADC12B1.ReadChannel(0);
  // send the value as text over MQTT
  TMSMQTTClient1.Publish('tms/raspi', inttostr(i)); 
end;

To get the i2c communication working on the Raspberry Pi, we open the i2c connection to the ADC in the form's OnCreate event:

procedure TForm1.FormCreate(Sender: TObject);
begin
  // make sure to start the Raspberry Pi app with sufficient permissions to be able to open access to i2c
  if not TMSLCLAdaADC12B1.Open then
  begin  
    ShowMessage('error opening i2c');
    Exit;
  end;
end;
and we close the port again from the form's OnClose event:

procedure TForm1.FormClose(Sender: TObject; var CloseAction: TCloseAction);
begin
  TMSLCLAdaADC12B1.Close;
end;

For the Delphi Windows client, here we'll add an event handler for TMSMQTTClient.OnPublishReceived() that is triggered when a message is received. From this event, we store the received value in a variable containing the last received value LastVal. Here the (positive) value of the ADC is mapped onto the 0 to 100 range:

procedure TForm1.TMSMQTTClient1PublishReceived(ASender: TObject;
  APacketID: Word; ATopic: string; APayload: TArray<System.Byte>);
var
  s:string;
begin
  s := TEncoding.UTF8.GetString(APayload);
  LastVal := Round(100 * strtoint(s) / 1024);
end;

To visualize the data, the TMS Instrumentation Workshop TVrScope component is used where we added one channel and automatic display (VrScope.Active = true). This means that at a configured frequency (VrScope.Frequency), this scope component requests the channel value and displays it in the scope. This is done via the TvrScope.OnNeedData() event that is triggered every time the scope advances and needs a new value. Here, the last received value LastVal is returned:
procedure TForm1.VrScope1NeedData(Sender: TObject; Channel: Integer;
  var Value: Integer);
begin
  Value := LastVal;
end;

As a result, here you can see some quickly captured data in our test setup:
Image may be NSFW.
Clik here to view.


In summary, this small demo shows how really quick & easy you can get started using m2m messaging using MQTT with the TMS MQTT Client and this on a wide range of devices, from desktop PC to mobile device, to Linux machine and to Raspberry Pi SBC. We wish you much fun with your projects and we love to hear from all the exciting stuff you create with these building blocks!


Who broke the SHA1 Algorithm?

SHA-1 is a hash function developed by NSA and standardized by NIST in 1994. It is implemented in many Internet protocols using cryptographic primitives, such as TLS. Last week the CWI Institute in Amsterdam and Google announced the first practical collision for SHA-1, meaning that they actually generated two files with the same cryptographic hash, something that should never happen with a hash function because collisions can be used to forge false messages in fraudulent activities.

TMS Software has been conservative with cryptographic algorithms and, while offering a wide variety of primitives in its comprehensive TMS Cryptography Pack, is committed to only supporting robust and secure algorithms. Therefore TMS Cryptography Pack never implemented deprecated algorithms such as SHA-1, MD5 or DES, but rather provides the Delphi and C++ Builder communities with the latest standards such as the AES, strong RSA, Elliptic Curve Cryptography, the SHA2 and SHA3 families and ARGON2 for key derivation and many other useful features packaged and ready to use for developers in all types of multi-platform applications.

Image may be NSFW.
Clik here to view.

TMS Cryptography Pack implements all these algorithms except SHA-1 and MD5

Presentation of TMS Cryptography Pack at Bordeaux and Nantes

Barnsten in organizing 2 free events in March:
Bernard Roussely from TMS Software will be presenting a client server demo showing how to generate a certificate, register to a Linux server that maintains a database of certs and then how to authenticate exchanges between clients with the server acting as a trust authority in the middle. If you are around and want to learn more about cryptography in general and TMS Cryptography Pack, register for one of these free events!

My Top 10 Aurelius Features - #2 LINQ Projections

LINQ Projections is the runner-up feature of My Top 10 Aurelius Features. It's a sort of "sequel" of the #5 feature LINQ Expressions and Paging, and you can see it in action in the video below.



You could consider that "LINQ Expressions" and "LINQ Projections" are just sides of the same feature. That's not incorrect indeed. But LINQ is a so nice feature of TMS Aurelius that it deserved to be split in two parts. And the reason that projections (and not expression) is ranked higher is just because it's at the core of LINQ.

The coolness of LINQ is more due projections than expressions in my opinion. An expression is actually just a comparison of two projections. It's in the projections that all complexity lies in. And it allows beautiful and complex queries like the following to be written:

Get the unit price and quantity of each order detail, multiply them, and group the sum of it by the year of Order Date.

    Manager.Find<TOrder>
      .CreateAlias('OrderDetails', 'd')
      .Select(TProjections.ProjectionList
        .Add(Linq['OrderDate'].Year.Group.As_('Group'))
        .Add((Linq['d.UnitPrice'] * Linq['d.Quantity']).Sum.As_('Value'))
      )
      .Where(Linq['OrderDate'].Year._In([1997, 1998]))
      .OrderBy('Value')
Yes, projections allow you to do grouping, counting, sum, arithmetic operations, extract information from dates like year, month, day, from strings like substring, pos, etc. A full list of available projections is in Aurelius documentation. And everything just translated correctly to the underlying SQL syntax!

Cool, isn't it? You can see queries like the ones above in action, by watching the video above. Don't forget to subscribe to our YouTube channel to get notified about upcoming videos!

One picture is worth a thousand words.

My Top 10 Aurelius Features - #1 Maturity

Finally, My Top 10 Aurelius Features series has come to an end. And the number 1 of the list is Maturity.



Aurelius has been first released in early 2012. Since then, in five years, it has received 33 releases! With the user feedback received during all the time, I’m confident that Aurelius feature set is pretty extensive.

For example, you can build applications for all supported Delphi platforms: Windows, Mac OS X, iOS, Android and Linux. The number of supported database systems is impressive: Oracle, MySQL, SQL Server, PostgreSQL, DB2, Firebird, SQLite, NexusDB, ElevateDB and the list goes on. The same can be said about the component libraries you can use to access the database: the list of 15 options include FireDac, dbExpress, ADO, UniDac, among others.

Maturity also means that you can trust it, because it just works. Aurelius test suite includes hundreds of unique tests, which makes up thousands of tests because we make sure that they work in all the supported platforms and servers. This means that you can be sure it will work on Windows, using dbExpress to access an Oracle database, the same way it will work on Linux, using FireDac to access a MySQL database.

In the end, why I really like this maturity feature? Because it makes my life easier and happier. Lower support because there are no known bugs that stand for too long. And happier customers because they have the features they need.

We’d love to hear your comments about it. Do you agree with this list? What would be yours? Post your opinions and comments below, visit our website, download TMS Aurelius trial and let us know what you think. Don't forget to subscribe to our YouTube channel to get notified about upcoming videos!

Introducing functional derivatives is easy

The unique feature of Analytics library is symbolic derivatives calculation. The library provides the simplest way to get a symbolic derivative expression for almost any complicated expression. There are predefined derivative for all standard functions: trigonometric, hyperbolic, logarithmic and exponential, inverse trigonometric and hyperbolic, and other.

Another fine thing is that any developer can easily define derivative for any other function. Let us consider how to define derivative for special Gamma function (https://en.wikipedia.org/wiki/Gamma_function#General). Its derivative is defined via another special function – Digamma (Polygamma function of order 0, https://en.wikipedia.org/wiki/Polygamma_function). Hereafter the Gamma function denoted as ‘G’ and the Digamma (and Polygamma) as ‘Y’. Then, the derivative formula is: d(G(x))/dx = G(x)*Y(x).

To introduce new functional derivative new class must be implemented. In our case, the class is inherited from ‘TSimpleFunctionalDerivative’ because the function has one argument only. Here is the code of the realized class:

TGammaDerivative = class sealed(TSimpleFunctionalDerivative)
protected
  function GetFunctionName(): string; override;
  function BaseDerivative(argument: TBaseExpression): TBaseExpression; override;
public
  class function IsRealized: boolean; override;
end;

function TGammaDerivative.GetFunctionName: string;
begin
  result:= 'G';
end;

class function TGammaDerivative.IsRealized: boolean;
begin
  result:= true;
end;

function TGammaDerivative.BaseDerivative(argument: TBaseExpression): TBaseExpression;
var
  ge: TBaseExpression;
  dge: TBaseExpression;
begin
  ge:= TFunctionExpression.CreateSimple('G', argument);
  dge:= TFunctionExpression.CreateSimple('Y', argument);

  result:= TProductExpression.MakeProduct(ge, dge);
end;
As can be seen from the code, there are only three methods to override. The GetFunctionName method defines that the derivative is for function with name ‘G’. The IsRealized functions returns ‘true’, that means the class is totally realized and can be used by the Analytics system. And the last method defines the derivation algorithm itself. Namely, it creates the Gamma and Digamma functions with the same argument and, according to the derivative formula above, their product.

Now we can calculate derivatives for expressions with the Gamma function. For the simplest case with input string ‘G(x)’ we get the expected output string ‘G(x)*Y(x)’. No surprise here, because we just wrote the code, which produces the output.

But the amazing thing is when we trying to calculate the derivative expression for the Gamma function with a composite argument. As example, for the input string ‘G(x^2+1)’ it produces the output string ‘(G(x^2+1)*Y(x^2+1))*(2*x)’ which is totally correct for this case. And the output is correct for all the expressions with the Gamma function. It is because the Analytics library cares about other things, like implementing the ‘chain rule’ for derivation process.

The source code of the example project is available here.

Viewing all 1008 articles
Browse latest View live


<script src="https://jsc.adskeeper.com/r/s/rssing.com.1596347.js" async> </script>