home *** CD-ROM | disk | FTP | other *** search
/ Chip 2001 September / Chip_2001-09_cd1.bin / zkuste / delphi / kolekce / d123456 / DFS.ZIP / DSAMsg.pas < prev    next >
Pascal/Delphi Source File  |  2001-06-28  |  45KB  |  1,162 lines

  1. {$I DFS.INC}  { Standard defines for all Delphi Free Stuff components }
  2.  
  3. {------------------------------------------------------------------------------}
  4. { DSAMsg Unit v2.17                                                            }
  5. {------------------------------------------------------------------------------}
  6. { A unit that provides "Don't Show Again" dialog and form services.  Included  }
  7. { is a form class that you can descend your own forms from, routines for       }
  8. { showing standarad TForm descendants, and replacement rountines for the       }
  9. { MessageDlg function.  DSA services allow the user to specify whether or not  }
  10. { they want to see the dialog or form in the future with only minimal effort   }
  11. { on the application programmer's part.                                        }
  12. {                                                                              }
  13. { Copyright 2000-2001, Brad Stowers.  All Rights Reserved.                     }
  14. {                                                                              }
  15. { Copyright:                                                                   }
  16. { All Delphi Free Stuff (hereafter "DFS") source code is copyrighted by        }
  17. { Bradley D. Stowers (hereafter "author"), and shall remain the exclusive      }
  18. { property of the author.                                                      }
  19. {                                                                              }
  20. { Distribution Rights:                                                         }
  21. { You are granted a non-exlusive, royalty-free right to produce and distribute }
  22. { compiled binary files (executables, DLLs, etc.) that are built with any of   }
  23. { the DFS source code unless specifically stated otherwise.                    }
  24. { You are further granted permission to redistribute any of the DFS source     }
  25. { code in source code form, provided that the original archive as found on the }
  26. { DFS web site (http://www.delphifreestuff.com) is distributed unmodified. For }
  27. { example, if you create a descendant of TDFSColorButton, you must include in  }
  28. { the distribution package the colorbtn.zip file in the exact form that you    }
  29. { downloaded it from http://www.delphifreestuff.com/mine/files/colorbtn.zip.   }
  30. {                                                                              }
  31. { Restrictions:                                                                }
  32. { Without the express written consent of the author, you may not:              }
  33. {   * Distribute modified versions of any DFS source code by itself. You must  }
  34. {     include the original archive as you found it at the DFS site.            }
  35. {   * Sell or lease any portion of DFS source code. You are, of course, free   }
  36. {     to sell any of your own original code that works with, enhances, etc.    }
  37. {     DFS source code.                                                         }
  38. {   * Distribute DFS source code for profit.                                   }
  39. {                                                                              }
  40. { Warranty:                                                                    }
  41. { There is absolutely no warranty of any kind whatsoever with any of the DFS   }
  42. { source code (hereafter "software"). The software is provided to you "AS-IS", }
  43. { and all risks and losses associated with it's use are assumed by you. In no  }
  44. { event shall the author of the softare, Bradley D. Stowers, be held           }
  45. { accountable for any damages or losses that may occur from use or misuse of   }
  46. { the software.                                                                }
  47. {                                                                              }
  48. { Support:                                                                     }
  49. { Support is provided via the DFS Support Forum, which is a web-based message  }
  50. { system.  You can find it at http://www.delphifreestuff.com/discus/           }
  51. { All DFS source code is provided free of charge. As such, I can not guarantee }
  52. { any support whatsoever. While I do try to answer all questions that I        }
  53. { receive, and address all problems that are reported to me, you must          }
  54. { understand that I simply can not guarantee that this will always be so.      }
  55. {                                                                              }
  56. { Clarifications:                                                              }
  57. { If you need any further information, please feel free to contact me directly.}
  58. { This agreement can be found online at my site in the "Miscellaneous" section.}
  59. {------------------------------------------------------------------------------}
  60. { The lateset version of my components are always available on the web at:     }
  61. {   http://www.delphifreestuff.com/                                            }
  62. { See DSAMsg.txt for notes, known issues, and revision history.                }
  63. {------------------------------------------------------------------------------}
  64. { Date last modified:  June 28, 2001                                           }
  65. {------------------------------------------------------------------------------}
  66.  
  67.  
  68. {: This unit provides "Don't Show Again" dialog and form services.  Included...
  69.    is a form class that you can descend your own forms from, routines for...
  70.    showing standarad TForm descendants, and replacement rountines for the...
  71.    MessageDlg function.  DSA services allow the user to specify whether or not...
  72.    they want to see the dialog or form in the future with only minimal effort...
  73.    on the application programmer's part.
  74.  
  75.    The dialog has a check box positioned at the bottom left corner which...
  76.    the user can check to specify that he does not wish to see it again. If...
  77.    checked, calling the function again will not display the dialog, it will...
  78.    simply return a default value immediately.
  79.  
  80.    Procedures to get and set the state of the dialog are also provided so that...
  81.    you can programmatically re-enable a dialog that has been hidden by the user.
  82. }
  83.  
  84. unit DSAMsg;
  85.  
  86. interface
  87.  
  88. uses
  89.   Dialogs, Classes, StdCtrls, Controls,
  90.   {$IFDEF DFS_WIN32}
  91.   Registry, Windows,
  92.   {$ELSE}
  93.   WinTypes,
  94.   {$ENDIF}
  95.   Forms;
  96.  
  97.  
  98.  
  99. {$IFDEF DFS_COMPILER_3_UP}
  100. resourcestring
  101. {$ELSE}
  102. const
  103. {$ENDIF}
  104.   SDontShow = '&Don''t show this message again';
  105.   SDSAGetSpecifierBlank = 'DSAIdentsGetState storage specifier blank';
  106.   SDSASetSpecifierBlank = 'DSAIdentsSetState storage specifier blank';
  107.  
  108.   
  109. const
  110.   { This shuts up C++Builder 3 about the redefiniton being different. There
  111.     seems to be no equivalent in C1.  Sorry. }
  112.   {$IFDEF DFS_CPPB_3_UP}
  113.   {$EXTERNALSYM DFS_COMPONENT_VERSION}
  114.   {$ENDIF}
  115.   DFS_COMPONENT_VERSION = 'DSAMsg Unit v2.17';
  116.  
  117. type
  118. {: The TdfsDSAForm class is a TForm descendant that you can base your forms on...
  119.    to easily provide "Don't Show Again" functionalitiy.  Several properties...
  120.    have been added to provide complete control over where the information...
  121.    on the displayable state of the dialog is stored, but you will often find...
  122.    that simply leaving them blank (which uses default values based on your...
  123.    application) will be sufficient.
  124.  
  125.    The DSA_CheckBox property is key as it defines the TCheckbox component on...
  126.    the form to be used to indicate whether or not the user wishes to see the...
  127.    form in the future or not.  You must assign a TCheckbox to it, or the DSA...
  128.    state can not be saved.
  129.  
  130.    The two key methods that you need to be aware of are DSAShow and...
  131.    DSAShowModal.  Because the Show and ShowModal methods of TForm are not...
  132.    virtual, they can not be overriden by descendants.  Therefore, I had to...
  133.    provide completely new equivalents of these functions.  One nice side...
  134.    effect of this is that if you want to treat the form as DSA in some...
  135.    situations but not others, you would simply call the old methods and not...
  136.    have to fool with making sure it was displayable first.
  137.  
  138.    Design-time support of the new properties is available for Delphi...
  139.    3.  Previous versions of Delphi and C++Builder 1.0 do NOT support...
  140.    design-time access of TForm descendants.  Sorry, just be happy Borland...
  141.    added it to Delphi 3 (and I presume C++B 3.0).  Unlike a normal component,...
  142.    TForm descendant classes must also have a package installed for the...
  143.    registration process to work.  See the installation notes in DSAMsg.Txt...
  144.    for complete installation instructions.
  145.  
  146.    If you are not using Delphi 3, you can still have your forms descend from...
  147.    TdfsDSAForm, you simply won't have design-time access to the properties.  In...
  148.    that case you will have to set the property values in code, most likely in...
  149.    the form's OnCreate event handler or just after calling the form's Create...
  150.    constructor if operating outside of the form's code.
  151.    }
  152.   TdfsDSAForm = class(TForm)
  153.   private
  154.     FDSA_NotShowable: boolean; { Internal flag only! }
  155.     {$IFDEF DFS_WIN32}
  156.     FDSA_UseRegistry: boolean;
  157.     {$ENDIF}
  158.     FDSA_Filename: string;
  159.     FDSA_ID: string;
  160.     FDSA_DefaultResult: integer;
  161.     FDSA_CheckBox: TCheckBox;
  162.  
  163.     procedure SetDSAShowable(Value: boolean);
  164.     function GetDSAShowable: boolean;
  165.   protected
  166.     function GetVersion: string;
  167.     procedure SetVersion(const Val: string);
  168.     procedure Notification(AComponent: TComponent; Operation: TOperation); override;
  169.   public
  170.     { Create creates and initializes an instance of TGradientForm. }
  171.     {: No documentaion, does nothing special the client needs to be aware of. }
  172.     constructor Create(AOwner: TComponent); override;
  173.     {: Destroys an instance of TGradientForm, storing DSA information. The...
  174.        DSA_Checkbox value must still be valid in the destructor, since that...
  175.        is the point at which the DSA information is stored.  You must not...
  176.        free the TCheckbox that is used for DSA purposes or the information...
  177.        cannot be stored. }
  178.     destructor Destroy; override;
  179.  
  180.     {: Shows the form modelessly, or not if the user has requested that it...
  181.        not be shown.  In that case, the window is simply closed.  The...
  182.        instance of the form is not freed unless you have set CloseAction to...
  183.        caFree in then OnClose event handler.
  184.  
  185.        Note that this function MUST be used in place of the normal Show...
  186.        method because Show is not virtual (i.e. it can't be overriden to...
  187.        modify behavior).  One nice side effect of this is that if you want...
  188.        to treat the form as DSA in some situations but not others, you would...
  189.        simply call the Show method and not have to fool with making sure it...
  190.        was displayable first.
  191.     }
  192.     procedure DSAShow;
  193.     {: Shows the form modally, or not if the user has requested that it...
  194.        not be shown.  In that case, the window is simply closed and the value...
  195.        of DSA_DefaultResult is returned.  The instance of the form is not...
  196.        automatically freed, and must be treated as you would any normal TForm.
  197.  
  198.        Note that this function MUST be used in place of the normal ShowModal...
  199.        method because ShowModal is not virtual (i.e. it can't be overriden to...
  200.        modify behavior).  One nice side effect of this is that if you want...
  201.        to treat the form as DSA in some situations but not others, you would...
  202.        simply call the ShowModal method and not have to fool with making sure...
  203.        it was displayable first.
  204.     }
  205.     function DSAShowModal: Integer;
  206.  
  207.     {: Use the DSAClear method to reset form's displayable state.  That is, if...
  208.        the user has elected not to show the form, you can reset it so that...
  209.        it will show up again.
  210.  
  211.        Normally, there is no way to re-enable a form once the user has turned...
  212.        it off since it isn't displayed any longer.  However, it is wise to...
  213.        include the ability to turn these back on in case the user disabled it...
  214.        by accident, or changes its mind.  This functionality is often found in...
  215.        a configuration/settings dialog.
  216.     }
  217.     procedure DSAClear;
  218.   published
  219.     property Version: string
  220.        read GetVersion
  221.        write SetVersion
  222.        stored FALSE;
  223.     {: The DSA_UseRegistry property is used to indicate if the displayable state...
  224.        of the form should be stored in the registry or an INI file.  The...
  225.        actual location in the registry or INI file is controlled by the...
  226.        DSA_Filename and DSA_ID properties.  This property merely indicates...
  227.        how those values should be interpretted.
  228.  
  229.        This property is not avaible under Delphi 1.
  230.     }
  231.     {$IFDEF DFS_WIN32}
  232.     property DSA_UseRegistry: boolean
  233.        read FDSA_UseRegistry write FDSA_UseRegistry;
  234.     {$ENDIF}
  235.     {: DSA_Filename is the INI file name (DSA_UseRegistry = FALSE) or Registry...
  236.        path (Win32 only, DSA_UseRegistry = TRUE) that is used in conjunction...
  237.        with the DSA_ID property to store the displayable state of the form.
  238.  
  239.        If this value is blank, the value of the DefaultFilename global is used.
  240.     }
  241.     property DSA_Filename: string
  242.        read FDSA_Filename write FDSA_Filename;
  243.     {: DSA_ID is the INI section name (DSA_UseRegistry = FALSE) or Registry...
  244.        path subkey (Win32 only, DSA_UseRegistry = TRUE) that is used in...
  245.        conjunction with the DSA_Filename property to store the displayable...
  246.        state of the form.
  247.  
  248.        If this value is blank, the value of the ClassName property is used.
  249.     }
  250.     property DSA_ID: string
  251.        read FDSA_ID write FDSA_ID;
  252.     {: The DSA_DefaultResult property is used to specify what value the...
  253.        DSAShowModal method should return if the user has elected not to...
  254.        display the form.
  255.     }
  256.     property DSA_DefaultResult: integer
  257.        read FDSA_DefaultResult write FDSA_DefaultResult;
  258.     {: The DSA_CheckBox property identifies the TCheckBox component on the...
  259.        form that should be treated as the "Don't Show Again" checkbox.  If...
  260.        this property is blank (NIL), DSA functionality is disabled for the...
  261.        form (i.e. DSAShowModal and DSAShow will always show the form).
  262.  
  263.        Simply assign any existing TCheckBox component on the form to this...
  264.        property and when the form is destroyed, this checkbox will be used...
  265.        to indicate the displayable state of the form for future calls to...
  266.        DSAShow and DSAShowModal.
  267.  
  268.        If the box is checked, that indicates that it should not be shown in...
  269.        the future.  The checkbox's caption should be worded accordingly.
  270.     }
  271.     property DSA_CheckBox: TCheckBox
  272.        read FDSA_CheckBox write FDSA_CheckBox;
  273.     {: The DSA_Showable property is used to check or set the displayable state...
  274.        of the form.
  275.  
  276.        Normally, there is no way to re-enable a form once the user has turned...
  277.        it off since it isn't displayed any longer.  However, it is wise to...
  278.        include the ability to turn these back on in case the user disabled it...
  279.        by accident, or changes its mind.  This functionality is often found in...
  280.        a configuration/settings dialog.
  281.  
  282.        Setting this value to FALSE is equivalent to calling the DSAClear method.
  283.     }
  284.     property DSA_Showable: boolean
  285.        read GetDSAShowable write SetDSAShowable;
  286.   end;
  287.  
  288.  
  289. {: A TForm.ShowModal replacement function.  This function will display the...
  290.    form passed in the AForm parameter using the form class' ShowModal...
  291.    function.  However, before ShowModal is called, the function will add a...
  292.    check box in the bottom left corner of the form.  If the user checks it...
  293.    before closing the form, the form will not be displayed in the future...
  294.    when this function is called.
  295.  
  296.    The text that appears next to the check box is "Don't show this message...
  297.    again", but this can be changed by using the DontShowMsgText global variable.
  298.  
  299.    If the user elects not to display the form in the future, this function...
  300.    stores a value in an INI file or the registry (Win32 only) to identify...
  301.    this fact.  Where this value is stored is controlled by three global...
  302.    variables defined in the DSAMsg unit: UseRegistry, RegRootKey, and...
  303.    DefaultFilename.  These values can be changed in your program if you so...
  304.    desire.  A unique identifier based on the class name of the form will also...
  305.    be used.  If you need more precise control over the storage location, you...
  306.    should use the DSAIdentsShowModal function.
  307.  
  308.    If you need to re-enable a form that has been disabled, you can use the...
  309.    DSAFormClear function, passing it the class type of the form variable you...
  310.    passed to this function.  The form will then be displayed when this...
  311.    function is called.
  312.  
  313.    AForm is an instance of the form you want to display already created.  The...
  314.    DefaultResult value is used to specify what value to return if the user...
  315.    has elected not to display the form.
  316.  
  317.    DSAShowModal returns the same value that TForm.ShowModal returns, except...
  318.    if the form is not displayed.  In that case, the value of the...
  319.    DefaultResult parameter is returned.
  320.  
  321.    $<EXAMPLE> }
  322. function DSAShowModal(const AForm: TForm; DefaultResult: word): Word;
  323.  
  324.  
  325. {: A TForm.ShowModal replacement function.  This function will display the...
  326.    form passed in the AForm parameter using the form class' ShowModal...
  327.    function.  However, before ShowModal is called, the function will add a...
  328.    check box in the bottom left corner of the form.  If the user checks it...
  329.    before closing the form, the form will not be displayed in the future...
  330.    when this function is called.
  331.  
  332.    The text that appears next to the check box is "Don't show this message...
  333.    again", but this can be changed by using the DontShowMsgText global variable.
  334.  
  335.    If the user elects not to display the form in the future, this function...
  336.    stores a value in an INI file or the registry (Win32 only) to identify...
  337.    this fact.  Where this value is stored is controlled by the Filename and...
  338.    ID parameters, along with three global variables defined in the DSAMsg...
  339.    unit: UseRegistry, RegRootKey, and DefaultFilename.  These values can be...
  340.    changed in your program if you so desire.  If you leave the Filename...
  341.    parameter blank, the value in DefaultFilename will be used.  If this is...
  342.    also blank, or if ID is blank, an exception will be raised.
  343.  
  344.    If you need to re-enable a form that has been disabled, you can use the...
  345.    DSAIdentsClear function, passing it the same Filename and ID parameters as...
  346.    you passed to this function.  The form will then be displayed when this...
  347.    function is called.
  348.  
  349.    AForm is an instance of the form you want to display already...
  350.    created.  Filename is the INI file name or Registry path (Win32 only) that...
  351.    is used in conjunction with the ID identifier to store the displayable...
  352.    state of the dialog.  DefaultResult value is used to specify what value to...
  353.    return if the user has elected not to display the form.
  354.  
  355.    DSAIdentsShowModal returns the same value that TForm.ShowModal returns,...
  356.    except if the form is not displayed.  In that case, the value of the...
  357.    DefaultResult parameter is returned.
  358.  
  359.    $<EXAMPLE> }
  360. function DSAIdentsShowModal(const AForm: TForm; Filename, ID: string;
  361.    DefaultResult: word): Word;
  362.  
  363.  
  364. {: A MessageDlg replacement function.  This function will display a dialog...
  365.    that is identical to the one that MessageDlg will display, except it will...
  366.    also include a check box in the bottom left corner of the dialog.  If the...
  367.    user checks it before closing the dialog, the dialog will not be displayed...
  368.    in the future when this function is called.
  369.  
  370.    The text that appears next to the check box is "Don't show this message...
  371.    again", but this can be changed by using the DontShowMsgText global variable.
  372.  
  373.    If the user elects not to display the dialog in the future, this function...
  374.    stores a value in an INI file or the registry (Win32 only) to identify...
  375.    this fact.  Where this value is stored is controlled by three global...
  376.    variables defined in the DSAMsg unit: UseRegistry, RegRootKey, and...
  377.    DefaultFilename.  These values can be changed in your program if you so...
  378.    desire.  A unique identifier based on the Msg parameter will also be...
  379.    used.  If you need more precise control over the storage location, you...
  380.    should use the DSAIdentsMessageDlg.
  381.  
  382.    If you need to re-enable a dialog that has been disabled, you can use the...
  383.    DSAClear function, passing it the same Msg parameter as you pass to this...
  384.    function.  The dialog will then be displayed when this function is called.
  385.  
  386.    The message box displays the value of the Msg parameter.  Use the AType...
  387.    parameter to indicate the purpose of the dialog.  Use the AButtons...
  388.    parameter to indicate what buttons should appear in the message box.  Use...
  389.    the HelpCtx parameter to specify the context ID for the help topic that...
  390.    should appear when the user clicks the help button or presses F1 while the...
  391.    dialog is displayed. Use the DefaultResult value to specify what value to...
  392.    return if the user has elected not to display the dialog.
  393.  
  394.    DSAMessageDlg returns the value of the button the user selected, or the...
  395.    value of the DefaultResult parameter if the dialog was not displayed. These...
  396.    are the possible return values if DefaultResult is not used:
  397.  
  398.        mrNone    mrAbort    mrYes
  399.        mrOk    mrRetry    mrNo
  400.        mrCancel    mrIgnore    mrAll
  401.  
  402.    $<EXAMPLE> }
  403. function DSAMessageDlg(const Msg: string; AType: TMsgDlgType;
  404.    AButtons: TMsgDlgButtons; HelpCtx: Longint; DefaultResult: word): Word;
  405.  
  406.  
  407. {: A MessageDlg replacement function.  This function will display a dialog...
  408.    that is identical to the one that MessageDlg will display, except it will...
  409.    also include a check box in the bottom left corner of the dialog.  If the...
  410.    user checks it before closing the dialog, the dialog will not be displayed...
  411.    in the future when this function is called.
  412.  
  413.    The text that appears next to the check box is "Don't show this message...
  414.    again", but this can be changed by using the DontShowMsgText global variable.
  415.  
  416.    If the user elects not to display the dialog in the future, this function...
  417.    stores a value in an INI file or the registry (Win32 only) to identify...
  418.    this fact.  Where this value is stored is controlled by the Filename and...
  419.    ID parameters, along with three global variables defined in the DSAMsg...
  420.    unit: UseRegistry, RegRootKey, and DefaultFilename.  These values can be...
  421.    changed in your program if you so desire.  If you leave the Filename...
  422.    parameter blank, the value in DefaultFilename will be used.  If this is...
  423.    also blank, or if ID is blank, an exception will be raised.
  424.  
  425.    If you need to re-enable a dialog that has been disabled, you can use the...
  426.    DSAIdentsClear function, passing it the same Filename and ID parameters as...
  427.    you pass to this function.  The dialog will then be displayed when this...
  428.    function is called.
  429.  
  430.    The message box displays the value of the Msg parameter.  Use the AType...
  431.    parameter to indicate the purpose of the dialog.  Use the AButtons...
  432.    parameter to indicate what buttons should appear in the message box.  Use...
  433.    the HelpCtx parameter to specify the context ID for the help topic that...
  434.    should appear when the user clicks the help button or presses F1 while the...
  435.    dialog is displayed.  Filename is the INI file name or Registry path...
  436.    (Win32 only) that is used in conjunction with the ID identifier to store...
  437.    the displayable state of the dialog.  Use the DefaultResult value to...
  438.    specify what value to return if the user has elected not to display the...
  439.    dialog.
  440.  
  441.    DSAIdentsMessageDlg returns the value of the button the user selected, or...
  442.    the value of the DefaultResult parameter if the dialog was not...
  443.    displayed. These are the possible return values if DefaultResult is not used:
  444.  
  445.        mrNone    mrAbort    mrYes
  446.        mrOk    mrRetry    mrNo
  447.        mrCancel    mrIgnore    mrAll
  448.  
  449.    $<EXAMPLE> }
  450. function DSAIdentsMessageDlg(const Msg: string; AType: TMsgDlgType;
  451.    AButtons: TMsgDlgButtons; HelpCtx: Longint; Filename, ID: string;
  452.    DefaultResult: word): Word;
  453.  
  454.  
  455. {: Use the DSAFormClear procedure to reset a DSAShowModal form that has been...
  456.    disabled by the user.  Simply pass the class type of the form that was...
  457.    passed to the DSAShowModal function.
  458.  
  459.    Normally, there is no way to re-enable a dialog once the user has turned...
  460.    it off since it isn't displayed any longer.  However, it is wise to...
  461.    include the ability to turn these back on in case the user disabled it...
  462.    by accident, or changes its mind.  This functionality is often found in...
  463.    a configuration/settings dialog.
  464.  
  465.    $<EXAMPLE> }
  466. procedure DSAFormClear(const AFormClass: TFormClass);
  467.  
  468.  
  469. {: Use the DSAClear procedure to reset a DSAMessageDlg dialog that has been...
  470.    disabled by the user.  Simply pass the same text in the Msg parameter as...
  471.    you do in the Msg parameter of the DSAMessageDlg function.
  472.  
  473.    Normally, there is no way to re-enable a dialog once the user has turned...
  474.    it off since it isn't displayed any longer.  However, it is wise to...
  475.    include the ability to turn these back on in case the user disabled it...
  476.    by accident, or changes its mind.  This functionality is often found in...
  477.    a configuration/settings dialog.
  478.  
  479.    $<EXAMPLE> }
  480. procedure DSAClear(const Msg: string);
  481.  
  482.  
  483. {: Use the DSAIdentsClear procedure to reset a DSAIdentsMessageDlg dialog..
  484.    that has been disabled by the user.  Simply pass the same values in the...
  485.    Filename and ID parameters as you do in the Filename and ID parameters of...
  486.    the DSAIdentsMessageDlg function.
  487.  
  488.    Normally, there is no way to re-enable a dialog once the user has turned...
  489.    it off since it isn't displayed any longer.  However, it is wise to...
  490.    include the ability to turn these back on in case the user disabled it...
  491.    by accident, or changes its mind.  This functionality is often found in...
  492.    a configuration/settings dialog.
  493.  
  494.    $<EXAMPLE>
  495. }
  496. procedure DSAIdentsClear(Filename, ID: string);
  497.  
  498.  
  499. {: This routine allows you to get the displayable state a form that is used...
  500.    with the DSAShowModal or DSAIdentsShowModal function.
  501.  
  502.    Simply pass the form class to the function and if the form has been...
  503.    disabled by the user, this function returns FALSE; otherwise, TRUE is...
  504.    returned.
  505.  
  506.    This function is useful when allowing users to restore DSA dialogs that...
  507.    they have hidden.
  508.  
  509.    $<EXAMPLE> }
  510. function DSAFormGetState(const AFormClass: TFormClass): boolean;
  511.  
  512.  
  513. {: This routine allows you to set the displayable state a form that is used...
  514.    with the DSAShowModal or DSAIdentsShowModal function.
  515.  
  516.    Simply pass the form class to the function and a boolean value indicating...
  517.    whether or not the form should be displayed.
  518.  
  519.    This function is useful when allowing users to override DSA dialogs...
  520.    settings, in a configuration dialog for instance.
  521.  
  522.    $<EXAMPLE> }
  523. procedure DSAFormSetState(const AFormClass: TFormClass; Value: boolean);
  524.  
  525.  
  526. {: This routine allows you to get the displayable state for a dialog that is...
  527.    used with the DSAMessageDlg function.
  528.  
  529.    Simply pass the same message string to the function that is passed to the...
  530.    DSAMessageDlg function and if the dialog has been disabled by the user,...
  531.    this function returns FALSE; otherwise, TRUE is returned.
  532.  
  533.    This function is useful when allowing users to restore DSA dialogs that...
  534.    they have hidden.
  535.  
  536.    $<EXAMPLE> }
  537. function DSAGetState(Msg: string): boolean;
  538.  
  539.  
  540. {: This routine allows you to set the displayable state for a dialog that is...
  541.    used with the DSAMessageDlg function.
  542.  
  543.    Simply pass the same message string to the function that is passed to the...
  544.    DSAMessageDlg function and a boolean value indicating whether or not the...
  545.    dialog should be displayed by DSAMessageDlg.
  546.  
  547.    This function is useful when allowing users to set preferences for showing...
  548.    or hiding DSA dialogs from a central location (say a configuration dialog...
  549.    that lists all DSA dialogs).
  550.  
  551.    $<EXAMPLE> }
  552. procedure DSASetState(Msg: string; Value: boolean);
  553.  
  554.  
  555. {: This routine allows you to get the displayable state for a dialog that is...
  556.    used with the DSAIdentsMessageDlg function.
  557.  
  558.    Simply pass the same Filename and ID parameters to the function that are...
  559.    passed to the DSAIdentsMessageDlg function and if the dialog has been...
  560.    disabled by the user, this function returns FALSE; otherwise, TRUE is...
  561.    returned.
  562.  
  563.    This function is useful when allowing users to restore DSA dialogs that...
  564.    they have hidden.
  565.  
  566.    $<EXAMPLE> }
  567. function DSAIdentsGetState(Filename, ID: string): boolean;
  568.  
  569.  
  570. {: This routine allows you to set the displayable state for a dialog that is...
  571.    used with the DSAIdentsMessageDlg function.
  572.  
  573.    Simply pass the same Filename and ID parameters to the function that are...
  574.    passed to the DSAIdentsMessageDlg function and and a boolean value...
  575.    indicating whether or not the dialog should be displayed by...
  576.    DSAIdentsMessageDlg.
  577.  
  578.    This function is useful when allowing users to set preferences for showing...
  579.    or hiding DSA dialogs from a central location (say a configuration dialog...
  580.    that lists all DSA dialogs).
  581.  
  582.    $<EXAMPLE> }
  583. procedure DSAIdentsSetState(Filename, ID: string; Value: boolean);
  584.  
  585.  
  586. const
  587.   {: This constant is the string that is assigned to the Name property of the...
  588.      checkbox that is created by the various DSA dialog functions.  It is...
  589.      included in case you ever needed to find the checkbox component.  You...
  590.      can simply search for it using the FindComponent method, passing this...
  591.      value as the parameter. 
  592.  
  593.    $<EXAMPLE> }
  594.   DSA_CHECKBOX_NAME = '__DSA_CheckBox'; { in case you ever need to find it. }
  595.  
  596. {$IFDEF DFS_WIN32}
  597. {$WRITEABLECONST ON}
  598.   {: This writeable constant (also known as a static variable) allows you to...
  599.      control whether the dialog display state storage uses the registry or an...
  600.      INI file.  By default, the registry is used for Win32 (Windows 95 and...
  601.      Windows NT), but simply setting this to FALSE will cause values to saved...
  602.      in an INI file.
  603.  
  604.      This is only available under Win32.  It does not exist in Delphi 1 since...
  605.      the registry is not the same as it is in Win32.  Only INI files can be...
  606.      used in Delphi 1.
  607.  
  608.    $<EXAMPLE> }
  609.   UseRegistry: boolean = TRUE;
  610.  
  611.   {: This writeable constant (also known as a static variable) allows you to...
  612.      control which root registry key is used when storing dialog display...
  613.      state information to the registry.  By default, the HKEY_CURRENT_USER...
  614.      key is used, as that is the recommend key for applications to use...
  615.      However, you may assign any of the HKEY_* constants to this to change...
  616.      the root key.
  617.  
  618.      This is only available under Win32.  It does not exist in Delphi 1 since...
  619.      the registry is not the same as it is in Win32.  Only INI files can be...
  620.      used in Delphi 1.
  621.  
  622.    $<EXAMPLE> }
  623.   RegRootKey: HKey = HKEY_CURRENT_USER;
  624.  
  625. {$ENDIF}
  626.  
  627.   {: This writeable constant (also known as a static variable) allows you to...
  628.      control the default registry key or INI filename to use when storing...
  629.      dialog display state information.
  630.  
  631.      This value is used by DSAMessageDlg, and also by DSAIdentsMessageDlg...
  632.      when the Filename parameter has been left blank.
  633.  
  634.      If you are compiling for Win32, the default is 'Software\your_app_title\...
  635.      DSADialogs\' where 'your_app_title' is the value returned by...
  636.      Application.Title.
  637.  
  638.      If you are compiling for Win16, the default is an INI file with the same...
  639.      name as your executable, and in the same directory.
  640.  
  641.    $<EXAMPLE> }
  642.   DefaultFilename: string = ''; { Value set in initialization section }
  643.  
  644.   {: This writeable constant (also known as a static variable) allows you to...
  645.      control the text that appears next to the check box.  By default, this...
  646.      value is "&Don't show this message again".  If you do not like this, or...
  647.      if using a foreign language, you can change the text by assigning your...
  648.      own value.
  649.  
  650.    $<EXAMPLE> }
  651.   DontShowMsgText: string = SDontShow;
  652.  
  653.   { Allowable characters in INI/registry keys.  Modified in InitValidChars below}
  654.   Valid_Key_chars: set of char = ['~', '!', '@', '#', '$', '%', '^', '&',
  655.      '_', '-'];
  656.  
  657.  
  658. implementation
  659.  
  660. uses
  661.   SysUtils, WinProcs, IniFiles;
  662.  
  663.  
  664. {$IFDEF DFS_DELPHI_1}
  665. function Trim(const S: string): string;
  666. var
  667.   I, L: Integer;
  668. begin
  669.   L := Length(S);
  670.   I := 1;
  671.   while (I <= L) and (S[I] <= ' ') do Inc(I);
  672.   if I > L then Result := '' else
  673.   begin
  674.     while S[L] <= ' ' do Dec(L);
  675.     Result := Copy(S, I, L - I + 1);
  676.   end;
  677. end;
  678. {$ENDIF}
  679.  
  680.  
  681. { Utility function to strip invalid characters from INI and registry keys }
  682. function StripInvalidChars(const S: string; AllowSlash: boolean): string;
  683. var
  684.   x: integer;
  685. begin
  686.   Result := '';
  687.   for x := 1 to Length(S) do
  688.   begin
  689.     if (S[x] in ['\', '.', ':']) and AllowSlash then
  690.       Result := Result + S[x]
  691.     else if S[x] in Valid_Key_Chars then
  692.       Result := Result + S[x]
  693.     else
  694.       Result := Result + ' ';
  695.   end;
  696.   { Also have to strip leading/trailing blanks or it messes up INI sections }
  697.   Result := Trim(Result);
  698. end;
  699.  
  700.  
  701. { Create creates and initializes an instance of TdfsDSAForm. }
  702. constructor TdfsDSAForm.Create(AOwner: TComponent);
  703. begin
  704.   FDSA_NotShowable := FALSE;
  705.   {$IFDEF DFS_WIN32}
  706.   FDSA_UseRegistry := TRUE;
  707.   {$ENDIF}
  708.   FDSA_DefaultResult := mrOk;
  709.  
  710.   { have to call after so we don't stomp on stuff that may happen in OnCreate }
  711.   inherited Create(AOwner);
  712. end;
  713.  
  714.  
  715. destructor TdfsDSAForm.Destroy;
  716. var
  717.   {$IFDEF DFS_WIN32}
  718.   OldUseReg: boolean;
  719.   {$ENDIF}
  720.   AnID: string;
  721. begin
  722.   if assigned(FDSA_CheckBox) and (not FDSA_NotShowable) then
  723.   begin
  724.     if DSA_ID = '' then
  725.       AnID := ClassName
  726.     else
  727.       AnID := DSA_ID;
  728.  
  729.     {$IFDEF DFS_WIN32}
  730.     OldUseReg := UseRegistry;
  731.     UseRegistry := DSA_UseRegistry;
  732.     try
  733.     {$ENDIF}
  734.       DSAIdentsSetState(DSA_Filename, AnID, not DSA_CheckBox.Checked);
  735.     {$IFDEF DFS_WIN32}
  736.     finally
  737.       UseRegistry := OldUseReg;
  738.     end;
  739.     {$ENDIF}
  740.   end;
  741.  
  742.   inherited Destroy;
  743. end;
  744.  
  745. function TdfsDSAForm.GetVersion: string;
  746. begin
  747.   Result := DFS_COMPONENT_VERSION;
  748. end;
  749.  
  750. procedure TdfsDSAForm.SetVersion(const Val: string);
  751. begin
  752.   { empty write method, just needed to get it to show up in Object Inspector }
  753. end;
  754.  
  755. procedure TdfsDSAForm.Notification(AComponent: TComponent; Operation: TOperation);
  756. begin
  757.   if Operation = opRemove then
  758.   begin
  759.     if AComponent = FDSA_CheckBox then
  760.       FDSA_CheckBox := NIL;
  761.   end else begin  { opInsert }
  762.     if (FDSA_CheckBox = NIL) and (AComponent is TCheckBox) then
  763.       FDSA_CheckBox := TCheckBox(AComponent);
  764.   end;
  765.  
  766.   inherited Notification(AComponent, Operation);
  767. end;
  768.  
  769.  
  770. procedure TdfsDSAForm.SetDSAShowable(Value: boolean);
  771. {$IFDEF DFS_WIN32}
  772. var
  773.   OldUseReg: boolean;
  774. {$ENDIF}
  775. begin
  776.   if ([csLoading, csReading] * ComponentState) <> [] then
  777.     exit; // Don't go setting values when we are reading the form.
  778.     
  779.   {$IFDEF DFS_WIN32}
  780.   OldUseReg := UseRegistry;
  781.   UseRegistry := DSA_UseRegistry;
  782.   try
  783.   {$ENDIF}
  784.     if DSA_ID = '' then
  785.       DSAFormSetState(TFormClass(ClassType), Value)
  786.     else
  787.       DSAIdentsSetState(DSA_Filename, DSA_ID, Value);
  788.   {$IFDEF DFS_WIN32}
  789.   finally
  790.     UseRegistry := OldUseReg;
  791.   end;
  792.   {$ENDIF}
  793. end;
  794.  
  795.  
  796. function TdfsDSAForm.GetDSAShowable: boolean;
  797. {$IFDEF DFS_WIN32}
  798. var
  799.   OldUseReg: boolean;
  800. {$ENDIF}
  801. begin
  802.   {$IFDEF DFS_WIN32}
  803.   OldUseReg := UseRegistry;
  804.   UseRegistry := DSA_UseRegistry;
  805.   try
  806.   {$ENDIF}
  807.     if DSA_ID = '' then
  808.       Result := DSAFormGetState(TFormClass(ClassType))
  809.     else
  810.       Result := DSAIdentsGetState(DSA_Filename, DSA_ID);
  811.   {$IFDEF DFS_WIN32}
  812.   finally
  813.     UseRegistry := OldUseReg;
  814.   end;
  815.   {$ENDIF}
  816. end;
  817.  
  818.  
  819. procedure TdfsDSAForm.DSAShow;
  820. begin
  821.   if (DSA_CheckBox = NIL) or DSA_Showable then
  822.     Show
  823.   else begin
  824.     { Flag it so we don't overwrite with the checkbox value }
  825.     FDSA_NotShowable := TRUE;
  826.     Close;
  827.   end;
  828. end;
  829.  
  830.  
  831. function TdfsDSAForm.DSAShowModal: Integer;
  832. begin
  833.   if DSA_CheckBox = NIL then
  834.   begin
  835.     Result := ShowModal;
  836.     exit;
  837.   end;
  838.  
  839.   if DSA_Showable then
  840.   begin
  841.     Result := ShowModal;
  842.     { Something may have whacked the checkbox, take no chances }
  843.     if DSA_CheckBox <> NIL then
  844.       DSA_Showable := not DSA_CheckBox.Checked;
  845.   end else begin
  846.     { Flag it so we don't overwrite with the checkbox value }
  847.     FDSA_NotShowable := TRUE;
  848.     Close;
  849.     Result := DSA_DefaultResult;
  850.   end;
  851. end;
  852.  
  853. procedure TdfsDSAForm.DSAClear;
  854. begin
  855.   DSA_Showable := TRUE;
  856. end;
  857.  
  858.  
  859.  
  860.  
  861. function DSAShowModal(const AForm: TForm; DefaultResult: word): Word;
  862. begin
  863.   Result := DSAIdentsShowModal(AForm, '', '', DefaultResult);
  864. end;
  865.  
  866.  
  867.  
  868. function DSAIdentsShowModal(const AForm: TForm; Filename, ID: string;
  869.    DefaultResult: word): Word;
  870. var
  871.   DSA: TCheckBox;
  872.   EdgeCtl: TControl;
  873.   TopCtl: TControl;
  874.   x: integer;
  875. begin
  876.   Result := DefaultResult;
  877.   if AForm = NIL then exit;
  878.  
  879.   if ID = '' then
  880.     ID := AForm.ClassName;
  881.  
  882.   if not DSAIdentsGetState(Filename, ID) then
  883.     exit;
  884.  
  885.   DSA := NIL;
  886.   { Find left edge of the left-most control on the form }
  887.   EdgeCtl := NIL;
  888.   TopCtl := NIL;
  889.   for x := 0 to AForm.ControlCount-1 do
  890.   begin
  891.     if EdgeCtl = NIL then
  892.       EdgeCtl := AForm.Controls[x]
  893.     else
  894.       if AForm.Controls[x].Left < EdgeCtl.Left then
  895.         EdgeCtl := AForm.Controls[x];
  896.     if TopCtl = NIL then
  897.       TopCtl := AForm.Controls[x]
  898.     else
  899.       if AForm.Controls[x].Top < TopCtl.Top then
  900.         TopCtl := AForm.Controls[x];
  901.   end;
  902.   if (EdgeCtl <> NIL) and (TopCtl <> NIL) then
  903.   begin
  904.     { It's possible that this form has already has the checkbox on it, i.e. it
  905.       has been passed to this function before without being freed.  Find out. }
  906.     DSA := TCheckBox(AForm.FindComponent(DSA_CHECKBOX_NAME));
  907.     if DSA = NIL then
  908.     begin
  909.       DSA := TCheckBox.Create(AForm);
  910.       DSA.Name := DSA_CHECKBOX_NAME;
  911.       DSA.Parent := AForm;
  912.     end;
  913.  
  914.     DSA.Caption := DontShowMsgText;
  915.     DSA.Width := AForm.Canvas.TextWidth(DontShowMsgText) + 19;
  916.  
  917.     { Position the checkbox at the bottom }
  918.     DSA.Left := EdgeCtl.Left;
  919.     DSA.Top := AForm.ClientHeight;
  920.     { Make room for the checkbox }
  921.     AForm.ClientHeight := AForm.ClientHeight + DSA.Height + TopCtl.Top;
  922.     { Make sure it's wide enough }
  923.     if (DSA.Width + (EdgeCtl.Left * 2)) > AForm.ClientWidth then
  924.       AForm.ClientWidth := DSA.Width + (EdgeCtl.Left * 2);
  925.     { Recenter it if we should }
  926.     if AForm.Position = poScreenCenter then
  927.       AForm.Top := (Screen.Height div 2) - (AForm.Height div 2);
  928.   end;
  929.  
  930.   Result := AForm.ShowModal;
  931.  
  932.   if DSA <> NIL then
  933.     DSAIdentsSetState(Filename, ID, not DSA.Checked);
  934.   { Don't need to free DSA item because it is owned by the form.  It will do it
  935.     when it is freed. }
  936. end;
  937.  
  938.  
  939. function DSAMessageDlg(const Msg: string; AType: TMsgDlgType;
  940.    AButtons: TMsgDlgButtons; HelpCtx: Longint; DefaultResult: word): Word;
  941. begin
  942.   Result := DSAIdentsMessageDlg(Msg, AType, AButtons, HelpCtx, '', '',
  943.      DefaultResult);
  944. end;
  945.  
  946. function DSAIdentsMessageDlg(const Msg: string; AType: TMsgDlgType;
  947.    AButtons: TMsgDlgButtons; HelpCtx: Longint; Filename, ID: string;
  948.    DefaultResult: word): Word;
  949. var
  950.   Dlg: TForm;
  951.   DSA: TCheckBox;
  952.   EdgeCtl: TControl;
  953. begin
  954.   Result := DefaultResult;
  955.   if ID = '' then
  956.     ID := Msg;
  957.  
  958.   if not DSAIdentsGetState(Filename, ID) then
  959.     exit;
  960.  
  961.   Dlg := CreateMessageDialog(Msg, AType, AButtons);
  962.   try
  963.     Dlg.HelpContext := HelpCtx;
  964.  
  965.     { DSA stuff }
  966.     DSA := TCheckBox.Create(Dlg);
  967.     DSA.Name := DSA_CHECKBOX_NAME;
  968.     DSA.Parent := Dlg;
  969.     DSA.Caption := DontShowMsgText;
  970.     DSA.Width := Dlg.Canvas.TextWidth(DontShowMsgText) + 19;
  971.     { Find left edge of a known control }
  972.     EdgeCtl := TControl(Dlg.FindComponent('Image'));
  973.     if EdgeCtl = NIL then { must be mtCustom type }
  974.       EdgeCtl := TControl(Dlg.FindComponent('Message'));
  975.     if EdgeCtl = NIL then begin { I give up }
  976.       DSA.Free;
  977.       DSA := NIL;
  978.     end else begin
  979.       { Position the checkbox at the bottom }
  980.       DSA.Left := EdgeCtl.Left;
  981.       DSA.Top := Dlg.ClientHeight;
  982.       { Make room for the checkbox }
  983.       Dlg.ClientHeight := Dlg.ClientHeight + DSA.Height + EdgeCtl.Top;
  984.       { Make sure it's wide enough }
  985.       if (DSA.Width + (EdgeCtl.Left * 2)) > Dlg.ClientWidth then
  986.         Dlg.ClientWidth := DSA.Width + (EdgeCtl.Left * 2);
  987.       { Recenter it }
  988.       Dlg.Top := (Screen.Height div 2) - (Dlg.Height div 2);
  989.     end;
  990.  
  991.     Result := Dlg.ShowModal;
  992.  
  993.     if DSA <> NIL then
  994.       DSAIdentsSetState(Filename, ID, not DSA.Checked);
  995.   finally
  996.     Dlg.Free;
  997.   end;
  998.   { Don't need to free DSA item because it is owned by the form.  It will do it
  999.     when it is freed. }
  1000. end;
  1001.  
  1002. procedure DSAIdentsClear(Filename, ID: string);
  1003. begin
  1004.   DSAIdentsSetState(Filename, ID, TRUE);
  1005. end;
  1006.  
  1007. procedure DSAClear(const Msg: string);
  1008. begin
  1009.   DSAIdentsSetState('', Msg, TRUE);
  1010. end;
  1011.  
  1012.  
  1013. procedure DSAFormClear(const AFormClass: TFormClass);
  1014. begin
  1015.   DSAIdentsSetState('', AFormClass.ClassName, TRUE);
  1016. end;
  1017.  
  1018.  
  1019. function DSAFormGetState(const AFormClass: TFormClass): boolean;
  1020. begin
  1021.   Result := DSAGetState(AFormClass.ClassName);
  1022. end;
  1023.  
  1024.  
  1025. procedure DSAFormSetState(const AFormClass: TFormClass; Value: boolean);
  1026. begin
  1027.   DSASetState(AFormClass.ClassName, Value);
  1028. end;
  1029.  
  1030.  
  1031. function DSAGetState(Msg: string): boolean;
  1032. begin
  1033.   Result := DSAIdentsGetState('', Msg);
  1034. end;
  1035.  
  1036.  
  1037. procedure DSASetState(Msg: string; Value: boolean);
  1038. begin
  1039.   DSAIdentsSetState('', Msg, Value);
  1040. end;
  1041.  
  1042.  
  1043. function DSAIdentsGetState(Filename, ID: string): boolean;
  1044. var
  1045.   INI: TIniFile;
  1046.   {$IFDEF DFS_WIN32}
  1047.   Reg: TRegistry;
  1048.   {$ENDIF}
  1049. begin
  1050.   Result := TRUE;
  1051.  
  1052.   if Filename = '' then
  1053.     Filename := DefaultFilename;
  1054.  
  1055.   ID := StripInvalidChars(ID, FALSE);
  1056.   Filename := StripInvalidChars(Filename, TRUE);
  1057.   if (ID = '') or (Filename = '') then
  1058.     raise Exception.Create(SDSAGetSpecifierBlank);
  1059.  
  1060.   {$IFDEF DFS_WIN32}
  1061.   if UseRegistry then
  1062.   begin
  1063.     if FileName[Length(Filename)] <> '\' then
  1064.       FileName := Filename + '\';
  1065.     Filename := Filename + ID;
  1066.     Reg := TRegistry.Create;
  1067.     try
  1068.       Reg.RootKey := RegRootKey;
  1069.       if Reg.OpenKey(Filename, FALSE) then
  1070.       begin
  1071.         try
  1072.           Result := not Reg.ReadBool('DontShow');
  1073.         except
  1074.           Result := TRUE;
  1075.         end;
  1076.         Reg.CloseKey;
  1077.       end;
  1078.     finally
  1079.       Reg.Free;
  1080.     end;
  1081.   end else
  1082.   {$ENDIF}
  1083.   begin
  1084.     INI := TIniFile.Create(Filename);
  1085.     try
  1086.       Result := not INI.ReadBool(ID, 'DontShow', FALSE);
  1087.     finally
  1088.       INI.Free;
  1089.     end;
  1090.   end;
  1091. end;
  1092.  
  1093.  
  1094. procedure DSAIdentsSetState(Filename, ID: string; Value: boolean);
  1095. var
  1096.   INI: TIniFile;
  1097.   {$IFDEF DFS_WIN32}
  1098.   Reg: TRegistry;
  1099.   {$ENDIF}
  1100. begin
  1101.   if Filename = '' then
  1102.     Filename := DefaultFilename;
  1103.  
  1104.   ID := StripInvalidChars(ID, FALSE);
  1105.   Filename := StripInvalidChars(Filename, TRUE);
  1106.   if (ID = '') or (Filename = '') then
  1107.     raise Exception.Create(SDSASetSpecifierBlank);
  1108.  
  1109.   {$IFDEF DFS_WIN32}
  1110.   if UseRegistry then
  1111.   begin
  1112.     if FileName[Length(Filename)] <> '\' then
  1113.       FileName := Filename + '\';
  1114.     Filename := Filename + ID;
  1115.     Reg := TRegistry.Create;
  1116.     try
  1117.       Reg.RootKey := RegRootKey;
  1118.       if Reg.OpenKey(Filename, TRUE) then
  1119.       begin
  1120.         try
  1121.           Reg.WriteBool('DontShow', not Value);
  1122.         except
  1123.           { do nothing };
  1124.         end;
  1125.         Reg.CloseKey;
  1126.       end;
  1127.     finally
  1128.       Reg.Free;
  1129.     end;
  1130.   end else
  1131.   {$ENDIF}
  1132.   begin
  1133.     INI := TIniFile.Create(Filename);
  1134.     try
  1135.       INI.WriteBool(ID, 'DontShow', not Value);
  1136.     finally
  1137.       INI.Free;
  1138.     end;
  1139.   end;
  1140. end;
  1141.  
  1142. procedure InitValidChars;
  1143. var
  1144.   c: Char;
  1145. begin
  1146.   for c := #0 to #255 do
  1147.     { ask Windows if it is alphanumeric.  This is for international chars }
  1148.     if IsCharAlphaNumeric(c) then
  1149.       Valid_Key_Chars := Valid_Key_Chars + [c];
  1150. end;
  1151.  
  1152.  
  1153. initialization
  1154.   InitValidChars;
  1155.   {$IFDEF DFS_WIN32}
  1156.   DefaultFilename := 'Software\' + Application.Title + '\DSADialogs';
  1157.   {$ELSE}
  1158.   DefaultFilename := ChangeFileExt(Application.EXEName, '.INI');
  1159.   {$ENDIF}
  1160. end.
  1161.  
  1162.