TAction.SecondaryShortCuts is language specific. How to set it correctly? - delphi

I just used the SecondaryShortCuts-Feature of Delphi's TAction. But Shortcuts are defined by Strings, like "F5" or "Shift+F5". Now the problem: On my German Windows the action doesn't fire, because the key "Shift" is called "Umsch" in German!
Does it mean the SecondaryShortCuts-Property is completely useless at design time, because nobody can create applications which work internationally with that?
I could set the key at runtime by translating the VK_SHIFT into the correct name. I tried it via GetKeyNameText but this didn't worked because it gave the long form "Umschalt" not "Umsch". Anybody know the function to get the short version of the key name?

You could try this: Generate the shortcut text from a shortcut:
var
s: TShortCut;
begin
s := ShortCut(Ord('A'), [ssShift]);
Action1.SecondaryShortCuts.Add(ShortCutToText(s));
By the way, these values are determined by the following constants. Have you translated those? And if so, do you need to?:
SmkcShift = 'Shift+';
SmkcCtrl = 'Ctrl+';
SmkcAlt = 'Alt+';

Related

DKLang's StoreList and Virtual treeview's header text translation

So I use the DKLang Localization Package for multi-language support.
TDKLanguageController has a property called StoreList (of type TStrings), where you can enter a TMask-compatible wildcard strings to force a property to be processed by DKLang, for example, "*.SomeStringProp" will force any component properties called SomeStringProp to be processed by DKLang.
The problem I'm having now is to force DKlang to handle Virtual treeview's header captions, ie. TVirtualStringTree.Header.Columns[i].Text.
I've tried "*.Text", "Header.Columns.Text" and "Header.Columns*.Text", none of them worked.
Thanks.
You can declare constant for each column text:
myVirtualStringTree.Header.Columns[0].Text := myConstant1;
myVirtualStringTree.Header.Columns[1].Text := myConstant2;
myVirtualStringTree.Header.Columns[2].Text := myConstant3;
and manage those constants with the DKLang editor by the "user defined constants".

Delphi - How to Exclude/turn off all values in a set?

Delphi XE6 - I have a set. I would like a simple way to turn ALL elements off. i.e. instead of Exclude, something like ExcludeALL. I have tried to loop through all elements, but I get an error.
Code
type
TSearchParametersType =
(smDUNSAvailable = 1,
smDUNSHit,
smDUNSMiss,
smDUNSAbsent,
smRegistryAvailable,
smRegistryHit,
smRegistryAbsent,
smRegistryMiss,
smNameAvailable,
smNameHitExact,
smNameHitWords,
smNameMiss
);
// Now create a set type, where we can have a variable that has all the values of TSearchParametersType
type
TSearchParametersSet = set of TSearchParametersType;
...
var
i : Integer;
sSearchStatus: TSearchParametersSet;
begin
for i := smDUNSAvailable to smNameMiss do
Exclude(sSearchStatus, i);
The error I get is "Incompatible Type: 'Integer' and TSearchParametersType. "
Is there a simple way to Exclude ALL, other than MANUALLY going through every element?
Thanks
From the documentation:
Every set type can hold the empty set, denoted by [].
So you can assign the empty set to your variable like this:
sSearchStatus := [];
FWIW, your code fails because smDUNSAvailable and smNameMiss are of type TSearchParametersType and so not compatible with the variable i which is of type Integer. In order to make your code work you would need to change the loop variable to be of type TSearchParametersType.
Let me start by saying that David's answer is the correct one.
I'll just post another one to show how you could do it manually. This code might come in handy some other time:
var
sSearchStatus: TSearchParametersSet;
SearchParametersType : TSearchParametersType;
begin
sSearchStatus := [smDUNSHit, smDUNSMiss, smDUNSAbsent, smRegistryAvailable, smRegistryHit];
for SearchParametersType := low(TSearchParametersType) to high(TSearchParametersType) do
Exclude(sSearchStatus, SearchParametersType);
end;

Inserting CrossReference to word via Delphi XE5

