Quantcast
Channel: TMS Software
Viewing all 1006 articles
Browse latest View live

Introducing Sergey Gladkiy and TMS Analytics & Physics Pack

$
0
0

It's always a privilege and honour to be able to work with very smart people who are not only expert in Delphi but also expert in a specific domain. Earlier this year, Bernard Roussely and Marion Candau joined tmssoftware.com and focus so far on advanced cryptography algorithms with the highest security levels in TMS Cryptography Pack. More tools that will use this underlying strong technology are already in the pipeline. Around the same time, also Roman Yankovsky joined tmssoftware.com and the static code analysis tool TMS FixInsight is the result. With TMS FixInsight, you can bring your Delphi code to a higher quality & safer level with numerous code hints and suggestions it gives.
Today, I'm proud to announce Sergey Gladkiy joins the TMS team for working on products with a strong mathematical background. The first result is the TMS Analytics & Physics Pack. This pack offers a set of (non-visual) platform independent classes to work with mathematical expressions and units of measurements. In TMS Analytics & Physics Pack, you can do evaluation of complex multiparameter mathematical expressions, including expressions with complex numbers. You can do physical measurement conversions of all kinds. But perhaps the most amazing part is symbolic derivative calculations. In this respect, TMS Analytics & Physics Pack brings a math wizard in the form of classes that can be used in VCL and FMX apps. You can discover the power of this library via the included demo but I wanted to share some examples of symbolic derivative calculations that will boggle your mind:

Task: calculate the derivative function of:
1/(x-1)+(2*x-1)/(x+1)^2

Result:
(-(1)/(x-1)^2)+(2*(x+1)^2-(2*(x+1)^(2-1))*(2*x-1))/((x+1)^2)^2

The code to achieve this is as simple as:

var
   f,df: string;

   f := '1/(x-1)+(2*x-1)/(x+1)^2';

   try
      if Translator.CheckSyntax(f) then
      begin
        df:=Translator.Derivative(f,'x');
        ShowMessage('Derivative function :' + df);
      end;
   except
      ShowMessage('Error');
   end;
Let's take another example with some trigonometric mathematical functions:

Task: calculate the derivative function of:
(sin(x)+cos(x))/x

Result:
((cos(x)+(-sin(x)))*x-(sin(x)+cos(x)))/x^2

The resulting derivative expression can then be evaluated, for example against x=2:
var
   df: string;
   v: TValue;

   df := '((cos(x)+(-sin(x)))*x-(sin(x)+cos(x)))/x^2';

   try
      Translater.Add('x', 2.0); 
      if Translator.CheckSyntax(df) then
      begin
        v :=Translator.Calculate(df);
        ShowMessage('Result :' + s:=TUtilities.SafeToString(v));
      end;
   except
      ShowMessage('Error');
   end;
The result of this calculation is: -0,786009779256047.

I kindly invite you to explore our new TMS Analytics & Physics Pack. A fully functional trial version is available and the registered versions comes with full source code. We're eager to learn in what kind of exciting and cool applications these powerful classes will find a place!


TEncryptedIniFile: easy to use class for handling app settings with encryption

$
0
0

What's wrong with the KIS principle to store application settings in an INI file? The risk that someone is tampering with the INI file is an often heard reason for not using them. Not being able to store private or secret information another one.
Both issues are solved with the introduced TEncryptedIniFile class. It descends from TMemIniFile and is as such a drop-in replacement and will deal only in app memory with decrypted data. In the file itself, the data is at all times encrypted. To build TEncryptedIniFile, we internally use AES 256bit encryption offered by the TAESEncryption class in TMS Cryptography Pack.

The code to use TEncryptedIniFile becomes something like:

const
  aeskey = 'anijd54dee1c3e87e1de1d6e4d4e1de3';
var
  mi: TEncryptedIniFile;
begin
  try
    mi := TEncryptedIniFile.Create('.settings.cfg', aeskey);
    try
      FTPUserNameEdit.Text := mi.ReadString('FTP','USER','');
      FTPPasswordNameEdit.Text := mi.ReadString('FTP','PWD','');
      FTPPortSpin.Value := mi.ReadInteger('FTP','PORT',21);
      mi.WriteDateTime('SETTINGS','LASTUSE',Now);
      mi.UpdateFile;
   finally
      mi.Free;
   end;
  except
    ShowMessage('Error in encrypted file. Someone tampered with the file?');
  end;
