-
Content Count
2561 -
Joined
-
Last visited
-
Days Won
133
Everything posted by Anders Melander
-
ANN: Better Translation Manager released
Anders Melander replied to Anders Melander's topic in Delphi Third-Party
Excellent question 🙂 First of all I would recommend that you use the TField.DisplayLabel property instead of the column Caption property unless you have a good reason not to. If you use TField.DisplayLabel then all columns that are bound to that field will automatically use that value as their caption and as a bonus you will only have to translate that value one place. The reason you're not seeing the Caption property of the TcxGrid*Column components is that the value isn't stored in the DFM and BTM can only see the properties that are stored in the DFM... Now, why isn't it stored? Well, the value has most likely been omitted from the DFM because it's the same as the FieldName. If you look at the TcxCustomGridTableItem.Caption property you will see that it has a stored directive. The stored directive controls if the property is stored in the DFM. In this case it will be stored if you have specified an explicit value and this value is different from the default value. So what is the default value? In this case the default value comes from the DisplayLabel property of the TDataSet field you have bound the column to. Again, if you haven't specified an explicit TField.DisplayLabel then the value of DefaultLabel defaults to TField.FieldName, in which case that value is also omitted from the DFM. Now you might think that the solution is to just specify an explicit Caption or DisplayLabel and that will probably work in most cases. However it will not work in the cases where this value is the same as the FieldName, because then the default rule will again cause it to be omitted from the DFM since it isn't needed. The solution is to "synthesize" the properties that have been omitted. By synthesize them I mean inject the "missing" properties into the translation project as if they were present in the DFM. If you go into the BTM settings there's an option to have BTM synthesize missing properties for you: The way it works is that when BTM reads the forms of the source application (e.g. during an Update), it runs the synthesize rules against each component that it find in the form. If a rule determines that a property is missing then a property is injected into the project with the specified name and value. I believe the above screenshot shows the default rule (preinstalled, but disabled by default): Type mask: ^T([A-Z][a-z]+)+Field$ A regular expression matching a component type. In this case the expression will match the different TField components (TIntegerField, TStringField, etc). Property name: DisplayLabel A property name. If this property is missing then it will be created in the translation project. Property value: @FieldName The value to assign the property. This can be an explicit value or the value of another property. In this case the @ specifies that we want the value of another property, namely the FieldName property. So let's say your application had a DFM with the following: ... object MyQuery: TFDQuery SQL.Strings = ('select name from users') object MyQueryUserName: TStringField FieldName = 'name' Size = 50 end end ... with the synthesize rules enabled BTM would import the above as if it looked like this: ... object MyQuery: TFDQuery SQL.Strings = ('select name from users') object MyQueryUserName: TStringField FieldName = 'name' DisplayLabel = 'name' Size = 50 end end ... Synthesized properties can be identified in the grid by their color (I believe the light green is the default - it can be customized): One thing to be aware of is that the synthesize option currently is an application level setting. This means that if you only enable it on one system and then update the project on another then the synthesized properties will be marked "Unused" which means that they will be removed if you Purge the project. I'll be fixing that "real soon now". If you run BTM in portable mode and include the portable config file in your version control (which I would recommend), then the above should not become a problem. Speaking from experience :-/ If you prefer to do the translation on the TcxGrid*Column level then you can use the following rule: Type mask: ^TcxGrid[a-zA-Z]*Column$ Property name: Caption Property value: @DataBinding.FieldName It seems there is a minor bug with adding synthesize rules so after adding the rule you should restart BTM and everything should be fine. I'll look into that. Fixed (but not yet built and uploaded). -
Do you need an ARM64 compiler for Windows?
Anders Melander replied to Lars Fosdal's topic in Cross-platform
From our POW there are primarily two reason to pay maintenance on a product (any product): If you need access to the latest version regularly, the yearly subscription fee is cheaper than paying for a new license each time. Support the supplier financially so they are able to keep the product alive. Since DevExpress seems to have done "the right thing" here, we're not about to punish them for that. Yes, we can expect lower output from them for a while while they get a new team up to speed, but unless development complete stalls, for an extended period of time, we can live with that. With regard to the mentioned limit on support I think it's entirely reasonable. That was not our problem. Our problem was more pertaining to the perceived increasingly non-committal responses we got when we raised issues regarding deficiencies in the products. Now that I know the state of things it makes much better sense. -
I think they will relocate FYI:
-
Do you need an ARM64 compiler for Windows?
Anders Melander replied to Lars Fosdal's topic in Cross-platform
Since I brought up DevExpress' association with Russia in this thread I think it's only fair that I share the response I just got from DevExpress on the matter. I sent the following to Julian Bucknall (DevExpress CTO) earlier today: and I just got the following response (emphasis mine) from Ray Navasarkian (DevExpress CEO): So I guess that puts that topic to rest for my part. I too would have liked a roadmap and I can't quite understand why they can't produce something, but apparently that's just the way it is. Indeed! -
Do you need an ARM64 compiler for Windows?
Anders Melander replied to Lars Fosdal's topic in Cross-platform
There's a difference between someone spying on me for their own gains and someone trying to harm me just because they're angry at everybody else. I'm not that concerned about the former. -
Left side cannot be assigned to
Anders Melander replied to AlanScottAgain's topic in RTL and Delphi Object Pascal
Some of the code I'm currently maintaining ironically has widespread use of dynamic arrays of very large records. Ironically because it was done to avoid the overhead of lists of objects in order to improve performance. Instead it now struggles with the overhead of dynamic array reallocation and records being copied back and forth. I'm slowly refactoring it to use lists and objects but meanwhile I'm using the approach you're suggesting (minus the copy/paste bug 🙂), so this: type THumongousRec = record Foo: integer; ... end; THugeArray = array of THumongousRec; TMyClass = class private FData: THugeArray; protected function GetData(Index: integer): THumongousRec; procedure SetData(Index: integer; const Value: THumongousRec); public property Data[Index: integer]: THumongousRec read GetData write SetData; end; function TMyClass.GetData(Index: integer): THumongousRec; begin Result := FData[Index]; end; procedure TMyClassSetData(Index: integer; const Value: THumongousRec); begin FData[Index] := Value; end; begin var Data := MyClass.Data[0]; Data.Foo := 1; MyClass.Data[0] := Data; end; becomes this: type THumongousRec = record Foo: integer; ... end; PHumongousRec = ^THumongousRec; THugeArray = array of THumongousRec; TMyClass = class private ...same as before... protected ...same as before... function GetPData(Index: integer): PHumongousRec; public ...same as before... property PData[Index: integer]: PHumongousRec read GetPData; end; function TMyClass.GetPData(Index: integer): PHumongousRec; begin Result := @FData[Index]; end; begin MyClass.PData[0].Foo := 1; end; Of course this only works when the property setter doesn't have side effects. -
Left side cannot be assigned to
Anders Melander replied to AlanScottAgain's topic in RTL and Delphi Object Pascal
True, if you have to implement an interface declared by someone else - but since you don't have to actually declare the property in your implementation there's zero difference from your perspective between an interface with and one without property declarations. Anyway, to each their own, free world and all. IMO both approaches are just fine. -
Left side cannot be assigned to
Anders Melander replied to AlanScottAgain's topic in RTL and Delphi Object Pascal
Nope: type IFoo = interface function GetBar: IBar; procedure SetBar(const Value: IBar); property Bar: IBar read GetBar write SetBar; end; TFoo = class(..., IFoo) private function GetBar: IBar; procedure SetBar(const Value: IBar); // Look ma, No property! end; begin var Foo: IFoo := TFoo.Create; var Bar := Foo.Bar; end; Sure, but I don't see the problem; Don't use them if you don't like them. You will still need the getters and setters so there's not much saved by omitting the property declaration and you lose the meta information that the property communicates. I too would wish the the getters and setters could be hidden from the public API of the interface (like I wish that the private part could be hidden from class declarations) but I guess that we have their history (as COM interfaces) to thank for that. Since I need both COM and non-COM interfaces and a new breed of interfaces would just be a mess I can live with the annoyances the versatility brings with it. -
Do you need an ARM64 compiler for Windows?
Anders Melander replied to Lars Fosdal's topic in Cross-platform
Sure - And the quality of soft- and hardware from behind the Iron Curtain reflected that fact. Let's say, for the sake of argument, that you represented a professional western software company. Would you accept a dependency on a library such as DevExpress (which is far from cheap), knowing that it was produced using pirated tools on a pirated OS, by developers which may or may not have your best interests in mind? I would not. Apart from the moral and business aspects there's also one of security. I know a few Russian developers which I fully trust because I know them both professionally and socially but from what I've heard from them I can't assume that all modern, educated Russians are like that. Some of their former colleagues would be happy to see the west go up in flames. -
Do you need an ARM64 compiler for Windows?
Anders Melander replied to Lars Fosdal's topic in Cross-platform
Since Russia no longer has (legal) access to moderne computer technology I wouldn't expect much - for the next decade or so. -
Left side cannot be assigned to
Anders Melander replied to AlanScottAgain's topic in RTL and Delphi Object Pascal
So use a function instead but I can't see how that would improve anything for you. A property better expresses the intent. For interfaces properties are purely syntactic sugar so you really don't have to use them if you prefer not to. You can just call the getters or setters directly. How is that a pain? -
Left side cannot be assigned to
Anders Melander replied to AlanScottAgain's topic in RTL and Delphi Object Pascal
Bold statement, given the fact that they were one of the language features, if not the feature, that made Delphi possible in the first place. If you need to pass them as var or out parameters then I would say that there's something wrong with your design but without a concrete example it's hard to say what. Code completion: Ditto. If you need to modify a property, which isn't writable, then there's something wrong with your design or with the class design. Many other languages doesn't have objects, interfaces, exception handling, etc. Pretty irrelevant. -
ANN: Better Translation Manager released
Anders Melander replied to Anders Melander's topic in Delphi Third-Party
Nice. I believe you can just use the FindDragTarget VCL function to find the control under the cursor. The current algorithm looks for an exact match on the control name and then iterates backward (i.e. negative row index increment) from the least property until it finds a visible property. It does not consider the Status of the property since it doesn't know what you're doing or why you want to select the item. I'd like to keep it that way. If you filter the Status column to exclude "Don't translate" then these properties will not be selected and it will behave like you want. Since you're not interested in the "Don't translate" items anyway there's no point in displaying them. -
ANN: Better Translation Manager released
Anders Melander replied to Anders Melander's topic in Delphi Third-Party
@KHJ Fixed and new version uploaded. Thanks for the patience. -
ANN: Better Translation Manager released
Anders Melander replied to Anders Melander's topic in Delphi Third-Party
Ah... That was the missing piece. Reproduced! -
ANN: Better Translation Manager released
Anders Melander replied to Anders Melander's topic in Delphi Third-Party
I'm stumped. I don't believe the EXE-file is the problem because I can't reproduce with the one you sent me. Which version of Windows are you on? I know which change probably caused this. Previously, after the resource scan, I discarded modules (i.e. forms) that had no translatable items (i.e. components/properties). Now I keep them. However that doesn't explain why the modules aren't being discarded during the resource scan since they are not DFM resources. The first thing I do when I examine a RCDATA resource item is to check if the resource starts with "TPF0" which is the binary DFM signature. If the signature isn't present then the module type is set to "other" and the module is discarded. If I load your project, containing the BB modules, and then do an update the BB modules are immediately marked as missing since BTM considers these modules as not being present in the EXE (which is correct). -
Use the standard system dialogs. They will work with any version of Windows and, most importantly, look and function like the users expect them to. For example DevExpress have begun using their own custom dialogs in their skin editor and in their design-time editors and it's just horrible. The dialogs are skinned even though nothing else is, the usability sucks, lots of things just doesn't work and the usual explorer integration that comes for free with a standard system dialog doesn't work properly, etc. etc. Is there any particular reason why you want to use a custom dialog? Based on the visdom of fortune cookies and my magic crystal ball I foresee that your as of yet unknown changes will lead to as of yet unknown challenges. You're welcome.
-
ANN: Better Translation Manager released
Anders Melander replied to Anders Melander's topic in Delphi Third-Party
Thanks. I have not been able to reproduce the problem with your application or its translation project, using the same version of BTM as you - or the newer. I can see from your application that the BB* modules are in fact RCDATA resources containing PNG images. Since I verify the signature of the resource data to determine if it's a Delphi form these should all have been excluded by the resource scanner. On reviewing the code the only way I can see that this problem would occur is if the resources contained data smaller than a dword. Could it be that you updated the project on a UPX compressed (or something like it) application file? I could reproduce the access violation if I opened your modified project (the one with the BB modules) and then updated the project (which correctly marked the BB modules "don't translate") but this doesn't explain how they got introduced in the first place. In any case I have now added an extra check to handle RCDATA smaller than 4 bytes. New version uploaded. -
ANN: Better Translation Manager released
Anders Melander replied to Anders Melander's topic in Delphi Third-Party
I don't know what output Sisulizer produces but if it works like BTM/ETM/ITE and produces resource modules (i.e. DLLs) then you can use "Tools -> Import application". Otherwise I guess you'll have to export from Sisulizer to TBX, import the TBX to the Translation Memory and then use that to translate the modules. -
ANN: Better Translation Manager released
Anders Melander replied to Anders Melander's topic in Delphi Third-Party
Those are the standard Delphi Bitmap resources and since I'm only importing RCDATA (Forms) and Strings (resourcestrings) resources, and I'm specifically asking Windows to only return a list of those, the problem is probably some sort of memory corruption. I have not been able to reproduce the problem. If you can mail me your application (zipped) I will try to reproduce with that. If you click on an already focused cell (i.e. a slow double click) then the cell will go into edit mode. Pressing F2 will also do that. The "slow double click" thing is a very annoying DevExpress "feature" and I usually apply a work around to fix it (e.g. I've done that in the main edit grid). It's been reported a million times but they refuse to fix it or even acknowledge that there is a problem. Anyway, I'll apply the work around to the TM form too. -
ANN: Better Translation Manager released
Anders Melander replied to Anders Melander's topic in Delphi Third-Party
Remove the space between -n and 1. Like so: -n1 or -n:1 I'm using FindCmdLineSwitch(<name>, Value, True, [clstValueAppended]) to fetch the parameters. -
ANN: Better Translation Manager released
Anders Melander replied to Anders Melander's topic in Delphi Third-Party
Not really. You are just using an older version of the command line tool 🙂 The latest version is 1.3.8198.28909. My guess is that you selected the installation type "Full installation" which doesn't include the command line tool. That's not intuitive so I'll change that. In the meantime just select the command line tool manually in the installer list. -
TStringHelper.IndexOfAny( array of string, ...): Why is this private ?
Anders Melander replied to Rollo62's topic in RTL and Delphi Object Pascal
Okay. So in other words: They're available through the UI from 11.1 -
TStringHelper.IndexOfAny( array of string, ...): Why is this private ?
Anders Melander replied to Rollo62's topic in RTL and Delphi Object Pascal
Huh? Your profile says 10.1 and AFAIK they were introduced in 10.2. Here's what I have on Delphi 11.0 (same with 10.3): -
TStringHelper.IndexOfAny( array of string, ...): Why is this private ?
Anders Melander replied to Rollo62's topic in RTL and Delphi Object Pascal
Ah! - and there's even a IMPLICIT_INTEGER_CAST_LOSS to go along with it. Am I correct in observing that that these hasn't been surfaced in the IDE options dialog?