What’s new in TMS FNC UI Pack 3.4

There are a lot of great new features available in our FNC components and this blog will highlight the new additions to the TMS FNC UI Pack. If you want to check the improvements on TMS FNC Maps, click here.

For the list of fixes and improvements, you can check the version history, but two new components were added to the product as well.

TTMSFNCPassLock

TTMSFNCPassLock is an updated version of the FMX passlock in the TMS FMX UI Pack.
This component gives you the ability to add password protection to your application.
It’s not only possible to further customize the buttons and pattern, but also the ability to not show the length of your password.
Next to that you have the similar workings of the numpad and pattern layout and the learn mode to set a new password.

TTMSFNCControlPicker

The TTMSFNCControlPicker helps you to create a dropdown variant of your control.

This can be done with the ITMSFNCControlPicker interface and is implemented by default in the TTMSFNCTreeView, TTMSFNCTableView, TTMSFNCListBox and TTMSFNCListEditor.

It is possible to implement the interface in your own control, for more information regarding the necessary procedures and functions to implement, please check the documentation.
Some additional events are available, to mimic the basic mechanics of the interface without implementing it and to make the control even more customizable.

This is an example of the base implementation to retrieve the content that should be shown in the dropdown edit. It shows the number of times the button was clicked.

First create a new extended button class:

type
  TButtonEx = class(TButton, ITMSFNCControlPickerBase)
  private
    FCount: Integer;
    function PickerGetContent: String;
  protected
    procedure Click; override;
  public
    constructor Create(AOwner: TComponent); override;
  end;
 
{ ButtonEx }

procedure TButtonEx.Click;
begin
  inherited;
  Inc(FCount);

  if Assigned(Parent) and (Parent is TTMSFNCCustomSelector) and Assigned(Parent.Owner) and (Parent.Owner is TTMSFNCControlPicker)then
  begin
    //Update ControlPicker if assigned as control
    (Parent.Owner as TTMSFNCControlPicker).UpdateDropDown;
  end;
end;

constructor TButtonEx.Create(AOwner: TComponent);
begin
  inherited;
  FCount := 0;
  Text := 'Click this';
end;

function TButtonEx.PickerGetContent: String;
begin
  Result := IntToStr(FCount) + ' Clicks';
end;

The only thing left to do is creating the button and assiging it to a TTMSFNCControlPicker:

procedure TForm1.FormCreate(Sender: TObject);
begin
  b := TButtonEx.Create(Self);
  b.Parent := self;

  TMSFNCControlPicker.Control := b;
end;

Read More

Read More

Upcoming Miletus cross platform support

About 3 weeks ago we released TMS WEB Core v1.7 Ancona. One of the new features was Miletus, our new framework to create desktop applications with TMS WEB Core. It was exciting to see that many of you showed interest in Miletus, so we’ll take a look at what you can expect in the future.

What’s coming in TMS WEB Core 1.8

We launched Miletus with Windows 32-bit and 64-bit support, but our goal was already set from the beginning: a cross platform alternative that is based on TMS WEB Core. To make this possible, research work has already started before the TMS WEB Core v1.7 release. We are happy to share that as of today here in the labs, we can already target MacOS and Linux!
Starting from TMS WEB Core 1.8 you’ll be able to select the MacOS and Linux target. This will mean that you can create MacOS and Linux applications on Windows without an additional connection to the target systems! After the proper setup, you’ll only need to copy your created application to the operating system of your choice. Keep in mind that for distribution it’s recommended to sign your application and that can only be done on the target operating systems.

Why choose Miletus?

Miletus is not meant to be an Electron replacement, but rather something to co-exists next to our current Electron support as an alternative to those who want:
  • No NodeJS dependency
  • Smaller executable sizes
  • Less deployed files
  • More broad local database support
You can take full advantage of web technologies combined with native operating system level operations:
There’s a lot of native functionality exposed already. Access to the local file system, operating system menus and notifications, drag and drop functionality, global shortcuts just to name a few. We are always looking to extend the native support based on your feedback! 
You don’t necessarily need a DB backend running, you can easily connect to a local DB file or a cloud DB service just like in a VCL or FMX application! For cross platform targets, the following databases will be supported: SQLite, MSSQL, PostgreSQL, mySQL. This if of course only the beginning, we already have plans to expand the supported DB list!
The power of HTML5 and CSS3 is at your disposal. There are a huge amount of libraries and templates available for web applications that you can not only reuse in your Miletus application but with their help you can also create visually more pleasing user interfaces! 
And did you know? It’s easy to migrate your existing TMS WEB Core application to Miletus. Watch this hands-on video from our colleague Dr. Holger Flick, who explains the process in detail:
After the TMS WEB Core v1.8 release the next step will be to bring Miletus to TMS WEB Core VSC too. We already did some further research in this area, and our results are promising to bring a truly cross platform experience!
But that’s not the only long-term goal: based on the feedback we got, we’ll also look to add more DB support! 
As mentioned earlier, we have full control over this technology which means we can extend the palette of components and functionalities without depending on 3rd party solutions while maintaining the advantages listed above. We are eager to learn what you’d like to see in future versions!

Read More

Read More

Customer use case: bringing an FMX app to the web with TMS WEB Core

Introduction

In this blog article, we want to present you the story of Howard Sanderson from the company Star Analyzer. Howard converted in the past couple of months his cross-platform FireMonkey app to a TMS WEB Core powered web application and hereby eases the life of his customers tremendously.

 

Why and How I converted my Delphi FMX App to TMS WEB Core

After years of marketing a Delphi Windows/macOS version of my Star Analyzer program, I found that many clients wanted a web-based program which would run on any device, especially a tablet. They also wanted their data stored in the cloud so that several people could use the program at the same time. The macOS version produced by Delphi was often plagued with macOS incompatibilities, and neither version would run on a tablet. So I decided to take the leap to the web.

Should I use Delphi and TMS WEB Core or learn another programming language?