end;
Of course, the weakness now is that the AES key is in the EXE file and as such, it won't stop seasoned hackers to extract it from the EXE and use it directly to decrypt/encrypt the settings file and tamper with it this way. Extra steps could be taken to use an AES key that is a combination of a unique machine ID and a part that is encrypted with a Ed25519 generated public key and decrypt the encrypted part of the AES key on the fly in the app with the Ed25519 private key and then use it in combination with the machine ID to encrypt/decrypt the INI file. That should make the effort to hack the settings file already a lot more difficult.

To start using this TEncryptedIniFile you can get TMS Cryptography Pack and you can download the TEncryptedIniFile class source here.


TMS online videos presented at CodeRage XI

$
0
0

During CodeRage XI, the online event from Embarcadero, Bruno Fierens (founder TMS software and Embarcadero MVP), Wagner Landgraf (TMS Business product manager) & Roman Yankovsky (TMS FixInsight product manager and Embarcadero MVP) brought sessions covering our latest technologies FNC, myCloudData, Aurelius, FixInsight developed at TMS software.

If you missed one of these sessions, you can now watch them via our Youtube channel.

New video's published at tmssoftwareTV:
Cross Framework UI Controls - by Bruno Fierens: This session explains the differences between the VCL and FMX framework that are relevant for custom user interface control development. Given these differences, an abstraction layer, FNC is presented that enables creating custom user interface controls starting from a single source code base that can be used for both VCL, FMX (and LCL) applications. In the last part of the session, several complex FNC UI controls that are in the TMS FNC UI Pack product are demonstrated that can be used in VCL, FMX, LCL applications and target this way Windows, iOS, Android, macOS and Linux.



Metadata assisted automatic DB form generation for cloud data - by Bruno Fierens: The myCloudData.net service offers easy to use structured cloud data storage. The foundation of the service is a REST API. For our Delphi users, we added several components to consume this service with an absolute minimum amount of effort. The TAdvmyCloudData component enables using object oriented programming techniques for using the myCloudData.net service. With TAdvmyCloudDataDataSet and TAdvmyCloudDataDataConnection, controls can be bound directly to the data in the cloud, be it via DB-aware controls or livebindings. For the next level of automation: bound DB forms auto generated with the help of rich metadata, two components are available, TAdvmyCloudDataFormPanel and TAdvmyCloudDataFormBox.



TMS Aurelius Free Edition, an overview - by Wagner Landgraf: An overview of the well-regarded Aurelius ORM framework for Delphi, which now has a free edition for commercial use, available for Delphi 10.1 Berlin.



FixInsight: Finding Bugs with Static Code Analysis - by Roman Yankovsky: Roman Yankovsky shows you how to use FixInsight's static code analysis in Delphi to find bugs in your code before your customers do. Roman Yankovsky is an Embarcadero MVP and the author of FixInsight static analysis tool for Delphi.



My Top 10 Aurelius Features - Introduction

$
0
0

After the release of TMS Aurelius Free Edition, the free version of our ORM framework, I've been thinking to do some blog posts about some key TMS Aurelius features. However I spent some time deciding what features to show: would they be in chronological order? Separated by categories? In order of "importance" - and what would be the criteria of "importance"?

Well, finally, as you can tell from the title of this post, I decided to do that in a "top 10 list" format - who knows, maybe this series will appear at Buzzfeed... But most important of all: this is my personal list of favorite features. So no objective criteria here - just some features I consider cool, features that I have "respect" for because were hard to implement or simply features that I use a lot.

So let's go for the list. Starting with #10, I will keep adding new blog posts over time until I reach feature #1. Hope you enjoy it:

#10 - Automapping
#9 - Plain Old Delphi Objects
#8 - Lazy Loading


My Top 10 Aurelius Features - #10 Automapping

$
0
0

This is the #10 feature of My Top 10 Aurelius Features. Follow the link for the full list!

Using the automapping feature is easy: you just need to add the [Automapping] attribute to your class:

type
  [Entity, Automapping]
  TCustomer = class
  private
    FId: Integer;
    FName: string;
  public
    property Id: Integer read FId write FId;
    property Name: string read FName write Name;
  end;

and it will automatically map the class to the database using some conventions. This prevents you from having to manually use the mapping attributes like Column, Table, Id, etc., to tell Aurelius exactly how the database schema will be.

