Modal Search Dialog Expert Beta 2 (D2010 and fixes)

I have fixed some bugs in the Modal Search Dialog Expert, added support for D2010 and here is now Beta 2.

For more information about the Modal Search Dialog Expert check my first Modal Search blog post.

This is the list of the changes:

  • Added D2010 support
  • Fixed RegEx focus bug (search did not consider the option “BRIEF regular expressions” and treated it always to be True)
  • Last search text is now shown in Find dialog, when “Find text at cursor” is disabled
  • Fixed Repeat Search “Not found” behavior for the case when “Show all search matches” is enabled
  • Match count is now localized and updated when repeating a search

The IDEs default “Not found” behavior since D2010 is a bit ill especially with “Show all search matches” enabled, because the IDE knows if there is any search result in the file. With steps this should be more understandable:

  • start the IDE
  • check if the editor option “Show all search matches” is enabled and if not, enable it and restart the IDE
  • check if the editor option “Auto search wrap around” is enabled and if yes, disable it
  • create a new console app
  • place cursor into the middle of the source
  • search for “foo”
  • -> message “Search string ‘foo’ not found” is shown
  • press F3
  • -> wrap around message “Restart search from the beginning of the file?” is shown
  • press Yes button
  • -> cursor is now on top of the file and message “Search string ‘foo’ not found” is shown

If “Auto search wrap around” is enabled then the behavior is a bit different

  • start the IDE
  • check if the editor option “Show all search matches” is enabled and if not, enable it and restart the IDE
  • check if the editor option “Auto search wrap around” is enabled and if not, enable it
  • create a new console app
  • place cursor into the middle of the source
  • search for “foo”
  • -> message “Search string ‘foo’ not found” is shown two times and cursor is now on top of the file
  • place cursor into the middle of the source
  • press F3
  • -> message “Search string ‘foo’ not found” is shown once and cursor is now on top of the file

In this Beta I have fixed the Repeat Search behavior for the case when “Show all search matches” is enabled. The behavior with and without “Auto search wrap around” after pressing F3 is now

  • -> message “Search string ‘foo’ not found” is shown once

I make use of the fact that with “Show all search matches” the IDE knows if there are matches anywhere in the file. If the match count is zero then I show myself the “Search string ‘foo’ not found” message and tell the IDE the search was successful. That prevents the unnecessary wrap around message “Restart search from the beginning/end of the file?” and the cursor does not jump to the top of the file.

Posted in IDE | 2 Comments

Modal Search is back from vacation!

I do not like the quality of the IDEs modeless search feature and you might remember my blog post “Scotts Valley get that search right!” from last October. There I have quoted more or less my co-worker with that “Every text editor can do that better. Why did they changed that?” and at that time he did not use Delphi XE2 daily. That changed in January and sometime ago he said something like “Are there two edits in the search panel in Replace mode?”. He knows that in Replace mode there is still a modal dialog and that is inconsistent.

I had a short look at some development tools and this is a short and incomplete development tools lists with the information if the search and replace features are modal or modeless.

Tool Version Search Replace
Delphi till D2009 Modal Modal
Delphi since D2010 Modeless Modal
Eclipse Helious Modal Modal
SharpDevelop 3.2 Modal Modal
Visual Studio 2008 Modal Modal
Visual Studio 2011 Modeless Modeless

Well you see there is no other tool than Delphi in that incomplete list with that Search/Replace in inconsistency. Another problem with the modeless search is that not all search options are visible even if that gets better with higher resolutions. The following screenshot shows the search panel for the “Default” IDE desktop layout with different resolutions and for the US and the DE version. I hope you do see that not all search options are visible in any case. If not all are visible one has to click with the mouse cursor on the chevron to get access to the “invisible” options. Is it possible to show the chevrons popup menu using keys? I do not think so.


Search Panel comparison (click for full size)

While I am at the search panel – Did the search panel add any new features to the IDE apart from the fact that the search dialog is now a modeless panel? Yes it did, but who really cares about them?

The new implicit and explicitly added functionality is:

  • implicit: one can still see the text to find and the options after executing the search
    -> no one cares about this
  • explicit: there are buttons to search forward, to search backward and to restart
  • explicit: the match count is shown and if the search has been restarted

About two weeks ago I have had a look into the IDEs search basics, it was very easy to replace the search panel with a dialog and to perform a simple search and I decided to look deeper into it. After testing, some issues and improvements the modal search is now back with my new expert so far called Modal Search Dialog Expert. It does not 100 percent behave as Delphi 2009 and earlier, because the meaning of the F3 key has been changed. In D2009 and earlier F3 did always search into the direction you did select in the search dialog, but since D2010 F3 does always search forward and SHIFT+F3 has been added for backward search. Now the direction group box is disabled in the modal search dialog, but I had enabled it in early versions of the modal search dialog and did run into the problem that searching stopped working. The reason was that I had used SHIFT+F3, that toggled the direction (the modal search dialog does use the IDEs internal search options) and there was just nothing above the cursor to find. When the search panel starts a search with enter then the direction is always set to forward and thatswhy I have never seen the problem there. The modal search dialog looks now like this:

Modal Search dialog

When you do run a localized IDE then this dialog is almost completely localized (only the caption is not localized in the FR and JA locale) – I just read the captions from the DFM resource of the replace dialog. As said above the search panel did add the feature that the match count is shown and since the panel is not longer visible anymore I did add the match count to the right hand side of the editors “statusbar” as you can see on the following screenshot:

Editor “Statusbar” with match count

Note I have used the x resolution 1280 for that screenshot and that means there is usually much more space between the sub editor views and the match count. Right now the match count is not localized, but I guess you do understand what it is trying to tell you. The match count needs a little bit more work, because it remains visible when you switch to another file and so on.

Unless the editor option “Auto search wrap around” is enabled the IDE shows a dialog when you hit (SHIFT+) F3 on the last or first match. That is a regular dialog, but looks like an old message box:

The IDEs default wrap around dialog