I looked at most of the current web programming languages, and took a short course on several of them. But because I’ve been using Delphi for 25 years I find that my brain is rather hooked on Delphi. In fact, I think that JavaScript and other web languages are totally incompatible with my brain. 
Another deciding factor was the library of 85 Object Pascal code files that I developed over the years for use with all my programs. I definitely did not want to rewrite my library from scratch. I am rather fond of it. My Star Analyzer program included another 100 Object Pascal code files which all use my library files.
Given the above conditions, I decided it would make sense to use TMS WEB Core to write my new web-based program in Object Pascal rather than to start from scratch in some other language. While there was a bit of a learning curve, the final program is  quite lovely I think. You can see Star Analyzer by going to my website, www.StarAnalyzer.com, scrolling down the page a bit, and clicking the “Run The Program” link.

Eight reasons I decided to use Delphi and TMS WEB Core

       
  1. I do not have to learn a new programming language. JavaScript and my brain are incompatible.
  2. I can reuse hundreds of library routines in Delphi.
  3. The new program can also look and act like a familiar Windows program for my customers.
  4. It runs on any web browser and almost any device.
  5. If you change the program, users have immediate access to the new code. You don’t have to send them emails or guide users through new install procedures.
  6. They do not have to fight anti-virus programs when installing program updates.
  7. They can run the program on multiple devices at the same time.
  8. Customer data is stored securely in the cloud and not lost when their computer dies.

Converting my existing code to TMS WEB Core

So far I have not needed to write a single line of JavaScript or HTML code, and about 80% my existing Delphi code works nicely with the WEB Core components. Some of 20% of new code I had to write was relatively straight forward, and some was a bit tricky. I’ll talk about the tricky parts a bit later in in this Blog.

Converting my existing FMX forms to TMS WEB Core

As we all know, the components on the forms talk to your code through their event handlers. Theoretically then all I would have to do is create new forms, drop FNC and WEB Core components on the new forms, and use hook them up to most of my existing code.  Not too much work, or so I thought, but it turns out it was not quite that simple.
If you look at Star Analyzer for the web you’ll see that it is built around tab controls. Click Data Entry and Data Analysis button and you’ll find there are 15 tab controls on the main form and 18 tab controls on the tabs on the main form. The original program was built around one large and complicated main form that held all the components for all 33 tabs, but the program worked nicely, and was easy to code and trouble shoot.
In converting my program to WEB Core, I first duplicated this tab structure using the TTMSFNCPageControl. The new layout looked just like the old layout, and was easy to work with in programming, but it would not compile. It turns out that you can’t compile a program with thousands of components and 33 tabs on one main form. It chokes the compiler.

Using Hosted Forms to reduce the complexity of browser pages

The solution was to use a TTMSFNCTabSet (which has no pages, just tabs) and to use a hosted form as shown in the TMSDemos\Web\Basics\Formhosting demo provide by TMS. The text and number of tabs on the main TabSet are changed in code, and the controls that used to be on the tabs are now on a Hosted Form.
In the image below the area outside the red box is the main form, while the area inside the red box shows one of the 23 different Hosted Forms. The advantage of Hosted Forms is that each web browser page has a small number of components and on it. 
This Case statement below shows how the hosted forms are called and created by the program.
  case SubFm of  // there are 23 hosted forms that I think of as SubForms
    sfProp     : MF.MainSubFm := TmfPropSubForm.CreateNew(MF.pnlMainHost.ElementID, @AfterSubFmCreate);
    sfFinBuy  : MF.MainSubFm := TmfFinBuySubForm.CreateNew(MF.pnlMainHost.ElementID, @AfterSubFmCreate);
    sfFinSell  : MF.MainSubFm := TmfFinSellSubForm.CreateNew(MF.pnlMainHost.ElementID, @AfterSubFmCreate);
   end;

Creating Pop-up Forms

In addition to the Hosted Forms mentioned above, every program needs pop-up forms as shown below. Forgive my wife and my cat in the images. This is just a demo after all. You can import photos and even take photos on your iPad with the TMS components. See the TMSDemos\Web\Basics\Multiform demo for details on creating pop-up forms. 
Why I chose Google Firestore as my online database

My original Star Analyzer program used a local SQL database and the FMS FNC Cloud Pack to allow users to backup and restore their data to Dropbox so that they could use multiple computers, one at a time, with their data. This confused a lot of users. Not a good solution.

After spending many days looking at all the cloud databases available, and after playing with various TMS cloud data storage solutions, I ended up choosing the Google Firestore and the TMS WebFirestoreClientDataset as my cloud data storage solution. 

Without the TMS Firestore components I never would have chosen Firestore. If you go to https://firebase.google.com/
and begin reading the hundreds of pages of Firestore documents you may find it overwhelming as I did. Or perhaps not. But I wanted a relatively simple solution, and did not want to learn another programming language. I know that you can write Java Script routines that work with Firestore, but as I said, Java Script is incompatible with my mind.
Beyond ease of use, I was looking for an inexpensive cloud database solution. Look at https://firebase.google.com/pricing
you’ll see that Firestore is free at first, and then inexpensive as your needs increase. You can write 20,000 documents and read 50,000 documents per day for no charge, and after that it is only $0.06 per 100,000 reads. Given my customer database, and the fact that each customer will never have more than 100 documents in their database, I’ll probably never have to spend a penny on cloud storage.

Learning to use the TMS TWebFirestoreClientDataset

It is probably best to start by reading the TMS WEB Core PDF help file, which is well written and fairly comprehensive. Next you should look at the TMS Blog entries on Firestore. And finally, you can look at the Demos\Web\DBBackend\Firestore as a simple example to learn the basics. 
At first you may find the lack of SQL query capability in Firestore to be a bit disturbing, but you’ll find that there are ways around most of the limitations. One limitation of Firestore is that the maximum document size is 1 Meg, so if you are storing photographs you’ll need to shrink them a bit. And that brings me to my next topic, hints and tricks in using WEB Core.

TMS WEB Core Hints and Tips