If you already have an existing database, this is not very useful since the convention used by it will probably not match your existing database. But when you do the code-first approach (my favorite) - where you start your application creating the classes, not the tables - this is very handy.

Besides the obvious fact that Automapping speeds up the development process (prototyping is really fast with it), what I really like about Automapping is how it makes you forget about the database and think only about classes: you just don't remember you have a table or a column somewhere in the database - let Aurelius chooses whatever it needs for the underlying database, and focus on your code.

Another interesting thing is that it's not an all-or-nothing feature: you can have use the Automapping attribute but still override it with specific mapping attributes - so you get the best of both worlds: convention with flexibility:
type
  [Entity, Automapping]
  TCustomer = class
  private
    FId: Integer;
    [Column('CUSTOMER_NAME', [TColumnProp.Required], 120)]
    FName: string;
  public
    property Id: Integer read FId write FId;
    property Name: string read FName write Name;
  end;

And to conclude, here is a small video (~4 min) showing Automapping usage:



Weekend fun with Delphi, math and FNC

$
0
0

Mathematics is fascinating, Delphi is cool, cross-platform is awesome, cross-framework is the icing on the cake. So, what's better than spending some time with all four on a weekend day?

For some time, we offer our TMS Analytics & Physics package that can do formula evaluation, complex number calculation and most interestingly also expression based derivative function calculation. Also since beginning of 2016, we offer our TMS FNC Chart, which is a chart package that offers a chart UI component that can be used in VCL applications, FMX applications and also LCL (Lazarus/FPC based) applications. This means that with the TMS FNC Chart, we can target Win32, Win64, macOS, iOS, Android, Linux, Raspbian operating systems.

So, I set out this weekend to spend some time creating a simple mathematical formula plotting application (cross platform & cross framework) that could not only display a function but also calculate its derivative function and plot it. This way, we can visually see the effect of calculating a derivative function.
The setup of this application turns out to be amazingly simple with some help of TMS FNC Chart and TMS Analytics & Physics Pack.

The core code is a model class that does chart initialization & formula calculation + derivative calculation by means of two class methods. This model can be used by the VCL, FMX or LCL application as apart from unit references, all code is framework independent. In this model, calculation is central and is nothing more than performing parsing of a mathematical formula and calculating it's derivative and Y-values for a range of X-values and display this in a chart. To do this, we initialize the TTranslator class (part of TMS Analytics) and specify the X is the main variable of the functions we can write and then we check the syntax, calculate the derivative and calculate values for both function and derivative function:

  FTransMain := TTranslator.Create;
  FTransDeriv :=  TTranslator.Create;

  vName := 'x';
  vValue := 1.0;
  FTransMain.Add(vName, vValue);
  FTransDeriv.Add(vName, vValue);

  try
    if FTransMain.CheckSyntax(f) then
    begin
      df := FTransMain.Derivative(f,'x');

      if FTransDeriv.CheckSyntax(df) then
      begin
        for i := -xrange to +xrange do
        begin
          // get Y value of the function for a given X value
          FTransMain.Variables['x'].Value := i;
          v := FTransMain.Calculate(f);
          // add the Y point to the XY chart series 1
          AChart.Series[0].AddXYPoint(i,v.AsExtended);

          // get Y value of the derivative function for a given X value
          FTransDeriv.Variables['x'].Value := i;
          v := FTransDeriv.Calculate(df);
          // add the Y point to the XY chart series 2
          AChart.Series[1].AddXYPoint(i,v.AsExtended);
        end;
      end;
    end;
  finally
    FTransMain.Free;
    FTransDeriv.Free;
  end;
This is the core code responsible for coming to a result for a function like sin(x)+1/4*cos(x*10) that you can think of as mathematical basis for modulation techniques.

FMX version of the Math Explorer app running on macOS

Of course, the intention of the math exploring application is that you can enter any other mathematical function of X and not only see the derivative function but also plot it in the chart. Download & install TMS Analytics & Physics and TMS FNC Chart and then compile and run the VCL or FMX version of the math explorer application you can download with full source code.

My Top 10 Aurelius Features - #9 Plain Old Delphi Objects

$
0
0

My number 9 feature of My Top 10 Aurelius Features refers to PODO - Plain Old Delphi Objects. Or in other words, the fact that Aurelius entities are simple, clean Delphi classes.

When Aurelius project started back in mid 2011, there were some object persistent frameworks available for Delphi. At that time I was wondering why such existing ones did not catch up strongly.