For Windows 6.x I have replaced this with a Task dialog and this looks like this:

Using TTaskDialog for the wrap around message

This looks much better to me on newer OS. Maybe Embarcadero thought the Task dialog would limit them, requires too much testing or this is a left hand vs. right hand problem, because TTaskDialog has no confirmation icon as you can see in the following screenshot:

Object Inspector showing possible values for TTaskDialog.MainIcon

The missing confirmation icon is not related to my filter and maybe the missing icon limited the developer and he decided to create an own dialog, but who knows. I know that my co-worker reworked some of our message helper functions to use TTaskDialog, I know that confirmation works there and the solution is just 99.

There is one unintended feature in my expert and that is that it does fix unintentionally without any changes at least the search bug QC 95578.

Setup:

  • Download the setup for XE and XE2 from here
  • Follow the instructions in the setup
  • Start the IDE

I hope the expert helps to improve your search experience!

Posted in IDE | 24 Comments

The better Insight for Delphi Compiler QA people

I have not found a better subject for this post, but however I do a lot Delphi compiler QA and especially in the Delphi 2010 field test I have created a large number of test cases out of thousands of lines of code. When reducing, reducing and reducing the amount of unrelated code the compiler errors help me to find the code that can be removed. That means for example that I do remove some methods in a class definition, invoke compile and the compiler in connection with the editor lead me to the first method implementation that needs to be removed too. The compiler generates also errors for the other methods, but in order to find out what to remove too I need to click onto the messages in the message pane or press compile again. That simply takes too long, do not tell me about Error Fail<-<-<-<-Insight and I wish I would have implemented already about three years ago what you see on the following screenshots.


Code Editor highlighting hints in blue and warnings in yellow


Code Editor highlighting errors in red
(there is no contrast control especially for [F1] and [F2] yet)

I am doing this right now as a personal favor and prerequisite for further Live Blame improvements. The Delphi compiler quality got much better in the last years, also a lot users do provide simplified test cases and so I have to simplify big “test cases” currently not that often. However everytime I have done I wished to have that editor enhancement, but writing the enhancement takes much more time than simplifing a test case does nor can you estimate how long it will take to write the enhancement or if it will be successful at all. Simplifying a bigger test case may take between 15 minutes up to one hour, but so far I guess I have invested six hours into that project. I do not have statistic on the durations for the test case creations and it is anyway better for me not to know how many thousands of hours I have invested into Delphi (QA).

Right now this editor enhancement is pre alpha and not available for download, but to make this sure – this is not supposed to become an Error Insight replacement – it is not supposed to do anything else than showing the compiler messages of the last compile attempt in the editor. However the current Error Insight is a hopeless case (in german I would say “hier ist Hopfen und Malz verloren”) and I hope it is getting better with the future Delphi Compiler written in Delphi. Barry Kelly indicated that in the “Delphi Birthday Webinar Replay with David I and Special Guests” at about 01:03:45 that the future Delphi Compiler is written in Delphi and it may power Error Insight. Allen Bauer indicated in the same webinar at 00:29:26 that he is too implementing stuff in Delphi for the Delphi compiler. BTW, I do know that “new” or “future” Delphi Compiler is confusing for some users, because for example there is already something new in the XE2 release – the compiler backend for the Win64 target is something completely new. It is written by Tagawa-San (Yooichi Tagawa), but I do not know if this is already written in Delphi nor have I tried to find that out. The frontend of the Win32, Win64 and OSX32 compilers and the backend of the Win32 and OSX32 compilers are “just” maintained and enhanced versions of the native Delphi compiler that exists since years (since Delphi 2?).