As you work with TMS WEB Core you’ll find little tricks that are not emphasized in the documentation. Here are a couple that I’ve found useful.
Tip 1: Selecting and Resizing Images
There are two images controls that I use with WEB Core, the TTMSFNCImage and the WebImageControl. The TTMSFNCImage can show images in their proper Height and Width Ratio (which I like), while in the TWebImageControl the image always takes the shape of the control on the form (which I don’t like). 
However I can resize images with the TWebImageControl and not with the TTMSFNCImage. Since the Firestore database can’t handle images larger than 1 Meg, you must resize all images larger than that. The best way to see this is in a demo program, which you can download from www.StarAnalyzer.com/TMS/ImageSel.zip and you can view the demo from https://www.StarAnalyzer.com/TMS/ImageSelDemo.
If you click the button or the image on the main form, a pop-up Image Select Form is shown. See the TMSDemos\Web\Basics\Multiform demo for more information on pop-up forms.
On the image select form, you can select a JPG if you are on a computer, and you can even take a photo if you are in an iPad. The image select form uses both an FNCImage (to see the image in actual height/width ratio) and an TWebImageControl to allow me to shrink JPG’s that are larger than 1 Meg. The image resizing is done during the TWebImage OnLoaded event. 
Curiously, the length of the resized images depends on the physical size of the TWebImageControl on the page. See the code in the zip file for details. I spent days trying to find a useable image resizing routine that did not distort the height/width ratio, but finally gave up and resorted to the TWebImageControl resizing. If anyone has a nice resizing routine, I would appreciate a copy.

Tip 2: Handling asynchronous behavior

I started writing the Star Analyzer for the web before the many async/await functions were introduced in TMS WEB Core and I’m eager to investigate and start using these. But well, when writing applications running applications in the browser, one cannot change the fact there are many asynchronous processes happening in the browser all for the sake of keeping the application at all times responsive. This is also the case in Star Analyzer when opening databases. Some delays occur when reading and writing to Firestore databases. In Star Analyzer we have to open three databases when the program starts up: Agents, Images, and Properties. This takes around seven seconds. This is how I handle the startup.

  1. Show the WaitMessage
  2. Call OpenServiceFilter for each database
  3. Start the WebTimer
  4. Wait for the WebTimer OnTimer event
  5. Check to see if all databases are open
  6. Keep looping with the timer until all are open
  7. Stop the WebTimer

The code will look something like this:

{----------------------------------------------}
procedure TMF.EnableWaitMsgAndStartupTimer;
{----------------------------------------------}
  procedure dbOpenDBSvcFilterStr(CDS: TWebFirestoreClientDataset;
                                 const FldName, Condition, Data: string);
  begin
    dbClose(CDS);
    CDS.ClearSortFieldDefs;
    CDS.ClearServiceFilters;
    CDS.AddServiceFilterCondition(FldName, Condition, Data);
    dbOpen(CDS);
  end; {dbOpenDBSvcFilterStr}

{--- EnableWaitMsgAndStartupTimer ---}
begin
  WaitMsg.Show;

  {--- agent ---}
  dbOpenDBSvcFilterStrEq(FAgent.CDS, xagAgentIDStr, cfv.SelectedAgentIDStr);

  {--- agent photo and logo ---}
  dbOpenDBSvcFilterStrEq(DM.imCDS, ximAgentIDStr, cfv.SelectedAgentIDStr);

  {--- agent properties ---}
  dbOpenDBSvcFilterStrEq(FProp.CDS, xprAgentIDStr, cfv.SelectedAgentIDStr);

  StartupTimer.Enabled := true;
end; 

We now loop while waiting for the three databases to all be open. Once all are open, we stop the timer, hide the wait message, and continue with the program.

{----------------------------------------------}
procedure TMF.mfStartupTimerUp(Sender: TObject);
begin
  //Note: DM.IsOpen uses the CDSAfterOpen event to set values true

  if not DM.IsOpen(Agents.CDS) then exit;
  if not DM.IsOpen(Images.CDS)   then exit;
  if not DM.IsOpen(Properties.CDS)  then exit;

  {--- stop timer and hide wait message ---}
  StartupTimer.Enabled := false;
  WaitMsg.Hide;

  //All datasets are open. Proceed with code
end; 

Conclusion

Well, that’s probably enough for now. Bottom line, my Star Analyzer program now runs perfectly in any web browser on most any device, my users don’t need to download and install program updates and fight antivirus programs, and their data is available from any computer they or their assistants wish to use. I’m happy. They are happy.
Feel free to contact me at Howard@StarAnalyzer.com if you have questions that I can answer, or hints to share with me about programming with TMS WEB Core.

Your story here?

Did you develop equally exciting projects meanwhile with TMS WEB Core? Your fellow Delphi developers for sure will want to hear & learn from it! Be in touch and we can work on bringing your success story here.

Read More

Read More

High performance multi-feature grid

Intro

The multi-device, true native app platform The FireMonkey® framework is the app development and runtime platform behind RAD Studio, Delphi and C++Builder. FireMonkey is designed for teams building multi-device, true native apps for Windows, OS X, Android and iOS, and getting them to app stores and enterprises fast.

source: https://www.embarcadero.com/products/rad-studio/fm-application-platform

FMX (FireMonkey) released in 2011 and shortly after we delivered a first set of components. Today, we want to show you the TTMSFNCGrid component, a high performance multi-feature grid

Features

