Jump to content

Anders Melander

Members
  • Content Count

    2297
  • Joined

  • Last visited

  • Days Won

    119

Posts posted by Anders Melander


  1. https://www.sourcetrail.com/blog/open_source/

    Quote

    Looking at other companies in the field, it seemed that to make more money, our only option was making our licenses more and more expensive, which in turn would limit our audience to fewer developers. We always dismissed the idea because we started to make Sourcetrail to benefit as many developers as possible and not to be a premium product for a few people in a handful of companies.

    Also Wow. Bold move and I hope it turns out good for them.

    I can't help but think of Borland who went for the exact opposite solution (remember Inprise?) and almost killed Delphi in the process. And we're still paying the price for that fiasco - literally.


  2. If you can reproduce the problem then simply run the application in the debugger, break when the problem occurs and examine the callstacks.

     

    ...however; My usual advice when people experience this kind of progressive or periodic slowdown/lockup is to uninstall the various cloud storage services they have running (ITunes, Google Drive, OneDrive, etc.). Solves the problem in 9 out of 10 cases.


  3. 25 minutes ago, Joseph MItzen said:

    Professor Lee goes on

    To paraphrase David Heffernan: That is utter nonsense and it doesn't appear that your Professor Lee has much practical knowledge about how to work safely with threads. Or maybe he's just using hyperbole to get a point across.

    Under any circumstances, Quoting academia? To disprove the opinions of a professional, highly skilled and experienced developer? Really? How about some arguments based on your own knowledge and experience...

     

    Many of us use threads on a daily basis and do so without wreaking havoc in the universe. If you understand the pitfalls of multi threading, know how to protect your resources, synchronize execution, understand race conditions, etc. etc., then threads are just another tool in the box. If you don't understand threading then yes, it will hurt you in a gazzilion ways you literally (and I use that word in the European sense) didn't think possible.


  4. 13 minutes ago, dummzeuch said:

    In that case obviously not.

    Actually it might. One of my grieves with the Refactor menu item is that if you accidentally move the mouse over the menu item (e.g. on the way to the View or Project menu item) then there's a noticeable delay (very noticeable on low end systems) as the IDE loads the refactor stuff (among it the J# run time I suspect) in order to populate the sub menu.

     

    2 hours ago, Dany Marmur said:

    we should maybe start another thread

    Agree, but I don't think I'll have more to contribute on the subject.


  5. 1 hour ago, Fr0sT.Brutal said:

    You can rename/remove refactoride###.bpl file

    Yes but that also removes the stuff I use and which actually works (mostly): "Find References" and "Rename".

    • Like 1

  6. Oh... This is the GExperts sub forum...

    I didn't notice that so I actually thought you meant the IDE main menu (which is what I was talking about). Well then, pls ignore what I said.


  7. Just now, Fr0sT.Brutal said:

    What if CallStuffThatMightBlockForever never returns?

    Then the thread will be killed when the application terminates.

    The point is that it's better to forget about the thread, report a timeout and continue as if the thread had been forcefully terminated.

     

    Of course if the thread has allocated or is blocking resources then that solution might not work.


  8. 49 minutes ago, aehimself said:

    If Self.IsRunning Then TerminateThread(Self.Handle, 1);

    I'm assuming the above is just an example to explain what you need - since if you can kill the thread from within the thread, then the thread isn't frozen and you could just exit it the normal way.

     

    3 minutes ago, Dalija Prasnikar said:

    if you need to kill the thread, you basically need to kill the application itself.

    I completely agree. Just don't do it.

     

    What you could do is signal the thread (use an event, a boolean, whatever) that it has become thread-non-grata and then just forget about it.

    If the blocking call ever returns then your thread can check the signal and terminate. E.g. something like this in your TThread.Execute

    procedure TMyThread.Execute;
    begin
      while (not Terminated) do
      begin
        CallStuffThatMightBlockForever;
        
        if (FNotInterestedAnymore) then
          break;
      end;
    end;

     


  9. 7 hours ago, chkaufmann said:

    The only question that remains, how can I set the IDE font used during designing to "Segoe UI, 9pt" because right now, when I choose "ParentFont = True" then I still get "Tahoma 8pt".

    I'm afraid I can't answer that.

    Supposedly there used to be a registry key that could do the trick (HKCU\Software\Embarcadero\BDS\19.0\FormDesign\DefaultFont) but that didn't work with the embedded form designer and as far as I can tell it no longer work with the detached designer either.

     

    I guess you could create an IDE plugin that modifies the form designer but that's probably more work than it's worth.

    Maybe just a design time package that modifies Application.DefaultFont like above will do the trick, but that will affect the whole IDE.

     

    FWIW I understand the OCD in you that wants the form to use SegoeUI at design time but it shouldn't really matter. If you have designed it "properly" then the form should be able to display correctly with both SegoeUI and Tahoma. After all you don't know what font the end-user will be using.


  10. 1 minute ago, David Heffernan said:

    It's a bug for the very reasons that you raised!

    I guess it's a matter of perspective.

    If you didn't expect the thread to start until after the constructor then I can see how the behavior would be seen as a bug. I never expected it to behave any other way so to me it was just an annoyance.

     

    A bit like FreeOnTerminate. A pretty good way to shoot one self in the foot.


  11. 1 minute ago, David Heffernan said:

    That was a bug fixed in Delphi 6, and one of the reasons for the introduction of AfterCreation.

    That must have been around the time when I stopped reading the documentation 🙂

    I can't see why it would be classed as a bug though.


  12. 1 minute ago, Dalija Prasnikar said:

    Actually, there is no race condition because thread is actually started in AfterConstruction. So you can put just about anything you need in thread constructor and create thread in non suspended state.

    Oh... You're right. It's even documented:

    Quote

    By calling Execute from the AfterConstruction method rather than the constructor, TThread avoids a race condition where the thread may free itself after Execute finishes but before the main thread calls AfterConstruction.

    I think I'll continue to use the create-suspended pattern anyway since it explicitly does what I wish.


  13. 3 hours ago, David Heffernan said:

    What happens if you pass False and so don't create suspended? 

    I know that this isn't really what you're asking but I don't think I've ever had a case where one didn't need to create suspended.

     

    You always have to either pass some information to the thread or initialize it's data and if you don't create it suspended there will be a race between the creator and the thread for access to the thread data structures. For example:

    type
      TMyThread = class(TThread)
      private
        FData: TSomeType;
      protected
        procedure Execute; override;
      public
        construtor Create(const AValue: TSomeType);
      end;
    
    construtor TMyThread.Create(const AValue: TSomeType);
    begin
      inherited Create(False); // Thread starts immediately
      FData := AValue; // Race condition here
    end;
    
    procedure TMyThread.Execute;
    begin
      FData.WhatEver; // Race condition here
    end;
    
    var
      Thread: TMyThread;
    begin
      Thread := TMyThread.Create(SomeData);
    end;

     


  14. @Vandrovnik A new version with the Duplicate View is now available:

     

    http://melander.dk/download/amTranslationManagerInstall-1.0.7254.4932.exe

     

    I had a bit of trouble getting this version up as BitDefender kept insisting that amResourceModuleBuilder.exe contained the Gen:Variant.DCry.1 ransomware.

    In the end I had to simply include the previous version of that file instead.

     

    Description of the Duplicate View above.

     

    I have also included the "Locate in TM action:

    image.thumb.png.327c64a081c1fb6397e1864c0486b7c1.png

    As the hint says, the action attempts to locate the focused source/target pair. It tries to be a bit intelligent about it in case there are multiple candidates (due to sanitation/equalization) so it will give priority to exact matches, case insensitive matches, sanitized matches and equalized matches, in that order. If a match is found the TM is opened and the matching row is selected:

    image.thumb.png.e4019a1e4331c75c81534c0851e68422.png

     

    This version also includes Copy to clipboard (as CSV) and Save to CSV. Next up is Paste and Import from CSV.

    • Like 1

  15. On 11/9/2019 at 10:05 AM, Vandrovnik said:

    If you add the button for finding duplicates in Translation Memory, please could this button follow the same rules for equalization as the rest of BTM?

    Done. The action performed on values to check for equality isn't called equalization though. It's called normalization. Internally, in the source, I call it Sanitation (i.e. I remove all the junk).

     

    Anyway, here's what I have implemented:

     

    The "duplicate view" is invoked via the popup menu:

    image.thumb.png.48fd7194cb819d8cd416be46f5dd8593.png

     

    When viewing duplicates a new column is added. This column displays the sanitized value of the selected language. You can control what sanitation rules to apply.

    Only rows that have duplicate values are displayed in duplicate view.

    image.thumb.png.335c0e8688a15df7d5acaced4c965761.png

     

    In case you wonder why I'm not grouping on the Duplicate column; I tried it but found that it just cluttered the user interface and made the grid too cumbersome to navigate.
    image.png.89853ee4fa00248e3d1f29304cf87252.png

     

    I'll try to get a new version with these changes released tomorrow or Tuesday.

     

    On 11/9/2019 at 10:05 AM, Vandrovnik said:

    If I press Yes, a duplicate record will be created; what I need is to replace original German text with the new one. Or is it possible to go directly to TM to the record which was used to translate this term to German and make changes there?

    I understand the problem.

    The dialog is already trying to communicate too much information and has become too complex for a standard message dialog. I have already redesigned it a bit (see below) but in order to add a "Replace" action I would have to switch to using a full blown Task Dialog or even better a custom dialog. That however will have to wait.

    image.png.3d6af1d9376729d6a9425bd793cc781d.png

     

    I think the best I can do in the short term is to add a "Find in TM" action. This would open the TM, try to locate the currently focused Source/Target value pair and focus the target value in the TM.

    • Like 1

  16. On 11/7/2019 at 9:55 AM, chkaufmann said:
    
      Font.Height = -12
      Font.Name = 'Segoe UI'
    

    Is there a simple way to achieve this?

     

    In the project file (the DPR file) I do this before the first form is created:

      if (CheckWin32Version(6, 0)) then
      begin
        // Application.DefaultFont is the font used when TForm.ParentFont=True.
        // It is Tahoma by default but should be Segoe UI on Vista and later (according to MS UI guide lines).
        // See InitDefFontData() in graphics.pas
        Application.DefaultFont.Assign(Screen.MessageFont);
        // DefFontData.Name specifies the default font for everything that doesn't specify a specific font.
        // For now we leave it as is (Tahoma). At some point it should follow the system default like above:
        // DefFontData.Name := Screen.MessageFont.Name;
      end;

    And then I just make sure to set all forms ParentFont=True at design time.

    • Like 3
    • Thanks 1

  17. 17 minutes ago, Joseph MItzen said:

    Classic OOP would, for instance, create a deck of cards class and then inherit from that to produce a blackjack game

    Nope. A deck is model, data, state and maybe presentation. The game is logic.

    A game is not a deck. A game uses a deck. Really basic OOP since we're going there.

     

    18 minutes ago, Joseph MItzen said:

    n the VCL, TJpegImage, TPNGImage, etc. are all inheriting from the TGraphic base class. If they all inherited from the TImage class instead

    Why stop there?

    What about layers, filters, transformations, scanner and cloud support. Yes, let's add SOAP, REST, FTP and Kermit support in case need to transfer these images between systems.

    Why do we need different classes at all? We could just create a single class that does EVERYTHING.

     

    6 minutes ago, Joseph MItzen said:

    It's the VCL inheritance scheme that seems rather ad hoc and unusual.

    You're confusing high level ease of use with low level architecture. The difference between the VCL and f.ex. ImageMagic is that one of them has it and the other doesn't. I'm guessing you've never read through the ImageMagick source code since you use it as a reference. I have. It's written in C. That might give you an idea of the inheritance scheme it uses... No?

     

    There's really no point in me trying to explain my point further since our reference frames are obviously worlds apart. Good night and good luck.

    • Like 1

  18. 27 minutes ago, Joseph MItzen said:

    Why not have just one image type that can read/write multiple formats?

    Monolithic design... Pick up any book on software design and it will explain why that is not a good idea. I'm not going to do it here.

     

    32 minutes ago, Joseph MItzen said:

    Or at least have TJPEGImage, etc. descend from TBitmap rather than TGraphic?

    Unnecessary coupling. The above book will explain that too, but ask instead: Why should it?

     

    Make a toolbox of individual tools that does as little as possible as good as possible and then assemble them into something larger. A swiss army knife is good to have if you're stranded on a deserted island. Besides that it's only good for impressing your 7 year old friends.

     

    Anyway, we're hijacking Foersom's thread. I'm outta here.


  19. 54 minutes ago, Joseph MItzen said:

    Do you know what the reason might be for that design decision?

    BMP, PNG, JPEG, GIF etc. are encoding formats. The sole purpose of TPNGImage, TJPEGImage and TGIFImage is to read, write and display these formats. Their internal representation is optimized to handle the features of the file format. They are not optimized to handle image manipulation.


    TBitmap on the other hand implements the BMP encoding and is internally represented as a native Windows DIB or DDB. TBitmap can wrap these with a TCanvas and thus provide access to most of the functionality of the GDI through the canvas.
    Additionally almost all other formats can convert to and from TBitmap so there's no reason why all the other formats should duplicate the functionality in TBitmap/TCanvas/GDI. They would just have to convert to/from TBitmap internally to do so anyway.

     

    Btw, using TCanvas.Pixels is extremely slow but fine for learning and very minor drawing tasks. For anything serious you have to mess with the raw DIB data directly - or use something like Graphics32 which does that for you. When you're using Pixels to manipulate the whole bitmap then the optimizations in the code become pretty pointless and only obfuscates the algorithm.

    • Like 1

  20. 2 hours ago, Vandrovnik said:

    The equalization - is it possible to customize it somehow?

    No. But...

     

    2 hours ago, Vandrovnik said:

    Upper/lower is problematic between Czech and German (in Czech noons begin with lower case, in German with upper case).

    OK. I will have to do something about that.

     

    For matches from TM the rule is that if I find an exact match in the TM then I do not equalize case (*). For example if I'm translating "Foo" and I find "Foo"->"bar" then I use "bar" as the translation. If I find "FOO"->"BAR" then I equalize "BAR" to "Bar" and use that.
    *) I still equalize endings and accelerators regardless of match exactness since the I consider TM data fidelity/consistency somewhat poor.

     

    I currently have the following equalization rules:

    • If source has an accelerator then make sure target also has one. If possible use the same hot key.
    • If source does not have an accelerator then accelerators are removed from the target.
    • If source ends with a colon, semicolon or ellipsis then make sure the target also does so, but only add new ending if the target ends with an alphanumeric character.
    • If source does not end with a colon, semicolon or ellipsis but the target does then remove the ending from the target.
    • If source is surrounded with ( ), [ ], { }, " ", ' ' or < > then make sure the target also does so.
    • If source is UPPER CASE, lower case, Title Case, Sentence case or simply Starts with an uppercase letter followed by a lowercase letter then make sure the target is too.

    It's implemented in the MakeAlike function in amLocalization.Utils.pas

     

    If I'm understanding you correctly then the only safe case rule between Czech and German is the UPPER CASE and maybe the Title Case rule.

     

    So if I'm making equalization configurable at what level should it be configurable. I mean I could make everything optional and all values configurable but it will be a nightmare to implement the UI for it and probably far too complex for the user to manage. I'm also guessing that the desired rules would differ between projects or even within projects, between languages.

     

    2 hours ago, Vandrovnik said:

    have disabled Apply to similar values, will it disable all these equalization and look for exact mathes only?

    No.

    image.png.d2ab5d01a8fa0744abdda0c03bacd8e2.png

    The "Apply new translations..." and "Apply to similar values" options controls if new translations are automatically applied to other identical or similar (via normalization) terms.

    For example if I translate "Foo" to "Bar" in once place, then it can automatically apply this translation to all other instances of "Foo" in the project. If the "similar" option is enabled then it will also apply the translation to "&Foo"->"&Bar", "FOO"->"BAR", "[foo]"->"[bar]" etc.

×