There were some people using it, but I didn't feel it was something that people were embracing. And one of the reasons (in my opinion) was that to make classes to become persistent the developer needed to do some many workarounds that the class end up being cluttered with unneeded things, and coding with that class was not very pleasant.

Imagine writing business code with the class below:

type
  TContact = class(TORMBaseClass)
  private
    FId: TORMInteger;
    FName: TORMString;
    FCountry: TORMRelationship;
    function GetId: TORMInteger;
    procedure SetId(const Value: TORMInteger);
    function GetName: TORMString;
    procedure SetName(const Value: TORMName);
    function GetCountry: TORMRelationship;
    procedure SetCountry(const Value: TORMRelationship;
  public
    constructor Create(SpecificParams: TORMINit); override;
    destructor Destroy;
    procedure Save(Context: TORMContext); override;
    procedure Update(Context: TORMContext); override;
    procedure Delete(Context: TORMContext); override;
  published
    property Id: TORMInteger read GetId write SetId;
    property Name: TORMString read GetName write SetName;
    property Country: TORMRelationship read GetCountry write SetCountry;
  end;

And compare to using this class when writing your code:
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;

The first code is not specific to any other persistent framework. Actually, it's really fake, it's just a combination of ideas and solutions used by several frameworks I've seen over the years. The fact that you have to inherit from a base class, override base methods in it, have a constructor implemented that initialize mappings manually, use framework-specific types instead of primitive Delphi types, and the list goes on.

Finally, having clean, pure Delphi classes allow you to extend them, like creating non-persistent properties, using pure object references to represent associations, etc. The following video gives slightly more details about that.




Introducing the myCloudData REST Client for Delphi & C++Builder

$
0
0

We are very excited to announce the launch of our new open-source myCloudData.net REST client for Delphi & C++Builder. The myCloudData REST Client is completely free and open-source and hosted on Github, this means that you can freely use or customize the code for your commercial or hobby projects.

Our goal was to provide you with an easy way of using the myCloudData.net service in all your applications, without having to worry about all the difficulties that come with integrating with a complex REST service.

The myCloudData REST Client takes care of handling the HTTP requests, the parsing of the JSON responses and the OAUTH2 authentication. All you have to do is drag the component on to your form and you can start using your cloud databases as they were local databases.

The library is developed from the ground up and is based on the REST technology that is included in RAD Studio 10.1 Berlin. It can be used with your Delphi, C++Builder, RAD Studio 10.1 Berlin IDE as-is, no need to install extra commercial libraries. There is a REST client for VCL applications (for Win32/Win64) and FMX applications (for Win32/Win64/iOS/macOS/Android)

To get you started, here are some highlights of commonly used patterns in consuming structured cloud data storage via myCloudData.net.

Some simple code examples

Creating a table

Typically, at the startup of your application, you'll want to check if the table you want to work with already exists on the current myCloudData account. The code example below does just that, it looks for the table on the Tables property of the myCloudData component and if it isn't found it will create the table with all the necessary fields.
var 
LContactsTable : TmyCloudDataTable;
begin
    // Search for an existing table
    LContactsTable := MyCloudData.Tables.GetTableByName('MyApplication_Contacts');

    if LTableName = nil then
    begin
        // Create the table
        LContactsTable := MyCloudData.Tables.CreateTable('MyApplication_Contacts');

        // Start adding your fields:
        LContactsTable.Fields.Add('ID', ftInteger);
        LContactsTable.Fields.Add('Name', ftWideString, 30);
        LContactsTable.Fields.Add('EmailAddress', ftWideString, 50);
        LContactsTable.Fields.Add('CountryCode', ftWideString, 2);

        // Save the fields to the myCloudData.net service
        LContactsTable.Fields.Save();
    end;

    // You can start working with the table here.

end;

Working with the entities

Once you have your table, let's add some data to it. The next example shows how you can insert a new entity and populate its fields.
var
LContact : TmyCloudDataEntity;
begin
    // Create the new entity on the table
    LContact := LContactsTable.Entities.CreateEntity();

    // Populate the fields on the entity
    LContact.SetValue('ID', 285);
    LContact.SetValue('Name', 'John Doe');
    LContact.SetValue('EmailAddress', 'johndoe@gmail.com');
    LContact.SetValue('CountryCode', 'USA');

    // Save the entity to the myCloudData.net service
    LContactsTable.Entities.Save;
end;

The following code shows you how to query the table and retrieve existing entities.
// Optionaly set the page size and index
LContactsTable.PageSize = 20;
LContactsTable.PageIndex = 0;

// Optionaly add one or more filter conditions
LContactsTable.Filters.Add('Name', coLike, 'John'); 
LContactsTable.Filters.Add('Email', coEndsWith, 'gmail.com', loAnd); 

// Optionaly add one or more sorting statements
LContactsTable.Sorting.Add('Company', soAscending); 
LContactsTable.Sorting.Add('Name', soDescending); 

// execute the query
LContactsTable.Query();

// now you can use the result of that query by accessing the Entities property
for LContact in LContactsTable.Entities do
begin
    ContactsListBox.items.Add(LContact.GetValue('Name'));
end;

Blobs

All the above examples work for both the free and the subscription accounts on myCloudData.net.
However, working with blob fields requires you to be connected with a subscription account.
To avoid unexpected behaviour, you'll always want to check if the current user can use the blob feature before actually creating or using a blob field.

This example shows how you can create a blob field in a table.
// Check if the current user can use blob fields
if MyCloudData.CurrentUser.CanUseBlobFields; then
begin
    // Add the field to the table
    LContactsTable.Fields.AddOrUpdate('Picture', ftBlob);
end;

Saving a new file to the blob field can be done as follows.
var
LPictureField : TmyCloudDataBlob;
begin
    // Fetch the Entities on the table
    LContactsTable.Query();

    // Get an entity by its ID
    LContact := LContactsTable.Entities.GetEntity(LEntityId);

    // Get the blob field 
    LPictureField := LContact.GetBlobField('Picture');

    // Save a new image
    LPictureField.FromFile('c:path	oyourimage.jpg');
end;


We invite you to start experimenting with these new free REST client components and we are very eager to learn how these will be used to build your creative & amazing apps with myCloudData.net and RAD Studio 10.1 Berlin.
Please take a look at the Github repository and let us know what you think!


Live Now: Intensive Delphi 2016 - The biggest online Delphi event in Brazil, for free!

$
0
0

(Este link em português)

Intensive Delphi 2016 is happening right now. It's the biggest online Delphi event in Brazil, and it's free for everyone! Already started on Monday, 19th and going on until 24th, it's six days full of sessions about the most different topics: Mobile development, Rest/JSON servers, Firemonkey, VCL, Beacons, Arduino, best practices, and many many more.

To access the conference, use the follow link: Intensive Delphi 2016 Official Link



Each day starts as early as 8 am local brazilian time, and goes on until up to 10 pm at night. Outside the official schedule for session streaming, sessions replays are provided in those alternative schedules. The chat windows is available for you to interact with speakers at specific session times, specially at night (brazilian time).

There will be sessions available in both Portuguese (most of them) and English.

More than 25 speakers and counting will be present at conference, including Marco Cantu, Jim Mckeeth and, from TMS Software, Wagner Landgraf with a session about TMS Business product line. The TMS Business session schedule is Thursday, 22th, 8 pm brazilian time (UTC-02:00) and Wagner will chat with attendees. Here is the full list of speakers in alphabetical order:

Adriano Santos
Alan Glei
Alan Victor (Bruto do Delphi)
Alister Christie
Amarildo Lacerda
Boian Mitov
Carlos Agnes (Tatu)
Emanoel Deivison
Jackson Gomes
Jim Mckeeth
Jonatan Souza
Jorge Eduardo
Kelver Merlotti
Kleberson Toro
Laercio Guerco
Landerson Gomes
Marco Cantu
Marcos Moreira
Marcus Vinicius
Mauricio Abreu
Newton Oliveira
Regys Silveira
Ricardo Boaro
Rodrigo Mourao
Samuel "Muka" David
Thulio Bittencourt
Wagner Landgraf (TMS Software)


My Top 10 Aurelius Features - #8 Lazy Loading

$
0
0

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

$
0
0

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;

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;

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, 
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;

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

$
0
0

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

$
0
0

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

$
0
0

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

$
0
0

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.


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.


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)">




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.



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.



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;


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:

                





TMS Aurelius and MVVM Design: an example

$
0
0

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.



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

$
0
0

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

$
0
0

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

$
0
0

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

$
0
0

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!

Viewing all 1006 articles
Browse latest View live


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