Below is a list of the most important features the TTMSFNCGrid has to offer. The features are not limited to this list, but this will give you a quick insight on what we offer to be able to create an application that visualizes your data in a grid structure in FireMonkey.

  • Column Persistence
  • Fixed cell single and range selection
  • Autosizing columns / rows on double-click
  • Highly configurable and flexible grid
  • Various cell types available and built-in as well as support for custom cell types
  • Fixed columns left and/or right, fixed rows at top and/or bottom.
  • Column & row freezing
  • High performance virtual mode
  • Several selection modes: single & multi cell, column, row, distinct cell, row, column
  • Cells with support for HTML formatted text, hyperlinks
  • Editing with range of built-in editor types and capability of using custom cell inplace editors
  • Cell merging and splitting
  • Grouping support with summary rows, and group calculations such as average, sum, min, max, custom calculation…
  • Filtering with optional auto filtering via dropdown
  • Different cell layouts for different cell states
  • Read-only and/or fixed state per cell configurable
  • Single column sorting, indexed column sorting, grouped column & indexed column sorting
  • Pixel and cell scrolling modes
  • Keyboard and Mouse handling customization: tab, enter, insert, delete key handling
  • Column and row dragging and sizing
  • Cell controls such as checkbox, radiobutton, button, bitmap, progressbar etc…
  • Configurable touch scrolling optimized for iOS / Android
  • Banding
  • Clipboard support
  • HTML Export
  • PDF Export
  • Excel Import / Export via the TTMSFNCGridExcelIO
  • Find and replace functionality
  • Separate ToolBar Popup

Learn More!

Want to learn more about what the TTMSFNCGrid can do? Here is a video that highlights some of the above features through a demo application.

Download & Explore!

The TTMSFNCGrid component is part of the TMS FNC UI Pack, which, on top of FMX, also offers the ability to write your code once and target other frameworks (VCL, LCL and WEB). You can download a full featured trial version of the TMS FNC UI Pack and start exploring the capabilities of the TTMSFNCGrid component.

Stay tuned!

The TTMSFNCGrid is the fifth and last component of a series of components that is covered to empower your FMX (FireMonkey) developments. We started the series with a general overview of the most important components that we have to offer, followed by the TTMSFNCRichEditorTTMSFNCPlannerTTMSFNCTreeView and the TTMSFNCKanbanBoard. Keep an eye on our blog post for more exciting news coming up for the FMX framework and FNC in the form of a whole new platform!

Read More

Read More

Firestore server-side filtering in TMS WEB Core v1.7

To create a high performance web client application, a lot of things need to be taken in account. But foremost, when you create a modern SPA (single-page-application) architecture web client application, you will want to look at optimizing the communication of the application to your database back-end. In case you use the Google cloud based infrastructure as your database back-end, you will want to perform as little as possible requests and ensure that the data involved in these requests is as compact as possible. The server-side filtering capabilities of Google Firestore allow you to easily achieve this, especially with the new built-in support for it in the TWebFirestoreClientDataSet in TMS WEB Core.

Recalling loading and filtering features of TClientDataSet in classic VCL

If you have used a TClientDataSet in Delphi VCL, you already know that the component provides an in-memory table that can be manipulated easily and efficiently. But if there are a large number of records in a database, loading all of them in the TClientDataSet needs to be avoided. With traditional Delphi TClientDataSet, if the records are loaded through a DataSetProvider that supports queries then you can change those queries to load limited records based on a criteria. This approach greatly reduces the memory overhead of the TClientDataSet, since fewer records need to be stored in memory. 
Compare this with another option of local filters, also from standard Delphi VCL, where the number of records visible in the dataset can be reduced by using local filtering options. But that does not reduce the number of records in memory. It only restricts access to the records filtered out.
In Web Core, we give a solution similar to  DataSetProvider where certain filtering criteria can be applied at the Firestore to reduce the number of records fetched on opening the dataset.

New server-side filtering features in TWebFirestoreClientDataSet

The new server-side filtering features purpose is to limit the number of records fetched from a Firestore collection. Consider the problem when the Firestore collection has a large number of records. Loading all of them at once is not a good idea due to the memory overhead of an in-memory table in the TClientDataSet. 

In the new release of TMS WEB Core, the Firestore ClientDataSet component provides new features to apply filters to the data obtained at the Firestore end.
Important background information
Before we look at the details of each filtering method, it is necessary to understand some core principles.

1) Method names begin with “AddService”

There are several Firestore related filtering methods available in the Firestore ClientDataSet component.  They are named starting with “AddService” indicating that they are applied at the Firestore Service level. This is to differentiate them from any local filtering methods already available in the standard ClientDataSet.

2) Firestore filters are not as flexible as SQL queries 

The primary purpose of the Firestore filter methods is to limit the number of records fetched on opening the dataset in order to reduce the memory overhead. 
Don’t expect the Firestore filters to be as flexible as an SQL query for your data processing requirements. There are many restrictions and limitations as you will discover later. For an exanple, please see “Limitations and Gotchas” under AddServiceFilterCondition method later in this article. 
If you have advanced filtering requirements then in addition to the Firestore filters, you should use the local filtering features of the ClientDataSet for the advanced filtering needs.

3) Understand their mapping to the Firestore Filter API

It’s necessary to understand that each of the methods descibed in this article maps to a particular kind of query on the Firestore side, for example AddServiceFilterCondition maps to a “where” query on Firestore. 
The mappings are important to keep in mind so that you can refer to the proper Firestore documentation to look for more details on what works and what doesn’t. We can not possibly describe/repeat all the Firestore specific gotchas in the TMS WEB Core documentation.
For example, the description of the method AddServiceFilterCount in this article mentions the following mapping:
The “maps to” means that internally the component uses “Firestore limit query.” So if you are a curious type and want complete details on “Firestore limit queries,” please go to the Firestore documentation on that keyword.

4) Many Filters depend on the current Sort order that you need to set up before calling the filter

For some of the Firestore filters, you need to sort on the field being used. This can be done by using the calls ClearSortFieldDefs and AddSortFieldDef. Note that this sorting happens at the Firestore end.
Here is an example of setting up a sort on the age field.
fireStoreCDS.ClearSortFieldDefs;
fireStoreCDS.AddSortFieldDef(
                   'age', // field name
                   true); // is ascending


5) The Filtering Methods

AddServiceFilterCount method (Maps to: Firestore “limit” query)
You can limit the number of records obtained by this method on an Open. You need to set it before calling Open.
Example:
The following filter when set up will fetch only 100 records on open.
fireStoreCDS.AddServiceFilterCount(100);
Usage notes:
  • If you have set up a sort order, they will be first 100 records in that sort order.
  • How do you get the next 100 records? Use the method AddServiceFilterContinueAfterLast described next.