Bonjour, Hello,
I'm making this delphi application that I use to create word documents. I'm done with basic word operations (create/save, text, tables..etc).
What I need to do is to insert Page Numbers of headings as Cross Reference in the text. Something like :
"... and the process works as explained on page 23..."
where page number is a hyperlink to a heading. When I recorded a Macros in word it looks like:
Selection.InsertCrossReference ReferenceType:="Heading", _
ReferenceKind:=wdPageNumber, ReferenceItem:="49", InsertAsHyperlink:=True _
, IncludePosition:=False, SeparateNumbers:=False, SeparatorString:=" "
What would be the equivalent in Delphi please?
Thanks in advance!
Arjun.
Even when you're using Late Binding you still need to provide all of the parameters in the same order as the original declaration.
expression.InsertCrossReference(ReferenceType, ReferenceKind, ReferenceItem,
InsertAsHyperlink, IncludePosition, SeparateNumbers, SeparatorString)
If you aren't using a parameter then you can replace it with EmptyParam.
So I think your code will be:
Selection.InsertCrossReference('Heading', 7, '49', True, False, False, ' ');
(I think that wdPageNumber's value is 7).

Datasnap & Fmx Mobile App How to send a dataset containing a blob field

I had a multi tier project in which i would collect data from a microsoft sql 2005 through a FDStoredProc with a function and the function would return a dataset to the client. When the server assigns the dataset to the result of the function and the function tries to send it to the client i get this error. Project etctec.exe raised exception class TDBXError with message 'TDBXTypes.BLOB value type cannot be accessed as TDBXTypes.Bytes value type'.
In another project i used the StoredProc of a different database with TFDStoredProc in exactly the same way and it works fine. Any ideas what would raise this error?
This is what i do in the server.
function TServerMethods1.getCategories(): TDataSet;
begin
FDStoredProc1.ParamByName('#val1').AsInteger:= 1;
FDStoredProc1.ParamByName('#val2').AsInteger:= 0;
FDStoredProc1.ParamByName('#val3').AsInteger:= 1;
FDStoredProc1.ParamByName('#val4').AsInteger:= 1;
FDStoredProc1.Open();
result:= FDStoredProc1;
end;
and the client calls it like this...
dataset:=ClientModule1.ServerMethods1Client.getCategories();
Problem comes from some fields that are of type NVARCHAR(max), anyone knows a workaround to this error without changing the field type?
I tried changing the dataset's field type to a string or something with no success. The only thing i can temporarily do is get these fields separately, put them in a stringlist or something like that and pass it to the client.
I think you should use some of similar methods below:
http://docwiki.embarcadero.com/Libraries/XE4/en/Data.DB.TDataSet.CreateBlobStream
http://docwiki.embarcadero.com/Libraries/XE4/en/Data.DB.TDataSet.GetBlobFieldData
You should define you field as a blob field and then put data in/out with the functions described in the links.
Here is also example how to copy data:
http://docwiki.embarcadero.com/Libraries/XE4/en/Data.DB.TDataSet.CreateBlobStream

Best way of storing an "array of records" at design-time

I have a set of data that I need to store at design-time to construct the contents of a group of components at run-time.
Something like this:
type
TVulnerabilityData = record
Vulnerability: TVulnerability;
Name: string;
Description: string;
ErrorMessage: string;
end;
What's the best way of storing this data at design-time for later retrieval at run-time? I'll have about 20 records for which I know all the contents of each "record" but I'm stuck on what's the best way of storing the data.
The only semi-elegant idea I've come up with is "construct" each record on the unit's initialization like this:
var
VulnerabilityData: array[Low(TVulnerability)..High(TVulnerability)] of TVulnerabilityData;
....
initialization
VulnerabilityData[0].Vulnerability := vVulnerability1;
VulnerabilityData[0].Name := 'Name of Vulnerability1';
VulnerabilityData[0].Description := 'Description of Vulnerability1';
VulnerabilityData[0].ErrorMessage := 'Error Message of Vulnerability1';
VulnerabilityData[1]......
.....
VulnerabilityData[20]......
Is there a better and/or more elegant solution than this?
Thanks for reading and for any insights you might provide.
You can also declare your array as consts and initialize it...
const
VulnerabilityData: array[Low(TVulnerability)..High(TVulnerability)] of TVulnerabilityData =
(
(Vulnerability : vVulnerability1; Name : Name1; Description : Description1; ErrorMessage : ErrorMessage1),
(Vulnerability : vVulnerability2; Name : Name2; Description : Description2; ErrorMessage : ErrorMessage2),
[...]
(Vulnerability : vVulnerabilityX; Name : NameX; Description : DescriptionX; ErrorMessage : ErrorMessageX)
)
);
I don't have an IDE on this computer to double check the syntax... might be a comma or two missing. But this is how you should do it I think.
not an answer but may be a clue: design-time controls can have images and other binary data associated with it, why not write your data to a resource file and read from there? iterating of course, to make it simpler, extensible and more elegant
The typical way would be a file, either properties style (a=b\n on each line) cdf, xml, yaml (preferred if you have a parser for it) or a database.
If you must specify it in code as in your example, you should start by putting it in something you can parse into a simple format then iterate over it. For instance, in Java I'd instantiate an array:
String[] vals=new String[]{
"Name of Vulnerability1", "Description of Vulnerability1", "Error Message of Vulnerability1",
"Name of Vulnerability2", ...
}
This puts all your data into one place and the loop that reads it can easily be changed to read it from a file.
I use this pattern all the time to create menus and for other string-intensive initialization.
Don't forget that you can throw some logic in there too! For instance, with menus I will sometimes create them using data like this:
"^File", "Open", "Close", "^Edit", "Copy", "Paste"
As I'm reading this in I scan for the ^ which tells the code to make this entry a top level item. I also use "+Item" to create a sub-group and "-Item" to go back up to the previous group.
Since you are completely specifying the format you can add power later. For instance, if you coded menus using the above system, you might decide at first that you could use the first letter of each item as an accelerator key. Later you find out that File/Close conflicts with another "C" item, you can just change the protocol to allow "Close*e" to specify that E should be the accelerator. You could even include ctrl-x with a different character. (If you do shorthand data entry tricks like this, document it with comments!)
Don't be afraid to write little tools like this, in the long run they will help you immensely, and I can turn out a parser like this and copy/paste the values into my code faster than you can mold a text file to fit your example.

Resources