Search Results for

    Show / Hide Table of Contents

    Integrated Development Environment

    TMS Scripter includes a ready-to-use IDE for writing scripts and designing forms. This chapter covers how to use that IDE and how to use additional components to build your own IDE. The IDE is only available for VCL applications.

    Specific IDE components

    TMS Scripter is a full scripting package for editing, debugging and running scripts and forms in Delphi and C++ Builder environment.

    Basic concepts

    TMS Scripter provides a set of components for scripting and designing. In summary, we can separate the usage in runtime and design time.

    Runtime

    For runtime execution, the main component to use is TIDEScripter. This component descends from TatScripter which descends from TatCustomScripter, so it has all functionalities of other scripter components present in previous versions and editions of TMS Scripter.

    TIDEScripter is the scripter engine which runs scripts. So, basically, it holds a collection of one or more scripts that can be executed. To see all tasks that can be done with TIDEScripter component, please refer to Working with scripter topic. To see a reference about the languages supported in script, and the syntax of each language, please refer to Language Features.

    Design time

    TMS Scripter provides several components that will allow your end-user to write and design scripts and script projects. Basically you can provide an Integrated Development Environment for your end-user to build script projects, create forms, and write scripts. Please refer to the Integrated Development Environment chapter.

    Component overview

    TIDEScripter

    component tidescripter

    This component is the non-visual component for running/debugging scripts. Check the topic "The TIDEScripter component" for more information.

    TIDEEngine

    component tideengine

    This is the core engine component for the IDE. Check the topic "The TIDEEngine component" for more information.

    TIDEDialog

    component tidedialog

    This is the wrapper for the IDE window. Use this component to show the IDE. Check the topic "Running the IDE: TIDEDialog component" for more information.

    Custom IDE components

    components ide custom

    • TIDEPaletteToolbar
    • TIDEInspector
    • TIDEMemo
    • TIDEFormDesignControl
    • TIDEComponentComboBox
    • TIDEPaletteButtons
    • TIDEWatchListView

    The components above are used to build your own custom IDE. Check the section "Building your own IDE" for more information.

    The TIDEScripter component

    The TIDEScripter component is a non-visual component used to execute scripts. It descends from TatCustomScripter and is fully compatible with other scripter components like TatPascalScripter and TatBasicScripter.

    The chapters "Language Features" and "Working with scripter" describes how to use the scripter component to execute scripts, access Delphi objects, integrate the scripter with your application, and also know the valid syntax and languages available.

    Running the IDE: TIDEDialog component

    The TIDEDialog component provides quick access to the ready-to-use IDE. It is a wrapper for a IDE form which already contains the memo, object inspector, among others. To invoke the IDE:

    1. Drop a TIDEScripter component in the form.

    2. Drop a TIDEEngine component in the form.

    3. Drop a TIDEDialog component in the form.

    4. Link the TIDEScripter component to the TIDEEngine component through the TIDEEngine.Scripter property.

    5. Link the TIDEEngine component to the TIDEDialog component through the TIDEDialog.Engine property.

    6. Call TIDEDialog.Execute method:

    IDEDialog1.Execute;
    

    This will open the IDE window.

    Overview of the IDE

    This is a screenshot of the TMS Scripter IDE:

    ide overview

    It's very similar to a Delphi or Visual Studio IDE. The object inspector is at the left, the syntax code editor memo is in center, menus and toolbars at the top, and the tool palette is at right. Please not that the tool palette is only available from Delphi 2005 and up. For previous versions of Delphi, a toolbar is available with Delphi 7 style (at the top of the IDE).

    Shortcuts are available for most used actions, you can see the shortcuts available in the main menu of the IDE.

    Managing projects and files

    Project concept and structure
    A project in TMS Scripter is a collection of scripts (files), and each file can be a unit (a single script file) or a form (a script file and a form file). A project file is just a list of the script files belonging to that project and the information of which script is the main script.

    Mixing languages
    You can mix scripts with different languages, i.e., in a project you can have a Basic script which creates and executes a Pascal form.

    Main script
    Each project has a "main" script. The main script is the script which will be executed when you press F9 or click the "Run" button (or menu option).

    Creating a new project
    To create a new project, choose "File | New Project" menu option. This dialog will be displayed:

    ide select language

    Keep in mind that here you are choosing the language for the units that will be created automatically by the IDE. It's not the language of the "project" itself, since such concept doesn't exist. It's the language of the main units.

    After you choose the language of the main units, the IDE will create a main unit and a form unit. This is the basic project and if you execute it right away you will have a running blank form in your screen.

    Note

    Before running this simple example, you must add the following units to your Delphi/C++Builder uses/include clause: ap_Classes, ap_Controls, ap_Forms, ap_Dialogs, ap_Graphics and ap_StdCtrls.

    Creating/adding units/forms to the project
    You can create or add existing units/forms to the project by choosing the "File | New unit", "File | New Form" and "File | Open (add to project)" menu options. If you are creating a new one, you will be prompted with the same dialog as above, to choose the language of the new unit. If you're adding an existing unit, then the IDE will detect the script language based on the file extension.

    Editing the script in code editor

    The IDE provides you with a code editor with full syntax highlight for the script language.

    The main features of code editor are:

    • code completion (pressing Ctrl+Space);
    • syntax highlight;
    • line numbering;
    • clipboard operations;
    • automatic identation;
    • among other features.

    ide code editor

    Designing forms

    When you're dealing with units that are forms, then you have two parts: the script and the form. You can switch between script and form using F12 key or by pressing the "Code" and "Design" tabs at the bottom of the screen.

    The form editor looks like the picture below:

    ide form editor

    Designing forms is a similar task as designing forms in Delphi or Visual Studio. You can use the tool palette the choose a component to drop on the form, position the component using the mouse or keyboard (resize, move, etc.) and change the properties using the object inspector.

    The main features of the form designer are:

    • Multi-selection;
    • Clipboard operations;
    • Alignment palette (menu "Edit | Align");
    • Bring to front / Send to back;
    • Tab order dialog;
    • Size dialog;
    • Locking/unlocking controls;
    • Grid and Snap to Grid;
    • among other features.

    You can change some properties of the form designer by opening the Designer Options dialog. This is available under the menu "Tools | Designer options":

    ide designer options

    You can customize the look and feel of the designer choosing colors, hints and grid options.

    Running and debugging scripts

    You can run and debug scripts from the TMS Scripter IDE. The main features of the debugger are:

    • Breakpoints;
    • Watches;
    • Step over/Trace into;
    • Run to cursor/Run until return;
    • Pause/Reset;
    • and more...

    The image below shows the options under the menu item "Run":

    ide run menu

    You can use the shortcuts above or use the menu/toolbar buttons to perform running/debugging actions, like run, pause, step over, trace into, etc..

    You can also toggle a breakpoint on/off by clicking on the left gutter in the code editor.

    The image below shows a script being debugged in the IDE. A watch has been added in this example to inspect the value of variable "FinalMsg".

    ide debug watch

    Library Browser

    The IDE provides the library browser dialog accessible from menu View > Library Browser.

    It allows your end-user too see all the classes, functions, methods, constants, procedures, etc., that are registered in the scripting system and available to be used. It works as kind of full reference/documentation for the IDE.

    ide library browser

    Code Insight features

    TMS Scripter comes with code insight features, meaning that in the IDE editor you can have fully automatic code completion and parameter hints.

    Code Completion

    Code completion is a feature activated by Ctrl+<Space> or when you type an identifier name followed by a "." (dot).

    A list appears at the cursor position, displaying all the available options (methods, properties, functions, variables) for the given context.

    ide code completion

    Smart code completion
    When a code completion list appears, it will automatically preselect the item which was previously chosen by you. The item selected is specific to the context.

    For example, you might be dealing with a TDataset and retrieving several field values from it, using FieldByName method. You follow this steps to use code completion for the first line:

    1. Invoke code completion by typing Ctrl+<Space>.

    2. Start type the naming of your TDataset object, for example, type "Dat" and then you get the "Dataset1" item selected in the completion list.

    3. Press "." to insert "Dataset1." text in the editor.

    4. A new code completion list will appear listing the methods and properties of the dataset.

    5. You start typing "FieldB" to select the item "FieldByName" from the completion list.

    6. Press "(" to insert "FieldByName(", type the name of field, type ")." to close the parameters and invoke the list again.

    7. Type "AsStr" to find AsString property and then press ";" to finally complete the line.

    Now, you want to start a second line with the same code for another field. Smart code completion will remember your last options, and this is what you would need to type:

    1. Invoke code completion by typing Ctrl+<Space>.

    2. "Dataset1" will come preselected in the list. Just press "." to insert text and invoke a new list for Dataset1 members.

    3. "FieldByName" will come preselected in the list. Just press "(" to insert text and type the field name.

    4. When close FieldByName parameters and press "." again, "AsString" will also come preselected, and you can just type ";" to finish typing.

    Easy navigation
    When you have the desired item selected in code completion list, you can click Enter to make the selection be typed in the text editor, so you don't have to type it.

    You can type other keyboard keys in order to complete the text and also insert the character. For example, if you press "." (dot), the selected item will be inserted in the text, followed by a dot, and a new completion list will be displayed for the selected context.

    Parameter Hints

    Parameter hints is a feature activated by Ctrl+Shift+<Space>, or when you type a method/function name followed by "(".

    This will display the list of parameters for the specified method, so you can properly type the parameters.

    The current parameter being typed is highlighted in the hint.

    ide parameter hint

    Enabling parameter hints
    Parameter hints feature is enabled by default, but you have to provide info to it. For each method, you must provide the names and types of parameters so scripter can show them. This is done with UpdateParameterHints method of TatMethod object. You would usually do this when you register a new method in scripter.

    You can use DefineMethod method and pass it as the last parameter:

    DefineClass(TSomeClass).DefineMethod(
      'MyMethod', 2, TkInteger, nil, MyMethodProc, true, 0, 
      'Name:string;Value:integer');
    

    or you can just call UpdateParameterHints:

    with DefineMethod('MyMethod', 2, TkInteger, nil, MyMethodProc) do
      UpdateParameterHints('Name:string;Value:integer');
    

    Parameter hint syntax
    The parameter hint has a very simple and specific syntax, which is:

    ParamName[:ParamType][=DefaultValue]
    

    Parts between brackets are optional. If there are more than one parameter, you must separate then with semicommas (;). Some examples:

    'Param1:String;Param2:Integer'
    'Param1; Param2; Param3 = 0'
    'Param1; Param2: TButton; Param3: boolean = false'
    

    You can have spaces between the characters, and you must not include any parameter modifier (var, const, etc.), this will be used automatically by the scripter.

    Also be aware that the parameter hints do NOT affect any information in the registered method itself. For example, if you build the hint with a different number of parameters than the specified for the method, the remaining parameters will be ignored. This is also valid for default values and param types, they are only used for hinting purposes.

    Cross-language parameter hints
    Scripter will automatically translate the parameter hints to the proper script language, so you don't need to register a parameter hint for each language syntax. The hint will be displayed according to the current script syntax. Even if you use script-based libraries, written in Pascal language, for example, when you call those methods from a Basic script, parameter hints will be displayed in Basic syntax.

    ide parameter hint basic

    Import tool
    The scripter import tool properly generates the DefineMethod call including the correct parameter hint for the method being registered.

    Enchanced RTTI
    If you use Delphi 2010 and up, and register your classes using the new enchanced RTTI, parameter hint are retrieved automatically with the RTTI and are available in the editor with no need for extra code.

    Building your own IDE

    TMS Scripter provides you several components to make it easy to build your own IDE. All elements in the IDE like the code editor, object inspector, tool palette, etc., are available for stand-alone or integrated use.

    And more, you don't need to use all components, you can use only three, two, or even one single component!

    The "magic" here is that all components are grouped together under a TIDEEngine. If you want one component to work in sync with another one, just use a TIDEEngine component to group them. The following sections will provide more information about the available components and the engine.

    IDE Components available

    The "pieces" of the IDE available as componentes are:

    TIDEMemo

    component tidememo

    Stand-alone syntax-highlighting memo for editing script source code. It is inherited from TAdvMemo component.

    TIDEFormDesignControl

    component tideformdesigncontrol

    Stand-alone form designer control to allow designing forms and its child controls.

    TIDEPaletteToolbar and TIDEPaletteButtons

    component tidepalettetoolbar component tidepalettebuttons

    Component palette controls. The TIDEPaletteToolbar is a Delphi7-like component toolbar, while TIDEPaletteButtons is a tool palette which looks like the Delphi 2005-2007 component palette. The TIDEPaletteButtons component is not available for Delphi 7 and previous versions.

    TIDEInspector

    component tideinspector

    Stand-alone object inspector for viewing/changing properties of components.

    TIDEComponentComboBox

    component tidecomponentcombobox

    A combo box which lists all the components available in the form, and selects the control when the user chooses an item from the combo box. To be used in conjunction with TIDEFormDesignControl.

    TIDEWatchListView

    component tidewatchlistview

    A stand-alone list view which shows the watches defined in the IDE, for debugging purposes.

    The TIDEEngine component

    The TIDEEngine component is the code behind the IDE. In other words, it has all the code which makes the IDE work and integrates all IDE components together. All IDE components provide feedback to the engine in order to synchronize other components. For example, when a component is selected in the form designer, the form designer notifies the TIDEEngine so that the engine can notify the inspector to update itself and show the properties of the selected component.

    All IDE components have an Engine property which points to a TIDEEngine component. And the TIDEEngine component also have properties which points to the component pieces that builds an IDE. The Engine property in the components are public, and the properties in the TIDEEngine are published, so at design-time you use the TIDEEngine component properties to link everything together. The key properties of the TIDEEngine component are:

    Scripter
    Points to an TIDEScripter component. The scripter is used to hold the scripts belonging to a project, to retrieve the name of the available event handlers, to refactor, among other functions.

    ComponentCombo
    Points to a TIDEComponentComboBox component. This component is optional, but if you associated it to the engine, then the engine will update the combo automatically and no extra code is needed to make it work.

    DesignControl
    Points to a TIDEFormDesignControl component. This component is used to design the form components. The engine synchronizes this component with the inspector, the component combo and the component palette toolbar (or buttons).

    Inspector
    Points to a TIDEInspector component. This component is used to inspect the properties and events of the component(s) selected in the designer. The engine synchronizes the inspector and the designer accordingly.

    Memo
    Points to a TIDEMemo component. The engine automatically updates the memo source code with the currently selected unit in the project, and also automatically provides code completion and other features.

    PaletteToolbar or PaletteButtons
    Points to a TIDEPaletteToolbar or TIDEPaletteButtons (from Delphi 2005 or above) component. They display at runtime all the components that are available to be dropped in the form designer. Several components are already available, and you can register more components in the IDE if you want to. The engine synchronizes the component palette and the designer, so that a component selected in the toolbar can be dropped in the designer.

    TabControl
    Points to a regular TTabControl component. This component is used to display the available units in the project, and also to select the desired unit when the end-user clicks a tab.

    WatchList
    Points to a TIDEWatchListView component. This component shows all active watches in the debugging environment, and the engine automatically updates the watches while debugging.

    Basic steps to build a custom IDE

    The following steps are a quick start guide to build a custom IDE. With these basic steps you can get a custom IDE running with minimum functionality.

    1. Drop a TIDEEngine component in the form.

    2. Drop a TIDEScripter component in the form.

    3. Drop a TTabControl component in the form.

    4. Drop a TIDEMemo component in the TTabControl. You can set Align property to alClient to make it look better.

    5. Drop a TIDEFormDesignControl component in the TTabControl. You can set Align property to alClient to make it look better.

    6. Drop a TIDEInspector component in the form.

    7. Drop a TIDEPaletteToolbar (or TIDEPaletteButtons) component in the form.

    8. Select the TIDEEngine component and set the following properties, pointing to the respective components:

      • Scripter (link to the TIDEScripter component);
      • DesignControl (link to the TIDEFormDesignControl component);
      • Inspector (link to TIDEInspector component);
      • Memo (link to the TIDEMemo component);
      • PaletteToolbar (or PaletteButtons, linking to the TIDEPaletteToolbar or TIDEPaletteButtons component); and
      • TabControl (link to the TTabControl component).

    That's it, you have the IDE running already. Of course, you need to add several actions to create unit, create form, save, load, etc., and you do that by using the TIDEDialog component programatically.

    So, as an example, you can perform these extra 9 and 10 steps here to have a project running:

    9. Drop a TButton in the form, change the Caption property to "Start" and in the OnClick event add the following code:

    IDEEngine1.CreateMainUnits(slPascal);
    

    10. Drop a TButton in the form, change the Caption property to "Run" and in the OnClick event add the following code:

    IDEEngine.RunProject;
    

    Using ready-to-use inspector and palette forms

    As an alternative to using TIDEInspector and TIDEPaletteButtons component, you can use some already built forms which contain those components. The advantage of using the forms is that they add some extra functionality (for example, the inspector form has the tabset which displays the tabs "properties" and "events", while the palette buttons form adds filtering functionality).

    TfmObjectInspector form
    The form with the inspector is available in the fObjectInspector.pas unit. Just create an instance of the TfmObjectInspector form and set its Engine property to a valid TIDEEngine component.

    TfmToolPalette form
    The form with the palette buttons is available in the fToolPalette.pas unit. Just create an instance of the TfmToolPalette form and set its Engine property to a valid TIDEEngine component.

    Using ready-to-use actions

    TMS Scripter also provides a TDataModule which contains several actions that can be used in your custom IDE.

    Just add the dIDEActions.pas unit to your project. Link your IDE form to this unit by adding it to the uses clause, create an instance of the TdmIDEActions data module and use the actions as you want. These actions are used by the default IDE provided by the TIDEDialog component, so you don't need to add extra code to perform basic operations like new project, open project, save file, create unit, copy to clipboard, etc..

    Using TIDEEngine component programatically

    The TIDEEngine component is the core component of an IDE in TMS Scripter. It provides several methods and properties to work with the IDE programatically. This topic shows some basic operations you can do with the component in either situation, and in all examples the name of the TIDEEngine component will be IDEEngine1.

    Creating a new project

    Use NewProject method. This will clear all existing files in the project and creating a new blank project:

    IDEEngine1.NewProject;
    

    Optionally, you can ask the engine to create the main units for a very basic project. This would be a blank form, and a separated unit (which will be the main unit) that creates an instance of the form and show it. To do that, call this method (you must pass the language used to create the units):

    IDEEngine1.CreateMainUnits(slPascal);
    

    Adding/removing units (scripts and forms) to the project

    You can add new blank units and forms to the project using these methods:

    var
      ANewUnit: TIDEProjectFile;
      ANewForm: TIDEProjectFile;
    begin
      {Creates a blank unit in Basic}
      ANewUnit := IDEEngine1.NewUnit(slBasic);
    
      {Creates a blank form in Pascal}
      ANewForm := IDEEngine1.NewFormUnit(slPascal);
    end;
    

    To remove a unit from the project, just destroy the TIDEProjectFile object inside the collection:

    //Remove Unit1 from project
    var
      AUnit: TIDEProjectFile;
    begin
      AUnit := IDEEngine1.Files.FindByUnitName('Unit1');
      if AUnit <> nil then
        AUnit.Free;
    end;
    

    C++Builder example

    Executing a project programatically

    The example below creates a new project, add a unit with a script source code, and execute it.

    procedure TForm1.RunSampleProject;
    var
      AUnit: TIDEProjectFile;
      AEngine: TIDEEngine;
      AScripter: TIDEScripter;
    begin
      AEngine := TIDEEngine.Create(nil);
      AScripter := TIDEScripter.Create(nil);
      AEngine.Scripter := AScripter;
      AEngine.NewProject;
      AUnit := AEngine.NewUnit(slPascal);
      AUnit.Script.SourceCode.Text := 'ShowMessage(''Hello world!'');';
      AEngine.RunProject;
      AEngine.Free;
      AScripter.Free;
    end;
    

    This example does the same, but instead of executing the code, it opens the IDE with the current unit:

    procedure TForm1.ShowIDEWithSimpleUnit;
    var
      AUnit: TIDEProjectFile;
      ADialog: TIDEDialog;
      AEngine: TIDEEngine;
      AScripter: TIDEScripter;
    begin
      ADialog := TIDEDialog.Create(nil);
      AEngine := TIDEEngine.Create(nil);
      AScripter := TIDEScripter.Create(nil);
      ADialog.Engine := AEngine;
      AEngine.Scripter := AScripter;
      AEngine.NewProject;
      AUnit := AEngine.NewUnit(slPascal);
      AUnit.Script.SourceCode.Text := 'ShowMessage(''Hello world!'');';
      ADialog.Execute;
      ADialog.Free;
      AEngine.Free;
      AScripter.Free;
    end;
    

    C++Builder example

    Managing units and changing its properties

    All units in a project are kept in a collection named Files (IDEEngine1.Files). Each unit (file) is a TIDEProjectFile object. So, for example, to iterate through all units in a project:

    var 
      AUnit: TIDEProjectFile;
    begin
      for c := 0 to IDEEngine1.Files.Count - 1 do
      begin
        AUnit := IDEEngine1.Files[c];
        //Do something with AUnit
      end;
    end;
    

    C++Builder example

    The TIDEProjectFile class has several properties and we list here the main ones (see full component reference for all properties):

    Script
    Points to the TatScript object inside the scripter component. When a unit is created, it also creates a TatScript object in the Scripter component. They are in sync (the file and the script). Use this to change source code, for example:

    AUnit.Script.SourceCode.Text := 'ShowMessage(''Hello world!'')';
    

    IsForm
    Use this function to check if the unit has a form associated with it:

    HasForm := AUnit.IsForm;
    

    Setting the active unit in the IDE

    Use ActiveFile property to specify which file is the one selected in the IDE:

    AMyUnit := IDEEngine1.Files.FindByUnitName('Unit1');
    IDEEngine1.ActiveFile := AMyUnit;
    

    C++Builder example

    Running and debugging a project

    To run a project, use RunProject method:

    IDEEngine1.RunProject;
    

    the main unit will be executed. The main unit is the unit specified by IDEEngine1.MainUnit property. There are several methods for debugging the script, and all of them start with "Debug" in method name.

    C++Builder example

    Here is a list with the main methods:

    {Pauses the script execution, for IDE debugging purposes}
    procedure DebugPause;
    
    {Perform debug step over action in the current active script}
    procedure DebugStepOver(RunMode: TIDERunMode = rmMainUnit);
    
    {Perform debug step into action in the current active script}
    procedure DebugTraceInto(RunMode: TIDERunMode = rmMainUnit);
    
    {Perform debug action "run to line": run the active script until the selected line in memo}
    procedure DebugRunToLine(RunMode: TIDERunMode = rmMainUnit);
    
    {Perform debug action "run until return": run the active script until the routine exists}
    procedure DebugUntilReturn;
    
    {Halts script execution}
    procedure DebugReset;
    
    {Toggle breakpoint on/off in the memo and script.
     If ALine is -1 then current line in memo will be toggled for breakpoint}
    procedure DebugToggleBreak(ALine: integer = -1);
    

    Methods for end-user interaction - open, save dialogs, etc.

    The TIDEEngine component provides several high-level methods for user interaction. All of those methods begin with "Dlg" in the method name, and are used to open/save project and units, closing units, etc.. The difference from the regular methods for saving/loading (or removing units) is that they perform more higher level operations, like displaying the open/save dialogs, checking if the file was saved or not, asking for saving if the file was modified, checking if the unit name exist, etc.. These are the main methods:

    {Creates a new project. Returns true if the new project is created sucessfully.}
    function DlgNewProject: boolean;
    
    {DlgProjectFile opens a dialog for choosing a project file and then open the project
     file, clearing all units and loading the units belonging to that project.
     It returns true if the project is opened successfully.}
    function DlgOpenProject: boolean;
    
    {Call DlgOpenFile to open an existing file in the IDE interface.
     It will open a dialog for choosing the file, and if confirmed, the new file will be 
     added to the project and opened in the IDE.
     This method returns the newly created TIDEProjectFile which contains the opened file.}
    function DlgOpenFile: TIDEProjectFile;
    
    {Call DlgSaveFile method to save the file specified by AFile. It automatically
     opens the "Save as..." dialog if the file was not yet saved for the first time.
     This method returns true if the file was saved succesfully.}
    function DlgSaveFile(AFile: TIDEProjectFile): boolean;
    
    {Same for DlgSaveFile method, except it automatically saves the 
     currently active file in the project.
     This method returns true if the file was saved succesfully.}
    function DlgSaveActiveFile: boolean;
    
    {Open the "Save as..." dialog for saving an unit.
     It performs extra operations like checking if the unit name already exists,
     and update the script source code (directive "$FORM") with the correct file name,
     in case the file name was changed.
     This method returns true if the file was saved succesfully.}
    function DlgSaveFileAs(AFile: TIDEProjectFile): boolean;
    
    {Same as DlgSaveFileAs, except that it automatically saves the currently active file.
     This method returns true if the file was saved succesfully.}
    function DlgSaveActiveFileAs: boolean;
    
    {Save all files in the project at once.
     For each file, if the file is not saved, it opens a "Save as..." dialog.
     If the dialog is canceled at some point, the remaining files will not be saved.
     This function returns true if  all files were saved sucessfully.}
    function DlgSaveAll: boolean;
    
    {Closes the file specified by AFile. If the file was already saved, 
     then it is not removed from project, just made invisible in the IDE.
     If the file is a new file that was not saved yet, then it's removed.
     If the file was modified, the engine asks the user if the file  must be saved or not.
     The result of the closing operation is returned in the TIDECloseFileResult.}
    function DlgCloseFile(AFile: TIDEProjectFile): TIDECloseFileResult;
    
    {Same as DlgCloseFile, except that it automatically closes the currently active file.}
    function DlgCloseActiveFile: TIDECloseFileResult;
    
    {Close all files in the project. It calls DlgCloseFile for each file in the project.
     It returns true if all files were closed succesfully.}
    function DlgCloseAll: boolean;
    
    {Same as DlgRemoveFile, except it removes the currently active file.}
    function DlgRemoveActiveFile: boolean;
    
    {Remove the file specified by AFile from the project.
     If the file was not saved, it asks for saving it.
     The method returns true if the file was successfully removed.}
    function DlgRemoveFile(AFile: TIDEProjectFile): boolean;
    
    {Opens a save dialog to save the project. Returns true if the project was saved sucessfully.}
    function DlgSaveProjectAs: boolean;
    
    {Save the current project. If the project was not saved yet, it calls
     DlgSaveProjectAs to choose the file name for the project.}
    function DlgSaveProject: boolean;
    
    {Calls the Add Watch dialog to add a new watch while debugging.
     Returns nil if no watch is added, otherwise returns the newly created TatDebugWatch object.
     There is no need to destroy this object later, the engine takes care of it automatically.}
    function DlgAddWatch: TatDebugWatch;
    

    Registering components in the IDE

    This topic covers some tasks that you can do to register (or unregister) components in the IDE system.

    Retrieving existing registered components

    All the components already registered in the IDE system are available in the TIDEEngine.RegisteredComps property. It is a collection of TIDERegisteredComp objects which holds information for each registered component. As an example, the code below retrieves information about all registered components:

    var
      ARegComp: TIDERegisteredComp;
      c: integer;
      ACompClass: TComponentClass;
      AUnits: string;
      APage: string;
    begin
      for c := 0 to IDEEngine1.RegisteredComps.Count - 1 do
      begin
        ARegComp := IDEEngine1.RegisteredComps[c];
    
        {Contains the class registered, for example, TButton}
        ACompClass := ARegComp.CompClass; 
    
        {Contains the name of units (separated by commas) that will be
         added to the script when the component is dropped in a form.
         For example, 'ComCtrls,ExtCtrls'}
        AUnits := ARegComp.Units;
    
        {Contains the name of the page (category, tab) where the 
         component will be displayed. For example, 'Standard'}
        APage := ARegComp.Page;
      end;
    end;
    

    C++Builder example

    Registering/Unregistering standard tabs

    The TIDEEngine component provides some methods which register/unregister automatically some components that are commonly used. The methods available are:

    {Register the following components in the tab "Standard":
     TMainMenu, TPopupMenu, TLabel, TEdit, TMemo, TButton, TCheckBox, 
     TRadioButton, TListBox, TComboBox, TGroupBox, TPanel, TRadioGroup}
    procedure RegisterStandardTab;
    
    {Register the following components in the tab "Additional": 
     TBitBtn, TSpeedButton, TMaskEdit, TImage, TShape, TBevel, TStaticText, TSplitter}
    procedure RegisterAdditionalTab;
    
    {Register the following components in the tab "Dialogs":
     TOpenDialog, TSaveDialog, TFontDialog, TColorDialog, TPrintDialog, TPrinterSetupDialog}
    procedure RegisterDialogsTab;
    
    {Register the following components in the tab "Win32":
     TTabControl, TPageControl, TProgressBar, TTreeView, TListView, TDateTimePicker}
    procedure RegisterWin32Tab;
    

    To unregister a tab from the palette, just call UnregisterTab method. Example:

    IDEEngine1.UnregisterTab('Win32');
    

    C++Builder example

    Register new components

    To register a new component in the component palette, just call RegisterComponent method. For example:

    {Register the new component TMyComponent in the tab "Custom".
     When the user drops this component in the form, the units ComCtrls, 
     ExtCtrls and MyComponentUnit are added to the script.
     These units must be registered in scripter in order to give access to
     them in the script environment. This registration can be done manually 
     (check "Accessing Delphi objects" chapter) or using the ImportTool.}
    IDEEngine1.RegisterComponent('Custom', TMyComponent, 'ComCtrls,ExtCtrls,MyComponentUnit');
    

    C++Builder example

    To set the image used to display the component in the palette, use the TIDEEngine.OnGetComponentImage event.

    Storing units in a database (alternative to files)

    By default the IDE in TMS Scripter saves projects and units to regular files. It displays open/save dialogs and then open/save the files. But you can also change this behaviour and make the IDE save/load the files in the place you want. The most common use for it is databases. You can also replace the open/save dialogs to display your own dialogs for the end-user to choose the available files to open, or choose the file name to be saved.

    To do that, you must add code to some special events of TIDEDialog component. This topic covers those events and how to use them.

    Replacing save/load operations

    You must add event handler code to two events: OnLoadFile and OnSaveFile.

    Declaration:

    type
      TIDELoadFileEvent = procedure(Sender: TObject; IDEFileType: TIDEFileType; AFileName: string;
        var AContent: string; AFile: TIDEProjectFile; var Handled: boolean) of object;
      TIDESaveFileEvent = procedure(Sender: TObject; IDEFileType: TIDEFileType; AFileName: string;
        AContent: string; AFile: TIDEProjectFile; var Handled: boolean) of object;
    
    property OnLoadFile: TIDELoadFileEvent read FOnLoadFile write FOnLoadFile;
    property OnSaveFile: TIDESaveFileEvent read FOnSaveFile write FOnSaveFile;
    

    Example:

    procedure TForm1.IDEEngine1SaveFile(Sender: TObject;
      IDEFileType: TIDEFileType; AFileName, AContent: String;
      AFile: TIDEProjectFile; var Handled: Boolean);
    begin
      {The IDEFileType parameter tells you if the file to be saved is a project file,
       a script file, or a form file.
       Valid values are: iftScript, iftProject, iftForm}
    
      {The AFileName string contains the name of the file that was chosed in the save dialog.
       Remember that you can replace the save dialog by your own, so the AFileName will 
       depend on the value returned by the save dialog}
    
      {The AContent parameter contains the file content in string format}
    
      {The AFile parameter points to the TIDEProjectFile object that is being saved.
       You will probably not need to use this parameter, it's passed only in case 
       you need additional information for the file}
    
      {If you save the file yourself, you need to set Handled parameter to true.
       If Handled is false, then the IDE engine will try to save the file normally}
    
      {So, as an example, the code below saves the file in a table which contains the
       fields FileName and Content. Remember that AContent string might be a big string, 
       since it has all the content of the file (specially for form files)}
    
      MyTable.Close;
      case IDEFileType of
        iftScript: MyTable.TableName := 'CustomScripts';
        iftForm: MyTable.TableName := 'CustomForms';
        iftProject: MyTable.TableName := 'CustomProjects';
      end;
      MyTable.Open;
      if MyTable.Locate('FileName', AFileName, [loCaseInsensitive]) then
        MyTable.Edit
      else
      begin
        MyTable.Append;
        MyTable.FieldByName('FileName').AsString := AFileName;
      end;
      MyTable.FieldByName('Content').AsString := AContent;
      MyTable.Post;
      Handled := true;
    end;
    

    Sample code for loading the file:

    procedure TForm1.IDEEngine1LoadFile(Sender: TObject;
      IDEFileType: TIDEFileType; AFileName: String; var AContent: String;
      AFile: TIDEProjectFile; var Handled: Boolean);
    begin
      {The IDEFileType parameter tells you if the file to be loaded is a project file,
       a script file, or a form file.
       Valid values are: iftScript, iftProject, iftForm}
    
      {The AFileName string contains the name of the file that was chosed in the open dialog.
       Remember that you can replace the open dialog by your own, so the AFileName will
       depend on the value returned by the open dialog}
    
      {The AContent parameter contains the file content in string format.
       You must return the content in this parameter}
    
      {The AFile parameter points to the TIDEProjectFile object that is being loaded.
       You will probably not need to use this parameter, it's passed only in case 
       you need additional information for the file}
    
      {If you load the file yourself, you need to set Handled parameter to true.
       If Handled is false, then the IDE engine will try to load the file normally}
    
      {So, as an example, the code below loads the file from a table which contains the
       fields FileName and Content. Remember that AContent string might be a big string,
       since it has all the content of the file (specially for form files)}
    
      MyTable.Close;
      case IDEFileType of
        iftScript: MyTable.TableName := 'CustomScripts';
        iftForm: MyTable.TableName := 'CustomForms';
        iftProject: MyTable.TableName := 'CustomProjects';
      end;
      MyTable.Open;
      if MyTable.Locate('FileName', AFileName, [loCaseInsensitive]) then
        AContent := MyTable.FieldByName('Content').AsString
      else
        raise Exception.Create(Format('File %s not found!', [AFileName]));
      Handled := true;
    end;
    

    C++Builder example

    Replacing open/save dialogs

    You must add event handler code to two events: OnOpenDialog and OnSaveDialog. The parameters are similar to the OnLoadFile and OnSaveFile. You must build your own windows to replace the default ones. Remember that in FileName parameter you can also return a path structure like '\MyFiles\MyFileName.psc'. Then you must handle this structure yourself in the OnLoadFile and OnSaveFile events.

    Declaration:

    type
      TIDEOpenDialogEvent = procedure(Sender: TObject; IDEFileType: TIDEFileType;
        var AFileName: string; var ResultOk, Handled: boolean) of object;
      TIDESaveDialogEvent = procedure(Sender: TObject; IDEFileType: TIDEFileType;
        var AFileName: string; AFile: TIDEProjectFile; var ResultOk, Handled: boolean) of object;
    
    property OnSaveDialog: TIDESaveDialogEvent read FOnSaveDialog write FOnSaveDialog;
    property OnOpenDialog: TIDEOpenDialogEvent read FOnOpenDialog write FOnOpenDialog;
    

    Example:

    procedure TForm1.IDEEngine1SaveDialog(Sender: TObject;
      IDEFileType: TIDEFileType; var AFileName: String; AFile: TIDEProjectFile;
      var ResultOk, Handled: Boolean);
    begin
      {The IDEFileType parameter tells you if the file to be saved is a project file,
       a script file, or a form file.
       Valid values are: iftScript, iftProject. itForm is not used for open/save dialogs}
    
      {The AFileName string contains the name of the file that was chosed in the save dialog.
       You must return the name of the file to be saved here}
    
      {The AFile parameter points to the TIDEProjectFile object that is being saved.
       You will probably not need to use this parameter, it's passed only in case 
       you need additional information for the file}
    
      {You must set ResultOk to true if the end-user effectively has chosen a file name.
       If the end-user canceled the operation, set ResultOk to false
       so that save process is canceled}
    
      {If you display the save dialog yourself, you need to set Handled parameter to true.
       If Handled is false, then the IDE engine will open the default save dialog}
    
      {So, as an example, the code below shows a very rudimentar save dialog (InputQuery) in
       replacement to the regular save dialog. Note that this example doesn't check if the 
       file is a project or a script. You must consider this parameter in your application}
    
      AResultOk := InputQuery('Save unit', 'Choose a file name', AFileName);
      Handled := true; 
    end;
    

    Sample code for replacing open dialog:

    procedure TForm1.IDEEngine1OpenDialog(Sender: TObject;
      IDEFileType: TIDEFileType; var AFileName: String; var ResultOk,
      Handled: Boolean);
    var
      AMyOpenDlg: TMyOpenDlgForm;
    begin
      {The IDEFileType parameter tells you if the file to be loaded is a project file,
       a script file, or a form file.
       Valid values are: iftScript and iftProject. itForm is not used for open/save dialogs}
    
      {The AFileName string contains the name of the file that was chosed in the open dialog.
       You must return the name of the file to be loaded here}
    
      {You must set ResultOk to true if the end-user effectively has chosen a file name.
       If the end-user canceled the operation, set ResultOk to false
       so that open process is canceled}
    
      {If you display the open dialog yourself, you need to set Handled parameter to true.
       If Handled is false, then the IDE engine will open the default open dialog}
    
      {So, as an example, the code below shows an open dialog in replacement to the regular
       open dialog. It considers that the form TMyOpenDlgForm lists all available units from 
       a database table or something similar. Note that this example doesn't check if the file 
       is a project or a script. You must consider this parameter in your application}
    
      AMyOpenDlg := TMyOpenDlgForm.Create(Application);
      AResultOk := (AMyOpenDlg.ShowModal = mrOk);
      if AResultOk then
        AFileName := AMyOpenDlg.ChosenFileName;
      AMyOpenDlg.Free;
      Handled := true;
    end;
    

    C++Builder example

    Checking if a file name is valid

    Another event that must have code attached is the OnCheckValidFile event. This event is called just after an open dialog is called, and before the file is opened. It is used to check if the file name provided by the open dialog is a valid file name, before effectively opening the file.

    Important

    This event is also important for the engine to know if there is a form file associated with a script. When using regular files, the engine tests if the file "UnitName.XFM" exists in order to know if the script has a form or not. So, you must return the correct information for the event so everything works fine.

    type
      TCheckValidFileEvent = procedure(Sender: TObject; AFileName: string;
        var AValid: boolean) of object;
    
    property OnCheckValidFile: TCheckValidFileEvent read FOnCheckValidFile write FOnCheckValidFile;
    
    
    procedure TForm1.IDEEngine1CheckValidFile(Sender: TObject; IDEFileType: TIDEFileType;
      AFileName: String; var AValid: Boolean);
    begin
      {The IDEFileType parameter tells you if the file to be checked is a form, script or project. 
       Valid values are: iftScript, iftProject}
    
      {The AFileName is the file name to be tested}
    
      {the AValid parameter must be set to true if the file name is valid.}
    
      {The code below is an example of how to use this event}
      MyTable.Close;
      case IDEFileType of
        iftScript: MyTable.TableName := 'CustomScripts';
        iftForm: MyTable.TableName := 'CustomForms';
        iftProject: MyTable.TableName := 'CustomProjects';
      end;
      MyTable.Open;
      AValid := MyTable.Locate('FileName', AFileName, [loCaseInsensitive]);
    end;
    

    C++Builder example

    In This Article
    Back to top TMS Scripter v7.36
    © 2002 - 2025 tmssoftware.com