AddServiceFilterContinueAfterLast method for pagination (Maps to: Firestore pagination)
This is the method that sets up the pagination to get the next set of records. You need to call Refresh after this. Then you can call Refresh again and again to get the next set of records or pages.
For example, if you call it after the above example of AddServiceFilterCount and call Refresh, it will fetch the next 100 records. Subsequently, just call Refresh to get the next set and so on till you get an empty dataset.
Usage notes:
AddServiceFilterContinueAfterLast can also be used after the AddServiceFilterRange method described later. But it also requires to clear filters and set a new range. Please see the Filters demo for the actual code. 
AddServiceFilterCondition method  (Maps to: Firestore “where” query)
Use this method to specify a where condition filter. Setting the filter activates it on the next Open or Refresh. 
Requirement:
If you are using a Sort Order by using a AddSortFieldDef call, it must be on the same field that you are using in this filter.
Examples:
1. Get records where field “status” has the value “New”
fireStoreCDS.AddServiceFilterCondition('status', '==', 'New');
2. Use more than once to specify multiple conditions ANDed but for the same field. 
fireStoreCDS.AddServiceFilterCondition('age', '>', 18);
fireStoreCDS.AddServiceFilterCondition('age', '<', 65);
3. For an OR condition, use the “in” operator. For example, to get records where field “status” has the value “New” or “Pending”
fireStoreCDS.AddServiceFilterCondition('status', 'in', TJSArray.New('New', 'Pending'));

Limitations and gotchas:
  • Date/Time fields require special code. This is described in Web Core documentation of Firestore.
  • This filter maps to Firestore “where” that is much limited as compared to SQL’s “where.” For example, one of the rules says, you can add more than one where filters, provided they are on the same field and if a Sort Order is being used, the Sort Order must be on the same field. To give you another example, the example 2 above works as AND. But if you want to use a similar OR condition, it’s not easily possible. People have written articles on such problems that you can find on the Internet by searching for Firestore where query problems with proper keywords.
  • It’s not possible to describe all possible rules and usage of Firestore “where” filter in this article or even in the Web Core documentation. For more details, please refer to the Firestore document “Querying and filtering data” (search Google on this) and refer to the section on “where” queries. 
AddServiceFilterRange method (Maps to: Firestore filters startAt, startAfter, endAt, endBefore)
Use this method to specify a Firestore “start” and/or “end” condition on a value that refers to the current sort field set by AddSortFieldDef call. Setting the range filter activates it on next Refresh or Open call. 
Requirement:
The value passed works on the current sort field. So you must have defined a sort order by AddSortFieldDef call.
Example:
Suppose you have defined the sort on the “age” field by AddSortFieldDef
fireStoreCDS.ClearSortFieldDefs;
fireStoreCDS.AddSortFieldDef("age", true);
Now you want to start at age 18 and end at age 65. You will use 2 filters.
fireStoreCDS.AddServiceFilterCondition(frStartAt, 18);
fireStoreCDS.AddServiceFilterCondition(frEndAt, 65);
Limitations and gotchas:
  • Date/Time fields require special code. This is described in TMS WEB Core documentation of Firestore.
ClearServiceFilters
Clears all the Firestore filters set up so that all the records are obtained on the next open or refresh.

New Firestore Filtering Demo

A demo is available that shows use of the above filtering methods. You will find this demo under Demo\Services\Firestore.
There are 2 parts to this demo, an import utility that imports 500 JSON objects to a Firestore collection as a prerequisite for the demo and then the Demo itself that filters the collection when obtaining data.
Preparing for the Filter Demo: Build and Run the Import Utility
In the Firestore Filters Demo folder under “Demo\Services,” you will find a project ImportTestData. 
Please follow these steps:

  1. Open the project TMSWeb_ImportTestData
  2. Build and Run the project
  3. Enter values for API Key, AuthDomain and ProjectID if they are not automatically filled by your previous usage of any Firestore demo. 
  4. Click on Import Test Data.
This should import 500 objects from the JSON file in a new collection called SalesData. You can verify that the data is imported to such a collection in the Firestore Console. Also, in case you want to recreate this collection due to any problems, you can delete the colleciton in Firestore console and import again.
Running the Filters Demo
Please follow these steps:

  1. Open the project TMSWeb_FirestoreFilters.
  2. If you didn’t change the Collection name when importing, just Build the project. Otherwise, please search for CUSTOMIZE comment and use the same collection name here in which you imported the data above.
  3. Now run the project.
  4. Click on the Filters items one by one and see how they work.
  5. To look at how the actual filters are used in code, please see the procedure setupExampleFilter.

Summary

  • First, we recalled the Loading and Filtering features of TClientDataSet from Delphi VCL. This was necessary to understand the memory limitations of TClientDataSet.
  • Next, the article stressed on some background information that is necessary to understand before going into the Firestore filtering methods.
  • This was followed with the actual description of the Firestore filtering methods along with examples, usage notes and limitations.
  • Then we looked at the Firestore Filtering Demo that uses the filtering methods of the component.

Of course, everything you learned here applies to TMS WEB Core for Delphi or Lazarus as well as TMS WEB Core for Visual Studio Code.

What’s next

In the next part 4 of this series, we are going to take a look at the new Async methods to perform database operations in code. In particular, we show you how to wait for the result of the previous operation before performing the next operation in a world of async Firestore updates.

Read More

Read More

GExperts bug: CTRL+V on FMX form designer inserts into secondary editor window