I guess you have seen on the screenshots the icons on the left hand side of the compiler messages. Due all former work for the compiler message drawing and the screenshot (test case) for QC 81121 in my blog post Some QC requests need your votes back in October 2010 it took me less than ten minutes to implement a initial version of a solution for another QC report. This report is QC 74097: Prefix compiler messages with a glyph by Anders Melander. Well the border of the icons does not yet look nice and I have already added the icon to an imagelist with 32-bit color depth. :-(
Another feature request to consider, but to be implemented into a separate window, is QC 67540: Support separate columns for compiler messages (file, line, msg type, message, etc.) by Erik Berry (the GExperts maintainer).

Last but not least – no that was not a post about creating compiler test cases and at this time such a post is not on the horizon.

Posted in IDE | Leave a comment

How not to write SQL or using DECODE and f(index)

I do write SQL statements and PL/SQL at work and the first also when I work on the JEDI VCS server, but I am not an expert in that area compared to my knowlegde in Delphi for example. Given someone of a company developing professional database tools writes SQL statements – do you expect these statements to make use of all the database possibilities to achieve the best goal? I do not expect that. This is just because no one is an expert right from the start, almost every company tries to save money and employs also people without expert knowledge, everyone has bad days or “in the available time was no more quality possible”.

Even if I am not an expert maybe the following solution for a fictive requirement does help you some day.

Fictive requirement

We do store the amount of downloads of all our tools, updates, 3rd party vendor tools and user contributions in a database. For all the 3rd party stuff, user contributions and our own free stuff we want to show the amount of downloads to the user to indicate the popularity. The downloads are shown in lists in a web interface and for our own tools and updates we do not want to show the amount of downloads as this might be useful information for our competition.

This is fictive and so I do not want to speculate about the “Why” and I even do not think that these numbers are accurate – someone might download something multiple times (yes one could make sure it is only counted once), but someone else downloads it and shares it with his friends and how does this affect the numbers?

Solution

Before looking at solutions it is necessary to show the existing, but fictive data structure and some sample data. FREE = 1 indicates a download where the number can be shown. The data structure is kept very simple – in reality it could be more than one table due normalization. I am using Firebird for the example.

CREATE TABLE DOWNLOAD
(
    ID             INTEGER,
    NAME           VARCHAR(100),
    FREE           INTEGER
      CONSTRAINT CKC_DOWNLOAD_FREE 
      CHECK (FREE IN (0, 1)),
    DOWNLOADAMOUNT INTEGER,
    CONSTRAINT PK_DOWNLOAD PRIMARY KEY (ID)
);
 
INSERT INTO DOWNLOAD(ID, NAME, FREE, DOWNLOADAMOUNT)
VALUES(1, 'Product A', 0, 500);
INSERT INTO DOWNLOAD(ID, NAME, FREE, DOWNLOADAMOUNT)
VALUES(2, 'Trial B', 1, 1500);
INSERT INTO DOWNLOAD(ID, NAME, FREE, DOWNLOADAMOUNT)
VALUES(3, '3rd Foo', 1, 3000);
INSERT INTO DOWNLOAD(ID, NAME, FREE, DOWNLOADAMOUNT)
VALUES(4, 'Hotfix C', 0, 2000);
INSERT INTO DOWNLOAD(ID, NAME, FREE, DOWNLOADAMOUNT)
VALUES(5, '3rd Bar', 1, 100);

With the following simple query one gets the following plain result

SELECT ID, NAME, DOWNLOADAMOUNT AS DL FROM DOWNLOAD
ID | Name      | DL
---------------------
 1 | Product A |  500
 2 | Trial B   | 1500
 3 | 3rd Foo   | 3000
 4 | Hotfix C  | 2000
 5 | 3rd Bar   |  100

In order to hide the download amount in the output for the web you could just do output “-” as amount when FREE is not 1. As Delphi snippet this could look like this

  if qrDOWNLOADFREE.AsInteger = 1 then
    Text := qrDOWNLOADDOWNLOADAMOUNT.AsString
  else
    Text := '-';

Well that requires to retrieve the FREE column from the database. Unless you need FREE for something else you could let the database do part of the work and let the database return either an “invalid” amount like -1 for downloads that are not free or the state NULL. For NULL the SQL statement does look like this (-1 is similar – just replace NULL by -1)

SELECT ID, NAME, DECODE(FREE, 1, DOWNLOADAMOUNT, NULL) AS DL 
FROM DOWNLOAD

and the Delphi snippet like this

  if not qrDOWNLOADDOWNLOADAMOUNT.IsNull then
    Text := qrDOWNLOADDOWNLOADAMOUNT.AsString
  else
    Text := '-';

Both solutions do fulfill the requirement. Do they not?

Yes, they do.

However it is worth another look. Given the user has the possibility to sort the list in the web interface by the column of their choice – What do you think happens when the user can sort by the download amount column? The output would look like this if you would just order by DOWNLOADAMOUNT

ID | Name      | DL
---------------------
 5 | 3rd Bar   |  100
 1 | Product A |    -
 2 | Trial B   | 1500
 4 | Hotfix C  |    -
 3 | 3rd Foo   | 3000

The requirement was

…for our own tools and updates we do not want to show the amount of downloads as this might be useful information for our competition.

Well the actual amount is not shown, but the user does know that he sorted by the download amount and can conclude that “Product A” has been downloaded between 100 and 1500 times and “Hotfix C” between 1500 and 3000 times. The more downloads are available with similar popularity the smaller the ranges for the values get and the more precise the information for the competition is. The competition can assume from that numbers that you have not sold “Product A” 100000 times. I guess this renders the attempt to hide the number as waste of time and also as something that causes the users asking themselves unnecessary questions. Furthermore this may cause a little bit bad impression as there seems to be something to hide whatever it costs.

What could one do to “hide” the number completely?

The answer is using DECODE also in the ORDER clause or SELECT from SELECT. The statements would look like this and is at the end something a framework could do automatically

SELECT ID, NAME, DECODE(FREE, 1, DOWNLOADAMOUNT, NULL) AS DL 
FROM DOWNLOAD
ORDER BY DECODE(FREE, 1, DOWNLOADAMOUNT, NULL)
SELECT * FROM
(
SELECT ID, NAME, DECODE(FREE, 1, DOWNLOADAMOUNT, NULL) AS DL 
FROM DOWNLOAD
)
ORDER BY DL

The result looks like this

ID | Name      | DL
---------------------
 1 | Product A |    -
 4 | Hotfix C  |    -
 5 | 3rd Bar   |  100
 2 | Trial B   | 1500
 3 | 3rd Foo   | 3000

Given sorting using DECODE causes an unacceptable slowdown (I do not think it does), then you could add a function based index for that virtual download amount field. Function based indexes are a very neat thing, because they can speed up things without the redundancy that an additional field would create. For the download amount the statement for the function based index would look like this

CREATE INDEX IDX_DOWNLOAD_DL ON DOWNLOAD
COMPUTED BY (DECODE(FREE, 1, DOWNLOADAMOUNT, NULL));

So that was my little “lesson” about DECODE and function based indexes. No, I do not plan regular posts on SQL and database related stuff. My domains are Delphi and Version Control and you can so quickly find the answers with your prefered search engine that I would just waste time that I do not have. This issue just caused me a big headache that I had to blog about it. I guess some readers do know or find out what caused me the headache.

Posted in Database, SQL | 4 Comments

Version Insight Plus Beta 8 (Find in [modified] Files)

I have fixed some minor issues, added some minor improvements, added “Find in Files” support as a new Plus feature and here is finally Version Insight Plus Beta 8. This setup is for XE and XE2.

This is the list of the changes:

  • [Svn] Added Blame Diff options
  • Commit: Tweak: Perform state flush after Revert, Add and Resolve
  • Improvement: File states: States can now be cleared on Close All
  • Menu: Added Revert on file level
  • [Svn] Commit View: Fixed error “Target changelist name must not be empty” when pressing ESCAPE or entering nothing in the “Create Changelist” dialog
  • Commit View: improved Files listview performance for a lot files
  • Commit View: Tweak: when a selected item is checked/unchecked then check/uncheck all other selected items as in TortoiseSVN
  • Added new Plus feature “Find in Files” support

“Find in Files” support

Back in late November last year I was looking for something in the files which I was currently working on. While doing so I thought it would be good if I could perform the search with the IDEs “Find in Files” feature instead of using Total Commander. I have looked into that topic and it did not take me that long to find out how “Find in Files” works in general, but implementing the feature was a bit more complicated.

What the feature is all about is that Version Insight can provide the “Find in Files” feature with a list of files that should be used as “Where” for the search. So far the “Where” in the IDEs “Find in Files” dialog has four entries and with Version Insight Plus it has now the two additional entries “Search modified files in project” and “Search modified files in project group” as you can see in the following screenshot.


“Find In Files” dialog with the two additional entries “Search modified files…”

When selecting one of these two new entries then the file list of the current project or project group is passed to the installed version control systems that support the new IOTAProVersionControlSearchFileFind interface. The version control system managing these files is supposed to return all the files of that list where the file state is either modified, added or just normal, but the file is opened in the Code Editor and is modified. The file states are right now taken from the file state cache and with the improvements in that area in this Beta this is especially for Git and Mercurial much faster than retrieving the file states again. (In the early days of that feature I retrieved the file state for every search and for bigger projects that took longer than the actual search did.)

Apart from showing “Searching: Getting files[...]” in the “Searching” tool window on the bottom of the right hand side before the actual search starts and the icon for the search result tab there are no other differences to the “Search all files in project[ group]” “Where” entries. That means the search itself is done by the existing “Find in Files” implementation and so do not blame me for the bugs in it. A known issue is for example that searching for non-ASCII characters (e.g. german umlauts) does not find something unless the file is already open in the Code Editor or uses UTF-8 encoding. There are at least six QC reports for this and the master report is QC 88114.

The mentioned icon for the search result tab, which you can see as well in the following screenshot, is only used when using the two new “Where” entries. For all other four “Where” entries there will not be an icon and so you know directly if the search was performed with or without the help of Version Insight.


“Find in Files” search result tab for a search performed with the help of Version Insight

“Close All” and the file states

This time I have looked into monitoring meta data in these directories like .git and .hg to detect file states changes due actions in other version control clients, but unfortunately that did not worked out. ReadDirectoryChangesW is not supposed to detect each and every change to a file and so I have decided to implement an alternative. When you enable “Clear files states after Close All” in the Environment Options for a version control system then all cached file states are cleared when you call “Close All”. Note “Close All” is also implicitly performed by actions like opening a project or creating a new one and the option is disabled by default to preserve the current behavior. When enabling this option then you can refresh the file states in the IDE after an external action like Commit by calling “Close All” and re-open the project (group) afterwards. I hope this helps too.

Posted in DelphiSVN | 7 Comments

Platforms Expert for XE2 Beta 2

Back in October last year I have released Project Manager Platform Utils for XE2. Meanwhile Blaise Thorn and I made some minor fixes and improvements, decided to rename the expert and here is now Platforms Expert Beta 2. This download contains now a setup.

This is the list of the changes:

  • Fixed: occasional exception when closing a project
  • Fixed: project rename (name did contain configuration and platform)
  • Fixed: missing command for “Target Platforms” in localized IDE versions
  • Added: Compile commands
  • Added: The platform names can now be customised via a registry key

Here is again the full list of the features of the Platforms Expert including screenshots:

  • Platforms are now sorted in the IDE
  • Added bitness to OSX32 target display name
    (“32-bit OS X” [EN] is more future-proof than just “OS X”)
  • Show active configuration and platform for project nodes in the Project Manager

  • Show active configuration for “Set active configuration(s)” toolbutton dropdown menu
    (when all projects have the same active configuration)

  • Show active platform for “Set active platform(s)” toolbutton dropdown menu
    (when all projects have the same active platform)

  • Added “Build All For” and “Compile All For” to Project Manager popup menu of project group node
    (like the default “Build All” command only visible when there is more than one project)
  • Added “Build All For All Platforms” and “Compile All For All Platforms” to Project Manager popup menu of project group node
    (like the default “Build All” command only visible when there is more than one project)

  • Added “Build” and “Compile” command to Project Manager popup menu of the target platforms

  • Added “Build All” and “Compile All” command to Project Manager popup menu of the target platforms root node

  • Added “Add…” command to Project Manager popup menu of folder nodes (QC 81304)

  • Custom platform names

The reg file snippet for these names looks like this:

[HKEY_CURRENT_USER\Software\Embarcadero\BDS\9.0\PlatformsExpert]
"Rename.Win64"="Windows/x64"
"Rename.Win32"="Windows/x86"
Posted in IDE, Open Tools API | Leave a comment

Handling some XE2 issues Part #1

I am using XE2 since it is available to me, but the stuff I am doing at home is different from the stuff at work and also different from the stuff my co-worker is doing. We have switched to XE2 almost two weeks ago and thatswhy we discover some more XE2 issues now. Here are some of the issues we discovered and I try to provide some information that may help you to help yourselfs when you are affected by the same issue. If this information is not enough for you – I am sorry, but I cannot and will not provide “works for everyone” solutions here. I am glad that we solved the issues for us. There might me more posts about XE2 issues and so I have added the “Part #1″ to the subject. This time the topics are:

and apart from the last issue these issues are new in XE2. There are not that much QC reports mentioned in this post, but Embarcadero knows already about most of the mentioned issues.

TDBNavigator glyphs

The TDBNavigator got new glyphs in the XE2 release and the following screenshot shows the difference between XE and XE2.


Delphi XE TDBNavigator at designtime without a TDataSource assigned


Delphi XE2 TDBNavigator at designtime without a TDataSource assigned


Delphi XE flat TDBNavigator at runtime in browse mode


Delphi XE flat TDBNavigator at runtime in edit mode


Delphi XE2 flat TDBNavigator at runtime in browse mode


Delphi XE2 flat TDBNavigator at runtime in edit mode


Delphi XE2 flat TDBNavigator at runtime in browse mode with non default colors

The opinions of the team members that used the XE2 build of our application were different regarding this new glyphs:

Well these icons does not look bad, but which meaning do have the colors?

I see blue, aqua, a mixture between red and orange, green and red. My co-worker started with the following guess

blue are harmless actions, red are harmful action

well but is adding a new record something bad or posting a record necessarily something good. Hey Embarcadero please explain!

It is hard to see the difference between the enabled and disabled Post button!

I have to add here that this team member is affected by partial red-green color blindness. (in german it is “Rot-Grün-Sehschwäche”)

The shadow looks ugly with non default colors. Haven’t they still fixed alpha transparency issue.

This is from co-worker, he does have non default colors and we have had looked into an alpha transparency issue with TSpeedButton sometime ago with 2010 or XE. I think due to other more important stuff I have never looked if there is already a report for this and so on. As you can see above on the last screenshot the shadow looks very ugly with non default colors.

In order to fix the issue I have replaced the resources in $(BDSLIB)\win32\release\dbctrls.res with the resources from the XE release and copied it to the win64 folder as well. Well XE does not have resources for the new ApplyUpdates and CancelUpdates buttons, but we do not use them. Other options would be to patch TDBNavigator.SetButtonGlyph at runtime or to create a TDBNavigator descendant and override TDBNavigator.SetButtonGlyph. In the IDE are still the new icons, but that does not bug us and if we want to have fancy new TDBNavigator glyphs we can have them when we start using VCL styles.

The good thing about the XE2 TDBNavigator is the new property Kind and now one can have a vertical navigator out-of-the-box.

TRect scope issue (Delphi lib recompiling issues)

The TRect record and other records do now have some additional methods and properties. TRect for example does have the properties Width and Height. At first that does sound like something good, but in combination with the “with” statement it can be something very bad and may cause failures in your application. Since the reason for a failure was a TRect scope issue did I want to identify such scope issues by the help of the compiler. In order to achieve that I have changed the following piece of code in $(BDS)\source\rtl\sys\System.Types.pas from

  TRect = record
  ...
    // changing the width is always relative to Left;
    property Width: Integer read GetWidth write SetWidth;
    // changing the Height is always relative to Top
    property Height: Integer read GetHeight write SetHeight;
  ...
  end;

to

  TRect = record
  ...
    // changing the width is always relative to Left;
    function Width: Integer; deprecated 'Check TRect.Width scope';
    // changing the Height is always relative to Top
    function Height: Integer; deprecated 'Check TRect.Height scope';
  ...
  end;

Since System.Types is part of the Delphi core RTL it was necessary to recompile the RTL. That can be done with the batch file $(BDS)\source\rtl\buildrtl.bat, which is provided since XE2 Update #2. Even that step was not free of issues for me – the build process did not found the zlib C object files. I had only Delphi (Pro) installed at work and since I was sure that I had successfully rebuild the RTL at home I tried to add C++Builder too via the installers upgrade function, because C++Builder installed yes/no was the difference between the installation at home and at work. The upgrade somehow failed, because bcbwin32.7zip could not be downloaded correctly and even before I have started the setup it was in the download folder. I had to abort the installation, my Delphi installation was completely broken and I have reinstalled Delphi and C++Builder. Afterwards the batch file recompiled the important RTL files and stopped with a problem in a Winapi DirectX unit, but did not care about that. Then I tried to compile our application, the compiler told me that there is a problem with the TeeChart units and that is completely okay – when you want to repeat the steps you need the source of all the components and there is no source provided for the TeeChart Embarcadero edition. TeeChart was only used in a few units and I just removed it in this units. Then another Delphi installation issue did bite me – the C object files for Vcl.Imaging.jpeg are not delivered even not when C++Builder is installed, I did use the files from Delphi XE and faked three missing methods.

Side note: I hate such delivery issues and over the years I have told Embarcadero several times the automation steps that would catch almost all source or lib file delivery issues. Great for you Embarcadero that you have all the files you need.

Well back to topic – afterwards I continued the attempt to compile our application and actually found some TRect scope issue, but not in our code. I found one issue in Vcl.DBGrids in the WriteText procedure and some other issues in 3rd party components. This WriteText issue might be only in theory an issue, because the code branch might never be execute – is there a way to make the following “if” be False?

  I := ColorToRGB(ACanvas.Brush.Color);
  if GetNearestColor(ACanvas.Handle, I) = I then

How get the TRect scope issues detected by the change?

Actually my changes detect the usage of the new TRect properties, but for code that compiled with pre XE2 releases it means in almost any case that there is a TRect scope issue. When TRect.Width or TRect.Height are accessed then the compiler puts out the warning

[DCC Warning] Foo.dpr(line): W1000 Symbol 'Width' is deprecated: 'Check TRect.Width scope'

and that tells you that there is supposed to be a problem. To make sure that there is actually no problem in our code I have just placed some sort of elephants in Cairo.

“Package Foo.bpl can’t be installed because it was created with a different version of Delphi or CBuilder.”

That the Delphi reinstallation did not make me too angry is just a result of the fact that I have build an installer that does setup the IDEs paths, compiles and installs the component packages and compiles the library DCUs for the components. However we had not installed all the necessary components in the IDE from the very beginning and once when adding some missing components I forgot to add a package to the requires section of the package with our own components and received the message

“Package Foo.bpl can’t be installed because it was created with a different version of Delphi or CBuilder.”

when starting the IDE.

Hey I have just compiled all the packages with XE2!

Actually the message is trying to say that our package did contain an unit that is also included in another package. So when you receive that message it maybe actually because of a duplicate unit issue. The best advice I can give you here is that you try to compile the package in the IDE and hope it tells you which packages needs to be added to the requires section.

I have not checked with XE2 versions before Update #3, but at least XE showed the message

Cannot load package ‘%s.’ It contains unit ‘%s’, which is also contained in package ‘%s’

and so this is regression. That message is still in System.SysConst.pas in XE2.

BTW, it is “cannot” and “C++Builder” and not “can’t” and “CBuilder”.

F12 performance

We do use data modules and in contrast to XE switching between Code and Design for them is very slow. It seems to be the slower the more components are on a form, frame or data module. Since fields on a data module are components too a data module can have a lot components. It is also the slower the more components are installed into the IDE and the time to switch seems to be the product of the amount of installed components and the amount of components on form, frame or data module. I have debugged the IDE with the IDE and have hit F12 to break into the debugger to find out what the IDE is doing when switching between Code and Design and yes F12 is the key to switch between Code and Design and when running under the debugger I have used the menu to switch. (Note the F12 debugger hotkey requires Andy’s “Delphi F12 Debug Hotkey support” expert when using Windows 6.x.) Whenever I hit F12 I saw the method “@Comppalmgr@TComponentPalettePageItemDelegate@CheckValid” in delphicoreide160.bpl. That lead me without a look into that method to the conclusion that the IDE is filtering the available components. That also explained why setting the ClassGroup property improves the switch times. Without that set the switch took about ten seconds for our largest data module and after setting it to Vcl.Controls.TControl it took about three seconds. That is still pain and so I have looked into “@Comppalmgr@TComponentPalettePageItemDelegate@CheckValid”. I did not try to find out how it is actually working, because understanding assembler is not my easiest exercise, but what I understood was enough to fix the issue for our needs. The solution has a lot disvantages, but they do not affect us because we do only develop for Windows with the VCL and seeing TButton on the Tool Palette or Component Toolbar for data modules is absolutely no problem for us. The rewritten version looks like this and brings for us the speed back to the XE level.

procedure NewCheckValid(Self: TObject; const AIntf1: IInterface;
  const AW: WordBool; AIntf2: IInterface);
var
  ComponentPalettePageItem: TObject;
  PIntf: IOTABasePaletteItem;
begin
  ComponentPalettePageItem := TObject(PDWord(Integer(Self) + $30)^);
  if Assigned(ComponentPalettePageItem) and
    Supports(ComponentPalettePageItem, IOTABasePaletteItem, PIntf) then
    PIntf.Visible := Assigned(AIntf1) and 
      (Pos('TComponentBased.FMX', PIntf.IDString) = 0);
end;

The advice I can give you regarding this issue is setting the ClassGroup property of the data module.

Excel automation

One of the first bug reports that came in for the XE2 build was about the export to Excel. It failed with “Add method of Workbooks class failed”. I know that there is a dataset to Excel function in the JVCL (ExportDataSetToExcel in JvgExport), I have tried it and it worked. The difference between our code and the code in the JVCL is that we pass xlWBATWorksheet as parameter. After removing the parameter our code worked too, but now there were three worksheets instead of one. I did remember a thread in embarcadero.public.delphi.oleautomation, which I have had “read” a few days ago and did remember something about a change in XE2 regarding the passed parameter type. I have changed the following code from

XLApp.Workbooks.Add(xlWBATWorksheet);

to

XLApp.Workbooks.Add(Integer(xlWBATWorksheet));

and afterwards it worked with that Integer typecast. The thread is “EOleException on XE2 Update 2 (works fine under XE)” and this particular message from the helpful Bruneau (Jean-Marie Babet) explains the problem and provides workarounds. Some hours after I have made the fix Bruneau posted a promising message in this thread that there might be an option (System.Variants.DispatchUnsignedAsSigned) in the next update which enables the old behavior. Meanwhile there is a section about the problem and this option in the preliminary Update #4 release notes. My suggestion is that you test your Excel automation code properly and in case of problems use one of the workarounds provided. In case you would have to touch too much calls then hope that the DispatchUnsignedAsSigned is actually in the Update #4 release.

Open File At Cursor

We do have not added our own (component) library units with the “in” clause to our projects. Their path is in the IDEs library path and for some reason trying to open these units ended up with the open dialog poping up and showing “LibUnit” without the “.pas” suffix. That was an ugly issue in Delphi 2007, had been fixed Delphi 2009 and still worked in XE, but it is back in XE2.

I have tried it at home and could not repeat the problem. After six or seven RAD re-installations I found the reason – this issue occurs when you have only installed Delphi or only use the Delphi personality (-pDelphi) when Delphi and C++Builder are installed. I have filed the issue into QC as QC 102434. Luckily I found a workaround and this is enabling “Replace Open File At Cursor…” in DDevExtensions. So if you have also C++Builder installed then start RAD Studio with both personalities and otherwise try DDevExtensions.

TDBGrid cell painting

We have had an XE Unicode build with enabled theming for quite a while and noticed that the text in the focused grid cell was somehow bold, but we never looked into it. Now we have started to look into it and it turned out that this is no feature. It is rather a bug in our OnDrawColumnCell event handler. First some screenshots that you know what I am talking about.


Themed TDBGrid without OnDrawColumnCell event handler


Themed TDBGrid with supposed to be wrong OnDrawColumnCell event handler

In the second screenshot you should see that “Foo” in the focused cell is bolder than it is in first screenshot. The OnDrawColumnCell event implementation is just this:

procedure TForm21.DBGrid1DrawColumnCell(Sender: TObject; const Rect: TRect;
  DataCol: Integer; Column: TColumn; State: TGridDrawState);
begin
  Column.Grid.DefaultDrawColumnCell(Rect, DataCol, Column, State);
end;

Well this is not the code we use, but it is enough to demo the issue.

So why is the text in the focused column bold?

The reason is that TDBGrid sets in themed mode TDBGrid.Canvas.Brush.Style to bsClear for the focused column when DefaultDrawing is True. This happens in TCustomGrid.DrawCellHighlight. After drawing the focus rect the text is drawn and afterwards the OnDraw events are called. With DefaultDrawColumnCell and Brush.Style bsClear the text is painted twice to the same place and I guess antialiasing in themed mode does make it bold then. We have not finished the work on this topic and for now my advise is that you look at your Draw events and try to understand the code in the grid units.

More?

Yes, there might be more. I have other issues that we have experienced (debugger does stop on breakpoints that have been removed, “File | Reopen” does not like forms with open descendants) or task like the ModalResult check on my list.

Posted in IDE, QC | 7 Comments

ITE re-evaluation experience

At work we do use right now GNU Gettext for the localization of our application and are not looking for another localization solution. However we have decided sometime ago to re-evaluate the ITE (Integrated Translation Environment) when we switch to XE2. We have used the ITE once with Delphi32 for a discontinued project and our experience was not that good. I have not worked on that topic and do not remember the issues, but I believe the translation run did abort when the CPU load was too low.

I have given the ITE in XE2 now a try and the following is what I did, what happened and so on.

At first I have tried with a new VCL application if forms, which are not explicitly added to the project, get added to the localized project, because we have not yet added all forms or frames explicitly to the project. They do not get added and I do not consider this to be an issue. I do not know a tool that does add all forms or units to the project and I could have tried to add all forms to the application by hand. I did not like that idea and my plan was to update the project source with the help of the dependency information that the compiler can output. First I tried to get that information by enabling “Output unit dependency information” in the project options and compile from the IDE. I was prepared that it may not work, because I filed QC 93897 some time ago for XE. This hurdle can be easily solved by copying the compiler command line from the message panes Output tab and execute it on the command line. With the information from the d file and some additional code (not supposed to be published) I have updated the project source including the information that tells the IDE if it is a unit, form, frame or data module.

The second step was to open the project and add a new language (I am using ENG here) and when I pressed the “Finish” button in the “Add Languages” dialog I received the following message (partly translated as I am using a german OS)

[Window Title]
Error

[Content]
Cannot open file "project folder\ENG\FooForm.dfm". Access denied

[OK]

The reason for this was the readonly attribute of “project folder\ENG\FooForm.dfm”, but wait this file was not there before I started the process. The reason for this seems to be the fact that the language creation process copies the source file including the file attributes from the source file and most of our source files do have the +R attribute as they are managed by JEDI VCS. Checking out every module before adding a new language is close to impossible and so I just removed locally the +R attribute for all the modules. I do not see the need for copying the +R attribute, consider this to be a bug and logged this as QC 102776.

My second attempt to add a language was successful, but it took almost 30 minutes with 100 percent CPU load on one core. Note compiling the project with Compiler Speed Pack installed takes between 20 and 30 seconds when the files are already in the OS cache. A second run confirmed that long time. The refresh of the language project took three minutes. I do not know what exactly happens when adding the new language, but guess when I would rewrite the language creation process for our needs it might take a tenth of the time. I will not and have not done this, but nevertheless the shorter runtime for our needs is not a complete wild guess as I did run recently another process that processed all project files.

Then I looked with the Translation Editor at some forms I have seen a lot of stuff I do not want to see there. For example we do not translate SQL statements. I found an enhancement request in QC asking to exclude some properties from translation that are customizable by the user. This is QC 92279. This report also mentions the Explicit* properties and it is really strange to see them in the Translation Manager and I guess with an exclude list the language creation and update process could be speed up.

Then I tried to compile the localized project, but got the following error in the message pane:

[Fatal Error] F2039 Could not create output file 'project folder\ENG\c:\tmp\d16exe\LocaleTest.ENG'

I have tried it with a new VCL app and there it worked. Looking at the TargetName in LocaleTest_ENG.bdsproj and of the new VCL app told me that this is supposed to be a relative path and when the project folder is on a different drive than the output dir then there is no relative path. After fixing the BDSProj file the project could be compiled. I think this issue is already in QC as QC 87820.

Then I checked the Translation Manager with an inherited form and found no option to show the inherited stuff – not in the list nor when I show the original form or the translated form. Well of course one has only to translate the new stuff in an inherited form, but which forms and frames has the translator to translate when only specific forms should be translated and strings in these forms come from different inheritence levels?

Another problem is that there seems to be no way to refresh a language project from the command line for example by passing a parameter to etm.exe and so we cannot integrate it in the build process. For us this is mandatory.

I have not looked deeper into the (External) Translation Manager or the Translation Repository, because the amount of work to use successfully parts of the provided translation environment is in my humble opinion to high. I do not have to decide what we do, but I guess we stick with our working GNU Gettext solution and if some day there is a need to have for example different Left or Top properties in localized versions we might rethink the decision.

Another thing I got aware of some days before I looked into it is that the project options for localized projects (the version info) are broken since D2009 and are completely broken since XE2. This issue is in QC as QC 76033. A workaround would be to add the version info with another resource, but you have to readd it after each language refresh.

I am not sure if this post is useful for anyone. For me it is enough if my co-worker does read it.

Posted in IDE, QC | 7 Comments

Happy New Year and Welcome revised Object Inspector (XE, XE2)

Happy New Year to all of you!

Last week I have had a look into the Object Inspector and have seen that it could be quite easy to implement my idea of a Favorite page. That Favorite page should show me properties and events that I need often for a specific control or component and releases me from scrolling and searching. In connection with that I have looked for reports in the Object Inspector area and found the report QC 10268 (January 11, 2005; so far 25 votes) that asks for a filter edit in the Object Inspector. As a little workaround you can so far use the Object Inspectors incremental search feature when you are looking for a specific property. If you do not know about this feature than see what Malcom wrote in this blog post. However I find that way a little bit cumbersome and it seems even to confuse QA, because they think it would not be able to find sub items, but how about using “an.” to jump to (Vcl.Forms.TForm.)Anchors.akLeft?

Meanwhile I have implemented the filter edit and the Favorite page for the case when the Object Inspector is used for the Form Designer. Even if I could leverage the existing filter mechanism, which separates the properties into the Properties and Events pages, there were a few hurdles to take.

Can anyone tell me for example how one can get the parents of IProperty?
[see $(BDS)\source\ToolsAPI\DesignIntf.pas]

Screenshots and description

Here is a screenshot of the upper part of the default Object Inspector in XE2.


XE2 Object Inspector for a TForm instance

Here are a few screenshots of the two new features in the revised Object Inspector with some explanation. At first comes a screenshot which shows the same as the prior image, but with my Object Inspector enhancements installed.


Revised Object Inspector for a TForm instance (differences are the filter edit and Favorites page on the top)

The filter edit enables you to filter the properties by the string in the edit. This filter is case-insensitive and that mean that actually I had not have to enter an upper case “S” in the following screenshot. The filter takes the child properties into account and thatswhy you do see the “Font” property, because it has the child property “Style” that contains “sty”. Right now there is no automatic expansion of the items with childs.


Revised Object Inspector with the filter “Sty” for a TForm instance (the filter is case-insensitive)

What you enter into the edit has to exists somewhere in the full qualified property name. By this I mean I add the parents with dots to the property name and that means the full qualified property name for “fsBold” of the “Style” property of TForm.Font is “Font.Style.fsBold”. You can use the dot in the filter and so “t.sty” does only show “Font.Style” and childs and not “BorderStyle” and so on as on the prior image.


Revised Object Inspector with the filter “t.sty” for a TForm instance (the filter is case-insensitive)

In order to make a property a favorite property you can use the “Add Favorite” popup menu item in the Object Inspector’s popup menu.


Popup menu item to add a property as favorite property to show up on Favorites page

After clicking on the popup menu item the following dialog is shown. It contains the full qualified class name and full qualified property name for the currently selected property (the one with the chevron). Favorite properties are not global by default, but you can make them global by clearing the class name edit. Note the asterisk char or partial names are not supported – so do not turn “Font.Style” into “Font.S*” or “Font.S” to show “Font.Size” and “Font.Style”. The same applies to the class names – you cannot just use “TForm” instead of “Vcl.Forms.TForm” or “FMX.Forms.TForm”.


Add Favorite dialog

If you accidentally added a property as favorite property or just needed some properties for some time for a special task then you can remove them with the “Remove Favorite” popup menu item on the Favorites page.


Popup menu item to remove a property from the Favorites page

If you like the Favorites page, but do not want to have the filter edit or the other way round then you can disable them in the Object Inspectors Properties dialog or in the Environment options on page “Environment Options | Object Inspector”. Note the filter edit gets automatically disabled when you disable the “Show instance list” option.


Object Inspector Properties with the two additional options “Show filter edit” and “Show Favorites page” at the bottom of the Options groupbox

Some more words on the favorites filter: When I do filter the properties I first gather a list of classes in the class hierarchie of the selected instance and for example for Vcl.Forms.TForm that means that this list does include Vcl.Forms.TCustomForm and Vcl.Controls.TControl. Afterwards a list of the favorite properties for each class in that list and for the “any type” properties is created and that list is used in the filter. That in connection with the following default properties explains why you see by default for every VCL control Left, Top, Height and Width on the Favorites page.

This are the default favorite properties:

  • Left, Top, Height and Width for Vcl.Controls.TControl
  • Caption, Text, Color and OnClick for any type

Before you ask why I have not removed that obviously useless description pane at the bottom of the Object Inspector, which Marco did not understood some time ago, then I have to tell you that it is actually used. To my knownledge it is not really used when the Object Inspector is used for the Form Designer, but it is when it is used by the Modelling feature or any other feature that uses the Object Inspector and so I will not just remove it. However I have to admit that some tuning could help here later.

Known issues

  • When expanding the instance list with the filter edit visible the drop down width is bigger than the instance list combobox
  • Multiselect in the Form Designer is supported, but then only the first type in the instance list is used to generate the list of the favorite properties
  • The filter edit is also shown when Object Inspector is used for the Modelling feature. There the value in the edit has no effect and this is as expected. That the filter edit is shown is right now a side effect of the fact that the instance list combobox is visible too. I am not used to the Modelling feature, that is anyway limited in my Professional Edition and so I do not know right now if the instance list combobox is shown by intention or if this is a bug. For now I could not see any usage and have first to find out which bug needs to be fixed.

Setup

  • Download the setup for XE and XE2 from here
  • Follow the instructions in the setup
  • Start the IDE

I hope you will find it as useful as I do and there are not too much bugs in the code.
Happy testing!

Posted in IDE | 16 Comments

I have to touch that VCL form here. Where does it come from?

At day time I do work on a really big project. Since not everything is written by me it happens that I do have to work on a form or frame I do not know or where I cannot remember the name. Well there are different ways to find out the name like following the code from a point you do know or pausing the application on an action in the form and looking at the call stack, but since Delphi 2009 there is a better way to do it. This way almost trivial – you just have to combine Windows.GetCursorPos, Controls.FindVCLWindow and TObject.UnitName, this looks like this when you like to show also the parent controls and this is what you would have to put into the developer build of your application…

procedure TfmControlNames.UpdateTimerTimer(Sender: TObject);
var
  P: TPoint;
  S: string;
  SL: TStringList;
  C: TWinControl;
begin
  SL := TStringList.Create;
  try
    if GetCursorPos(P) then
    begin
      C := FindVCLWindow(P);
      while Assigned(C) do
      begin
        S := C.Name + ': ' + C.UnitName + '.' + C.ClassName;
        SL.Add(S);
        C := C.Parent;
      end;
    end;
    lbInfo.Caption := SL.Text;
  finally
    SL.Free;
  end;
end;

In action in the IDE this looks like this.

If you think you have a need for this control info form in the developer build of your application then you can get the download here. It should work with D2009 till XE2, but I have only tested it with XE and XE2. In order to show the form call the following code at a suitable place

  if not Assigned(fmControlNames) then
    fmControlNames := TfmControlNames.Create(Application);
  fmControlNames.Show;

This will show the control info form that stays on top. Just move the mouse cursor over a control and see what is shown.

There is room for improvements like showing vendor information (e.g. Embarcadero for Vcl.Forms) from a list, showing maintainer information (e.g. USchuster for SvnClientMerge) from a list, show parent class information (e.g. TCustomVirtualStringTree…TBaseVirtualTree…TCustomControl for TVirtualStringTree), use TListView or TVirtualStringTree to show the list or open a unit on double click in the IDE…

Posted in Uncategorized | 5 Comments