I got a bug report for GExperts and Delphi 10.4 that’s really curious: When a secondary editor window is open in the IDE and the FMX form designer is active, trying to insert a component from the clipboard into the form inserts the textual description of that component into the editor windows instead. I could immediately reproduce this but finding the culprit took quite a bit longer. Observation 1: It does not happen for the VCL form designer. Observation 2: It only happens, if you use CTRL+V to insert the component. The form designer’s context menu entry works fine. Observation 3: Even disabling all experts in GExperts did not solve this problems… Until you restart the IDE, then it’s gone, even if you then enabled the experts again… Until you restart the IDE again which brings it back. After a lot of trial and error I found that the cause are two of the GExperts editor experts: Goto Previous Modification Goto Next Modification Disabling these experts and restarting the IDE solves the problem. These are rather simple experts that only add entries to the editor window’s context menu for a functionality that already is part of the IDE. I added them to make that functionality more visible, and because I could. Since Delphi 10.3 I had to use a workaround to still be able to add entries to that menu because apparently it is being recreated in the OnPopup event. I think this code somehow activates the menu entries or their associated actions even if the editor window doesn’t have the focus. So for now until I find a real workaround: If you have this problem, disable these two experts. (The workaround might be to remove these experts altogether. They aren’t that useful anyway.) If you want to comment on this blog post, you can do so in the corresponding topic in the international Delphi Praxis forum.
Read More

Turbo Boost Your Delphi Knowledge – Become a Docwiki Ninja Warrior

I’ve made a commitment to learn FireMonkey. My flagship software product, Zilch Standard, turned 30 years old in 2021 and I still don’t have a macOS version. I’ve got macOS consumers who buy my Windows® software and then email asking if there’s a version that runs on their mac computer. This inevitably leads to me issuing a refund. So, I have a pretty strong incentive to learn FireMonkey.

“I feel like I’m sitting in the cockpit of an airplane.”

I tried going down the FireMonkey learning path before but unfortunately I didn’t get very far. Learning FireMonkey makes me feel like I’m sitting in the cockpit of an airplane. There’s so many things that are unfamiliar. The scope of it all is overwhelming. There’s so much to learn. I don’t know where to look first. What about the help? It’s just an [F1] key press away!

I don’t know about you but I get frustrated at the built-in help that comes with Delphi? Does this sound familiar? You’re frantically trying to figure something out… pressing [F1] all over the place, and hopelessly rummaging around through Delphi’s built-in help. Sometimes it’s great and gives you what you exactly what are looking for. Often times you are left feeling like you just read a bunch of cryptic tea leaves. 

Where do you turn at this point? The Facebook Delphi groups? Stackoverflow?  Your stash of Delphi books? Delphi’s dockwiki?
In the past I’ve rarely thought to use Delphi’s docwiki. In my mind I felt like it was the same rehashed [F1], cryptic leaves stuff. Well, that changed last night. 
It turns out, I wasn’t using the dockwiki in a meaningful way. I figured out how to exploit the value of the docwiki. I’m going to show you how to become a docwiki ninja warrior.

“I’ll show you how to become a Delphi Docwiki Ninja”

It all started last night when I wanted to learn more about FormFactor. I wrote a simple FMX application that displays the ClientHeight, ClientWidth, FormFactor.Width, and FormFactor.Height in the OnResize event handler. I was curious why the FormFactor values never changed as the form was resized, so I wanted to learn more. That’s when I highlighted FormFactor in the Object Inspector and pushed [F1] .

This brought up the built-in help for FormFactor. This is one of those cryptic tea leaves help reference.

This wasn’t very helpful. I may have done some googling to learn more but couldn’t find anything that talked about FormFactor. What it is? How it’s used? Why it’s used? So I posted my question to StackOverflow
Someone commented and said “Please look at the documentation. It seems to concern iOS only, and changes according target device selection.”
How did he find that docwiki page? That’s not the docwiki page I found. In fact I couldn’t find the dockwiki page referenced in StackOverflow comment. Turns out I didn’t understand how to use the dockwiki. I was stuck in the API library and couldn’t got out!

I was stuck in the API library and couldn’t get out!

That’s when I discovered how to become a Docwiki Ninja Warrior. This takes less than a minute to setup and I believe it will save you hours looking for information about Delphi that is relevant to what you are looking for. For illustrative purposes I’m sticking with my original pursuit of FormFactor.
Step 1: From inside the IDE click Help > RAD Studio Docwiki

Step 2: This opens the RAD Studio docwiki page in your default browser.
Step 3: Right-click on Library Reference > Open link in new tab 

Step 4: This opens the Library docwiki page in a new browser tab.
Step 5: Right-click on Code Example > Open link in a new tab.

At this point you should have three tabs in your browser each dedicated to separate docwiki sections. And now the fun begins.
Step 6: Enter FormFactor in the search box for tab 1 RAD Studio and press [Enter]. I’m horrible at spelling so I usually just copy and paste the value I need. I just highlighted FormFactor in the IDE code editor and pasted it in the search box. 

Step 7: Switch to tab 2 Library docwiki page and paste or enter FormFactor in the search box and press [Enter].

Step 8: Switch to tab 3 Code Examples docwiki and paste or enter FormFactor in the search box and press [Enter].

“So, what did I learn about FormFactor?”

FormFactor is only used used when you are creating an iOS application. This is awesome. I learned enough about FormFactor to satisfy my current need. Because I’m focused right now on learning how to use FireMonkey to create desktop applications for Windows and macOS, FormFactor is not relevant to my current situation. This lets me know I can skip a thorough investigation about FormFactor for the time being. It also lets me know that ignoring FormFactor at this time is okay since it does not apply to desktop applications for Windows or macOS. I don’t need to be concearned about FOMO (fear of missing out).

However, if FormFactor was something I was interested in, the three different docwikis provide ample links to related, relevant, information in one convenient location. 
Oh yeah, make sure to play around with the “Advanced” link on the special search results pages.
There you have it. I am so glad I stumbled upon this. It will surely be very helpful in my quest to learn FireMonkey. 
Enjoy!
Semper Fi,
Gunny Mike

Read More

Read More

SAPI (Microsoft Speech API) problems with the IDE

Every few months or so someone sends me an email telling me they’ve speech-enabled their application with SAPI (the Microsoft Speech API) after having read my old coverage (specifically that for SAPI 5.1) from conferences in 2002 and before. It’s always good to hear that stuff you’ve worked on is being found useful, even long after you did it, in this case frighteningly close to 2 decades ago (Ͼ˳Ͽ)..!!!

Sometimes the communications are asking how to do specific things with SAPI – unfortunately those are typically a dead end, as I haven’t used SAPI in anger for a long while.

Sometimes, though, people are stuck on the basics and I was recently contacted by someone with a fairly current version of RAD Studio saying they couldn’t get started at all. It turns out that the current version of SAPI, SAPI 5.4, cannot be imported into RAD Studio!

Uh-oh. Time to investigate…

The steps to import SAPI components into the IDE is as follows (and is documented here):

  • Choose Component, Import Component… (as mentioned in the documentation)
  • Select Import a Type Library and press Next
  • Choose the Microsoft Speech Object Library that is defined in sapi.dll:
  • Press Next and choose a target Palette Page:
  • Press Next, select Install to New Package and press Next again
  • Now choose a value for Package name (and optionally for Description) and press Finish:
At this point the package will be created and a type library import unit is added to it and the IDE will try to build the package. Immediately something is flagged up:

Click Yes and the package will start building proper. This is where it all falls apart:

Hmm, is there a massive FUBAR in the type library importer? Sure looks like that could be the case….
However, upon closer inspection the issue actually comes up thanks to the SAPI type library defining its own versions of the already-defined-in-Delphi interfaces IStream and ISequentialStream. In the SAPI versions they have extra methods, references to which then fail to compile thanks to those methods not being imported.

Why are those ‘known’ interfaces not imported? Well, the idea is to avoid ambiguity with having multiple definitions, but that’s not important as… we can override this omission!

In your RAD Studio bin folder (e.g. C:\Program Files (x86)\Embarcadero\Studio\21.0\bin) you will find a file called tlibimp.sym. This is the configuration file for the type library importers (both the one in the IDE we just used and also the command-line utility TLibImp.exe). The content of this configuration file affect the way type libraries get imported to help cover various trouble areas. In this case we need to remove some settings to get the SAPI type library imported.

Here is a part of tlibimp.sym:

;;===================================================================;;
;; Names listed in this section are skipped by the importer         
;; Built-in Interfaces, such as IUnknown and IDispatch are listed
;; here
;;===================================================================;;
[BuiltInInterfaces]
{00020400-0000-0000-C000-000000000046}=IDispatch
{00000000-0000-0000-C000-000000000046}=IUnknown
{0000000C-0000-0000-C000-000000000046}=IStream
{0C733A30-2A1C-11CE-ADE5-00AA0044773D}=ISequentialStream
We need to comment out the IStream and ISequentialStream lines to get a successful import. Once those 2 lines have semicolons inserted at their start we can try again.

Remove the emitted import unit SpeechLib_TLB.pas from the package still open in the IDE, then delete that unit from disk and close the package project.

Now you can go through the steps above again, but this time instead of selecting Install to New Package you select Install to Existing Package. After pressing Next you press Browse and locate the original DCLSAPI54.dpk project file, which by default will have been saved in the default Delphi projects folder (Embarcadero\Studio\Projects within your Documents folder tree).

This time the package will build and you will be told of the component wrappers now installed in the IDE:

If you want to import the SAPI type library from a RAD Studio Command Prompt you can run this command:

tlibimp -P -Yh+ -Yr+ -HpsActiveX C:\WINDOWS\System32\Speech\Common\sapi.dll

Note that the SAPI 5.x sample applications from the 2002 conference paper have been updated and are available along with an updated import package at these URLs:

Read More

Read More

What’s coming in TMS WEB Core v1.7 Ancona


The new version v1.7 of TMS WEB Core has
been in development for about 6 months by now. Many of its features were
already in development in parallel to v1.6. And yes, our team already is working
on v1.8! It will not come as a surprise to you that in v1.7 there are new
game-changing features in TMS WEB Core also.

Those who have been following the TMS WEB
Core development since the first version TMS WEB Core v1.0 Brescia will know
that we name the releases after cities along the famous historic race “MilleMiglia”. To be more precise, the legendary race of 1955. And as such, after we
visited the city Pesaro with v1.6, for v1.7 we land in Ancona. The historical
meaning of the word “Ancona” is elbow which is commonly associated with the
shape of the coastline. After the ‘elbow’ Ancona, there are new sights towards
the more southern coasts of Italy.

Enough history! Let’s bring an overview of
what our team has been working on for TMS WEB Core v1.7 Ancona.

1) Components wrapping browser API for local file access

The W3C consortium proposed an API forlocal file access from Web browser applications and Google Chrome implements it
already. Given that Microsoft uses the Google Chromium engine, it is also available
in Microsoft Edge Chromium. With TMS WEB Core, you can take a head start, explore,
and start using this with its three components today:

  • TWebLocalTextFile
  • TWebLocalBinaryFile
  • TWebLocalFolder.

These components allow you to directly open
text and binary files from the local file system as well as traverse the local
file system’s folder structure from a Web application. Of course, for security
reasons, the users have to give their consent first.

2) Popup menu component and popup menu support in components

In TMS WEB Core, we offered the regular
TWebMainMenu since its inception and now we completed this trend with the new
TWebPopupMenu. It works very similar to a Windows VCL TPopupMenu. Simply drop a
TWebPopupMenu on your Web forms and assign it to control.PopupMenu to obtain an
automatic context menu for controls.


3) USB device access


The times that software developers thought
you could never use a Web application for controlling your machine’s hardware
are officially over. We already introduced support for Bluetooth with our
TWebBluetooth component, and with this release we add two new components
TWebUSBSerial and TWebUSBHID that allow you to write applications communicating
with locally connected USB devices using a serial protocol or the HID protocol.
This opens up a whole new field of applications that can be implemented using Web
technologies.


4) TWebStringGrid & TWebDBGrid extensions

We added a whole range of new grid features
in TWebStringGrid and TWebDBGrid. There are now:

  • Methods to insert & remove rows
  • A range of different inplace editor types
  • Cell merging and cell splitting
  • Loading and saving to streams
  • Loading from a stringlist with CSV data
  • Direct access to grid data as TJSArray
  • Add checkboxes to the grid

5) Async methods

There is no way around it in the Web
browser, there are different APIs that can only be used in an asynchronous way.
The reason for this is very clear: Always guarantee a responsive UI even when
lengthy operations are taking place in the application.

Many developers struggle with implementing
sequential logic for processes that occur asynchronously. We already offered
anonymous methods that can be used to handle results of methods asynchronously,
but, in v1.7, we added a whole range of async methods to classes. With a simple
await() construct around an async method, you can write your code as-if it were
synchronous and sequential, but, behind the scenes, the browser still handles
it asynchronously and keeps your UI responsive. The components to perform HTTP(S)
requests for example, load data from a URL, load images from URL, etc… now
all have async equivalents making you write code that is cleaner and consequently
easier to maintain.

var
  ms: TMemoryStream;
begin
  ms := TMemoryStream.Create;
  try
    await(boolean,ABinaryFile.LoadStream(ms));
    ms.Position := 0;
    webmemo2.lines.LoadFromStream(ms);
  finally
    ms.Free;
  end;
end;

6) Miletus framework

This is probably the biggest feature of TMS WEB Core v1.7! Miletus is a framework for creating native desktop applications with Web technologies. It permits to create wonderful and modern user-interfaces using (and in many cases reusing) HTML/CSS templates.

Still, it allows to run as a desktop application and to access desktop features normally reserved for a native desktop app. This includes:

  • local file access
  • operating system menu
  • drag & drop interaction
    with the operating system
  • access to the taskbar
  • access to local databases (SQLite, MSSQL, PostgreSQL, mySQL, MS Access)
  • so much more… 

This first introduction of Miletus in TMS
WEB Core offers the capability to create Win32 and Win64 native single EXE file
applications with a size below 10MB. And in the near future, we will add macOS
and Linux to that.

Stay tuned for another blog with a more
detailed overview of the Miletus features. An additional benefit of Miletus is
that we developed this framework from the ground up as opposed to a similar
framework called Electron that is from a 3rd party. This means that for the
future, we have full control to design any feature set we want for Miletus.

7) TWebSocketClient method added to send & receive binary data

When communicating with a web socket
server, TWebSocketClient can now directly send & receive binary data
whereas in previous versions this had to be sent as Base64 encoded string data.

8) TWebForm extended

We added more flexibility to the TWebForm. This includes:

  • Option to have a close button in the caption
  • Property to choose whether a shadow border is used or not
  • ElementCaptionClassName property added to allow the use of CSS for the caption
  • OnDOMContentLoaded event added, that signals when the browser loaded the entire DOM content
  • OnHashChange event added to handle browser back & forward buttons

9) New server-side filtering + multi-tenant support in TWebFireStoreClientDataSet

We have also significantly improved
TWebFireStoreClientDataSet. Now, TWebFireStoreClientDataSet supports to create
more flexible and more performant Web client applications using Google’s
Firestore as the backend for data storage. In the new version, it is possible
to specify server-side filters. This facilitates not only multi-tenant
scenarios but also increases performance by minimizing data returned from the
server.

10) Numerous smaller extensions & improvements to various components & IDE integration

Not only was the TMS WEB Core framework improved
in almost any corner, the IDE integration got further fine-tuning as well. The
capability to use environment variables in the compiler path with the $()
syntax was added. The same is possible with custom compiler directives. And
finally, also the pas2js compiler & RTL were updated to the latest version
v2.0.4.

Planning

The first step is that we will release the
beta version of TMS WEB Core v1.7 in the next few days to all TMS ALL-ACCESS
users and registered users of TMS WEB Core. We expect the upgrade process
should be smooth and painless as we paid a huge amount of attention to
backwards compatibility. This is proven by the fact that we did not have to make
any modifications to the meanwhile over 100 demos included. However, we want to
put the v1.7 beta into your hands first and listen closely to your feedback.
That allows us to apply further polish where needed.

After this beta period, TMS WEB Core v1.7
Ancona will be officially released, and our team will continue to work hard on
the next milestones.

TMS WEB Core for Visual Studio Code v1.3

The new version v1.3 of TMS WEB Core for Visual Studio Code is also around the
corner. The major new feature of v1.3 will be extensibility via 3rd party
components with a package system and with this, the whole portfolio of
TMS FNC components will also become usable at design-time in Visual Studio Code. The
TMS WEB Core framework will be at the same level as TMS WEB Core v1.7 for
Delphi & Lazarus. The only feature that will not yet be included in TMS WEB
Core for Visual Studio Code v1.3 is Miletus support. That is reserved for v1.4
and with this, it is expected to already bring Miletus for Windows, macOS, and
Linux.

TMS WEB Core v1.8

There are several ongoing new developments
for TMS WEB Core that we cannot reveal yet, but it is clear that v1.8 will come
with Miletus support for macOS and Linux. We already have proof of concept
versions working in the lab, but further work is needed before this is
considered “feature complete”. This will very likely be the case in v1.8.

Get started today!

The only constant in software development is change. Web technologies open up exciting new capabilities for us Delphi, Lazarus, or Object Pascal developers in general. It allows us to create with RAD component-based techniques and a strongly-typed object-oriented language no-deploy web applications. Further, we may create PWAs for iOS and Android that can be installed and run offline when needed. Best of all, we do not need to conform to Apple or Google store censorship. Alternatively, you can create  cross-platform desktop applications with Electron or Miletus at the same time. 

We are of course curious to hear what you like the most about TMS WEB Core v1.7 Ancona or what you wish to see in future versions of TMS WEB Core! We look forward to discussing all these great milestones with you!

Webinar

If you want to see the new capabilities in TMS WEB Core 1.7 Ancona demonstrated live and ask questions, we have organized this opportunity for you! Attend our free webinar on April 8, 2021, from 15h00 to 16h00 UTC (17h00 – 18h00 CEST).  Register for the webinar here.

Read More

Read More