-
-
- true
-
-
-
-
- true
-
-
-
-
- true
-
-
-
-
- DelphiAIDeveloper.bpl
- true
-
-
+
+
+
+
+
+
+
+
+
1
@@ -263,16 +323,6 @@
0
-
-
- classes
- 1
-
-
- classes
- 1
-
-
res\xml
@@ -283,12 +333,6 @@
1
-
-
- library\lib\armeabi-v7a
- 1
-
-
library\lib\armeabi
@@ -341,6 +385,16 @@
1
+
+
+ res\drawable-anydpi-v21
+ 1
+
+
+ res\drawable-anydpi-v21
+ 1
+
+
res\values
@@ -361,6 +415,66 @@
1
+
+
+ res\values-v31
+ 1
+
+
+ res\values-v31
+ 1
+
+
+
+
+ res\drawable-anydpi-v26
+ 1
+
+
+ res\drawable-anydpi-v26
+ 1
+
+
+
+
+ res\drawable
+ 1
+
+
+ res\drawable
+ 1
+
+
+
+
+ res\drawable
+ 1
+
+
+ res\drawable
+ 1
+
+
+
+
+ res\drawable
+ 1
+
+
+ res\drawable
+ 1
+
+
+
+
+ res\drawable-anydpi-v33
+ 1
+
+
+ res\drawable-anydpi-v33
+ 1
+
+
res\values
@@ -371,6 +485,16 @@
1
+
+
+ res\values-night-v21
+ 1
+
+
+ res\values-night-v21
+ 1
+
+
res\drawable
@@ -391,6 +515,16 @@
1
+
+
+ res\drawable-xxxhdpi
+ 1
+
+
+ res\drawable-xxxhdpi
+ 1
+
+
res\drawable-ldpi
@@ -531,6 +665,56 @@
1
+
+
+ res\drawable-anydpi-v24
+ 1
+
+
+ res\drawable-anydpi-v24
+ 1
+
+
+
+
+ res\drawable
+ 1
+
+
+ res\drawable
+ 1
+
+
+
+
+ res\drawable-night-anydpi-v21
+ 1
+
+
+ res\drawable-night-anydpi-v21
+ 1
+
+
+
+
+ res\drawable-anydpi-v31
+ 1
+
+
+ res\drawable-anydpi-v31
+ 1
+
+
+
+
+ res\drawable-night-anydpi-v31
+ 1
+
+
+ res\drawable-night-anydpi-v31
+ 1
+
+
1
@@ -551,6 +735,10 @@
1
.framework
+
+ 1
+ .framework
+
0
@@ -564,6 +752,10 @@
1
.dylib
+
+ 1
+ .dylib
+
0
.dll;.bpl
@@ -578,7 +770,7 @@
1
.dylib
-
+
1
.dylib
@@ -590,6 +782,10 @@
1
.dylib
+
+ 1
+ .dylib
+
0
.bpl
@@ -608,7 +804,7 @@
0
-
+
0
@@ -617,394 +813,350 @@
0
+
+ 0
+
0
-
-
- 1
-
-
+
+
1
-
+
1
-
-
+
+
+
+
+
+ Contents\Resources
1
-
+
+ Contents\Resources
1
-
+
+ Contents\Resources
1
-
-
- 1
-
-
+
+
+ library\lib\armeabi-v7a
1
-
+
+ library\lib\arm64-v8a
1
-
-
1
1
-
+
1
-
-
-
- 1
-
-
+
1
-
+
1
-
-
-
+
1
-
+
1
-
- 1
+
+ 0
-
-
- 1
-
-
- 1
-
-
+
+
+ library\lib\armeabi-v7a
1
-
-
+
+
1
-
+
1
-
+
1
-
+
+ ..\$(PROJECTNAME).app.dSYM\Contents\Resources\DWARF
1
+ ..\$(PROJECTNAME).app.dSYM\Contents\Resources\DWARF
1
-
+
+ ..\$(PROJECTNAME).app.dSYM\Contents\Resources\DWARF
1
-
+
+
+
+
1
1
-
+
1
-
-
- 1
-
-
+
+
+ Assets
1
-
+
+ Assets
1
-
-
- 1
-
-
+
+
+ Assets
1
-
+
+ Assets
1
-
-
- 1
-
+
+ ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset
1
-
+
+ ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset
1
-
-
- 1
-
+
+ ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset
1
-
+
+ ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset
1
-
-
- 1
-
+
+ ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset
1
-
+
+ ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset
1
-
-
- 1
-
+
+ ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset
1
-
+
+ ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset
1
-
-
- 1
-
+
+ ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset
1
-
+
+ ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset
1
-
-
- 1
-
+
+ ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset
1
-
+
+ ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset
1
-
-
- 1
-
+
+ ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset
1
-
+
+ ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset
1
-
-
- 1
-
+
+ ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset
1
-
+
+ ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset
1
-
-
- 1
-
+
+ ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset
1
-
+
+ ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset
1
-
-
- 1
-
+
+ ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset
1
-
+
+ ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset
1
-
-
- 1
-
+
+ ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset
1
-
+
+ ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset
1
-
-
- 1
-
+
+ ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset
1
-
+
+ ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset
1
-
-
+
+
+ ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset
1
-
+
+ ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset
1
-
-
- ..\$(PROJECTNAME).app.dSYM\Contents\Resources\DWARF
- 1
-
+
- ..\$(PROJECTNAME).app.dSYM\Contents\Resources\DWARF
+ ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset
1
-
-
-
-
-
-
+
+ ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset
1
+
+
+ ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset
1
-
+
+ ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset
1
-
-
-
-
-
- Contents\Resources
+
+
+ ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset
1
-
- Contents\Resources
+
+ ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset
1
-
-
- library\lib\armeabi-v7a
- 1
-
-
- library\lib\arm64-v8a
- 1
-
-
- 1
-
+
+ ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset
1
-
- 1
-
-
+
+ ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset
1
-
- 1
-
-
- 1
-
-
- 0
-
-
-
- library\lib\armeabi-v7a
- 1
-
-
-
-
+
+
+ ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset
1
-
+
+ ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset
1
-
-
- Assets
+
+
+ ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset
1
-
- Assets
+
+ ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset
1
-
-
- Assets
+
+
+ ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset
1
-
- Assets
+
+ ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset
1
-
-
+
+
+
+
+
-
-
-
-
+
+
+
+
False
@@ -1012,6 +1164,7 @@
False
True
False
+ True
12
diff --git a/Package/DelphiAIDeveloper.res b/Package/DelphiAIDeveloper.res
index 9273b09..4a37369 100644
Binary files a/Package/DelphiAIDeveloper.res and b/Package/DelphiAIDeveloper.res differ
diff --git a/Package/Img/c4d_database.bmp b/Package/Img/c4d_database.bmp
new file mode 100644
index 0000000..ba3f71d
Binary files /dev/null and b/Package/Img/c4d_database.bmp differ
diff --git a/Package/Img/c4d_database_add.bmp b/Package/Img/c4d_database_add.bmp
new file mode 100644
index 0000000..59e69bf
Binary files /dev/null and b/Package/Img/c4d_database_add.bmp differ
diff --git a/Package/Img/c4d_database_execute.bmp b/Package/Img/c4d_database_execute.bmp
new file mode 100644
index 0000000..80f0a5f
Binary files /dev/null and b/Package/Img/c4d_database_execute.bmp differ
diff --git a/README.md b/README.md
index c98fb58..9b37e71 100644
--- a/README.md
+++ b/README.md
@@ -1,35 +1,21 @@
# Delphi AI Developer (Copilot)
-Inspired by GitHub Copilot, Delphi AI Developer is a plugin that adds Artificial intelligence (AI) interaction capabilities to the Delphi IDE, using both the OpenAI API, Gemini API and Groq API, as well as offering offline AI support.
+Inspired by GitHub Copilot, Delphi AI Developer is a plugin that adds Artificial intelligence (AI) interaction capabilities to the Delphi IDE, using both the OpenAI API, Gemini API, Mistral API and Groq API, as well as offering offline AI support.
With Delphi AI Developer, you will have assistance in generating and refactoring code, facilitating and accelerating development.
Receive suggestions for creating and improving code directly in the IDE and take advantage of the possibility of creating predefined questions to speed up your searches.
-# 📞 Contacts
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-## ⚙️ Installation
+## 📞 Contacts
+
+[](https://t.me/Code4Delphi)
+[](https://www.youtube.com/@code4delphi)
+[](https://www.instagram.com/code4delphi/)
+[](https://www.linkedin.com/in/cesar-cardoso-dev)
+[](https://code4delphi.com.br/blog/)
+[](https://go.hotmart.com/U81331747Y?dp=1)
+[](mailto:contato@code4delphi.com.br)
+
+## 🚀 INSTALLATION
1 - Download Delphi AI Developer. You can download the .zip file or clone the project on your PC.

@@ -51,25 +37,136 @@ Receive suggestions for creating and improving code directly in the IDE and take
-## ▶️ Demo Video
-We have also created a video with details on how to download, install and use the plugin. The video is in Portuguese (ptBR), but we are providing subtitles and possibly a video in English.
-* [https://www.youtube.com/watch?v=2NAlUFK2FGs](https://www.youtube.com/watch?v=2NAlUFK2FGs)
+## ⚙️ PLUGIN SETTINGS
+Access the menu “AI Developer” > “Settings” > Tab “Preferences”
+
+
+1. **Language used in questions:** Indicate in which language you will ask questions in chats, so that the prompts generated by the Plugin are generated in the same language.
+2. **AI default (Chat and Databases Chat):** Default AI when starting the IDE.
+3. **Color to highlight Delphi/Pascal code:** Color to highlight Delphi/Pascal/SQL code in responses displayed on chat screens
+4. **Default Prompts:** Prompts added in this field will be sent to the AIs along with the requests. This can significantly improve the quality of the responses. (Example prompt: Always return SQL commands in lowercase letters)
+
+
+
+
+## ⚪ CONFIGURING AI ONLINE
+You can choose between 3 APIs, Gemini (Google), ChatGPT (OpenAI) and Groq. Gemini and Groq APIs are free.
+
+Access the menu “AI Developer” > “Settings” > Tab “AI on-line”
+
+
+1. Inform the desired model.
+2. Click on the **"Generate API Key"** link to generate your key.
+3. In this field you must enter the API access key.
+
+
+
+## 🟠 CODE COMPLETION
+
+To configure, access the menu “AI Developer” > “Settings” > Tab “Code Completion”
+
+
+
+1. Enables/disables use of Code Completion
+2. **AI default:** Default AI that will be used by Code Completion
+3. **Suggestion Code Color**: Color code suggested by plugin before being accepted
+4. Shortcut to invoke Code Completion usage (requires restart of Delphi IDE)
+5. **Default Prompts:** Prompts added in this field will be sent to the AIs along with the requests. This can significantly improve the quality of the responses. (Example prompt: Always return SQL commands in lowercase letters)
+
+- To use it, simply use the configured shortcut keys (default Alt+Enter)
+- To **accept** the suggestion, simply use the Tab key.
+
+
+
+
+
+## 🔵 AI CHAT INTERACTING WITH DELPHI IDE
+Access the menu “AI Developer” > “Chat” or Ctrl+Shift+Alt+A
+
+
+1. Select the desired AI to be used in the chat
+2. Field where the question/prompt should be added
+3. Field where the AI response will be displayed
+4. Access the menu with pre-registered questions (to register, access the menu: “AI Developer” > “Defaults Questions”)
+5. By checking this option, the AI will only return codes, without inserting comments or explanations.
+6. By checking the "Use current unit code in query" option, the source code of the current unit will be used as a reference for the prompt sent to the AIs.
+Note: If the current unit has any code selected, only the selected code snippet will be used as a reference, otherwise the entire unit code will be used.
+7. Button that makes the request to the AIs
+8. **Insert Selected Text at Cursor**: Inserts the selected text into the response, field in the IDE code editor (if there is no selection, use the entire response)
+9. Create new unit with selected code (if there is no selection, use the entire response)
+10. Copy Selected Text (if there is no selection, use the entire response)
+11. Clean all and start a new chat
+12. Opens a menu with additional options
-## 📄 Documentation under construction
-**We will soon publish the complete documentation for the Plugin.**
+## 🟣 CHAT FOR DATABASE INTERACTION
+- To register Databases, access the menu “AI Developer” > “Databases Registers”
+
+
+- **Generate reference with database**
+- Note: This process must always be performed whenever a new field or table is added to the database.
+
+
+- Optional Step: Link Default Database to Project or Project Group
+
+
+- Chat for database
+
+
+
+
+1. Select the desired database
+2. Quick access to the reference generation screen for the selected database
+3. Select the desired AI to be used in the chat
+4. Field where the question/prompt should be added
+5. Button that makes the request to the AIs
+6. Field where the AI response will be displayed
+7. Button to execute the SQL command of the field with the response (field 6)
+8. Grid with the response from the execution of the SQl command
+9. Options for copying or exporting Grid data
+10. Access the menu with pre-registered questions (to register, access the menu: “AI Developer” > “Defaults Questions”)
+11. By checking this option, the AI will only return SQL commands, without inserting comments or explanations.
+12. By checking the "Use current unit code in query" option, the source code of the current unit will be used as a reference for the prompt sent to the AIs.
+Note: If the current unit has any code selected, only the selected code snippet will be used as a reference, otherwise the entire unit code will be used.
+13. **Insert Selected Text at Cursor**: Inserts the selected text into the response, field in the IDE code editor (if there is no selection, use the entire response)
+14. Create new unit with selected code (if there is no selection, use the entire response)
+15. Copy Selected Text (if there is no selection, use the entire response)
+16. Clean all and start a new chat
+17. Opens a menu with additional options
+
+
-# 💬 Contributions / Ideas / Bug Fixes
-To submit a pull request, follow these steps:
+## 🟤 AI OFF-LINE
+
+To use AI offline, follow these steps:
+1. Install Ollama, which can be found at the following link: [https://ollama.com/download](https://ollama.com/download)
+2. Choose the desired model. This can be done at the following link: [https://ollama.com/library](https://ollama.com/library)
+
+3. Open command prompt or terminal and run the command “ollama run ” and wait for the installation to finish
+
+4. **To configure**, access the menu “AI Developer” > “Settings” > Tab “AI off-Line“
+
+
+
+
-1. Fork the project
-2. Create a new branch (`git checkout -b minha-nova-funcionalidade`)
-3. Make your changes
-4. Make the commit (`git commit -am 'Functionality or adjustment message'`)
-5. Push the branch (`git push origin Message about functionality or adjustment`)
-6. Open a pull request
+## ▶️ DEMO VIDEO
+For more details about the plugin, watch our talk, voted one of the best of Embarcadero Conference 2024. The video is in Portuguese (pt-BR), but we are providing subtitles and possibly an English version.
+* [https://www.youtube.com/live/7UcfPyqR2TY?si=bLw27HQP4diF7TCB&t=2822](https://www.youtube.com/live/7UcfPyqR2TY?si=bLw27HQP4diF7TCB&t=2822)
+
+
+
+## 💬 CONTRIBUTIONS / IDEAS / BUG FIXES
+Any suggestions or help are welcome. Send us a pull request or open an [issue](/../../issues/).
+
+
+
+## 📄 LGPD Compliance
+[Access information about LGPD](https://github.com/Code4Delphi/Delphi-AI-Developer/blob/master/LGPD.md)
+
+
+## ⚠️ LICENSE
+`Delphi AI Developer` is free and open-source wizard licensed under the [MIT License](LICENSE).
-## ⚠️ License
-`Delphi AI Developer` is free and open-source wizard licensed under the [MIT License](https://github.com/Code4Delphi/Delphi-AI-Developer/blob/master/LICENSE).
diff --git a/Src/AI/DelphiAIDev.AI.ChatGPT.pas b/Src/AI/DelphiAIDev.AI.ChatGPT.pas
index 7d7e4a8..7409225 100644
--- a/Src/AI/DelphiAIDev.AI.ChatGPT.pas
+++ b/Src/AI/DelphiAIDev.AI.ChatGPT.pas
@@ -7,6 +7,7 @@ interface
System.JSON,
System.Classes,
RESTRequest4D,
+ DelphiAIDev.Consts,
DelphiAIDev.Utils,
DelphiAIDev.Settings,
DelphiAIDev.AI.Interfaces;
@@ -15,11 +16,11 @@ interface
TDelphiAIDevAIChatGPT = class(TInterfacedObject, IDelphiAIDevAI)
private
FSettings: TDelphiAIDevSettings;
+ FResponse: IDelphiAIDevAIResponse;
protected
- function GetResponse(const AQuestion: string): string;
+ function GetResponse(const AQuestion: string): IDelphiAIDevAIResponse;
public
- class function New(const ASettings: TDelphiAIDevSettings): IDelphiAIDevAI;
- constructor Create(const ASettings: TDelphiAIDevSettings);
+ constructor Create(const ASettings: TDelphiAIDevSettings; const AResponse: IDelphiAIDevAIResponse);
end;
implementation
@@ -27,19 +28,14 @@ implementation
const
API_JSON_BODY_BASE = '{"model": "%s", "messages": [{"role": "user", "content": "%s"}], "stream": false, "max_tokens": 2048}';
-class function TDelphiAIDevAIChatGPT.New(const ASettings: TDelphiAIDevSettings): IDelphiAIDevAI;
-begin
- Result := Self.Create(ASettings);
-end;
-
-constructor TDelphiAIDevAIChatGPT.Create(const ASettings: TDelphiAIDevSettings);
+constructor TDelphiAIDevAIChatGPT.Create(const ASettings: TDelphiAIDevSettings; const AResponse: IDelphiAIDevAIResponse);
begin
FSettings := ASettings;
+ FResponse := AResponse;
end;
-function TDelphiAIDevAIChatGPT.GetResponse(const AQuestion: string): string;
+function TDelphiAIDevAIChatGPT.GetResponse(const AQuestion: string): IDelphiAIDevAIResponse;
var
- LQuestion: string;
LResponse: IResponse;
LJsonValueAll: TJSONValue;
LJsonValueChoices: TJSONValue;
@@ -48,30 +44,41 @@ function TDelphiAIDevAIChatGPT.GetResponse(const AQuestion: string): string;
LJsonValueMessage: TJSONValue;
LJsonObjMessage: TJSONObject;
LItemChoices: Integer;
+ LResult: string;
begin
- Result := '';
- LQuestion := TUtils.AdjustQuestionToJson(AQuestion); //AQuestion.Replace(sLineBreak, '\n', [rfReplaceAll, rfIgnoreCase]);
+ Result := FResponse;
LResponse := TRequest.New
.BaseURL(FSettings.BaseUrlOpenAI)
- .ContentType('application/json')
- .Accept('application/json')
+ .ContentType(TConsts.APPLICATION_JSON)
+ .Accept(TConsts.APPLICATION_JSON)
.Token('Bearer ' + FSettings.ApiKeyOpenAI)
- .AddBody(Format(API_JSON_BODY_BASE, [FSettings.ModelOpenAI, LQuestion]))
+ .AddBody(Format(API_JSON_BODY_BASE, [FSettings.ModelOpenAI, AQuestion]))
.Post;
+ FResponse.SetStatusCode(LResponse.StatusCode);
+
if LResponse.StatusCode <> 200 then
- Exit('Question cannot be answered' + sLineBreak + 'Return: ' + LResponse.Content);
+ begin
+ FResponse.SetContentText('Question cannot be answered' + sLineBreak + 'Return: ' + LResponse.Content);
+ Exit;
+ end;
LJsonValueAll := TJSONObject.ParseJSONValue(TEncoding.UTF8.GetBytes(LResponse.Content), 0);
if not(LJsonValueAll is TJSONObject) then
- Exit('The question cannot be answered, return object not found.' + sLineBreak +
+ begin
+ FResponse.SetContentText('The question cannot be answered, return object not found.' + sLineBreak +
'Return: ' + LResponse.Content);
+ Exit;
+ end;
LJsonValueChoices := TJSONObject(LJsonValueAll).GetValue('choices');
if not(LJsonValueChoices is TJSONArray) then
- Exit('The question cannot be answered, choices not found.' + sLineBreak +
+ begin
+ FResponse.SetContentText('The question cannot be answered, choices not found.' + sLineBreak +
'Return: ' + LResponse.Content);
+ Exit;
+ end;
LJsonArrayChoices := LJsonValueChoices as TJSONArray;
for LItemChoices := 0 to Pred(LJsonArrayChoices.Count) do
@@ -89,10 +96,10 @@ function TDelphiAIDevAIChatGPT.GetResponse(const AQuestion: string): string;
//GET MESSAGE LIKE TJSONObject
LJsonObjMessage := LJsonValueMessage as TJSONObject;
- Result := Result + TJSONString(LJsonObjMessage.GetValue('content')).Value.Trim + sLineBreak;
+ LResult := LResult + TJSONString(LJsonObjMessage.GetValue('content')).Value.Trim + sLineBreak;
end;
- Result := Result.Trim;
+ FResponse.SetContentText(LResult.Trim);
end;
end.
diff --git a/Src/AI/DelphiAIDev.AI.Facade.pas b/Src/AI/DelphiAIDev.AI.Facade.pas
new file mode 100644
index 0000000..d7f418d
--- /dev/null
+++ b/Src/AI/DelphiAIDev.AI.Facade.pas
@@ -0,0 +1,91 @@
+unit DelphiAIDev.AI.Facade;
+
+interface
+
+uses
+ System.SysUtils,
+ System.Classes,
+ DelphiAIDev.Utils,
+ DelphiAIDev.Types,
+ DelphiAIDev.Settings,
+ DelphiAIDev.AI.Interfaces,
+ DelphiAIDev.AI.Response,
+ DelphiAIDev.AI.Gemini,
+ DelphiAIDev.AI.ChatGPT,
+ DelphiAIDev.AI.Groq,
+ DelphiAIDev.AI.Mistral,
+ DelphiAIDev.AI.Ollama;
+
+type
+ IDelphiAIDevAIResponse = DelphiAIDev.AI.Interfaces.IDelphiAIDevAIResponse;
+
+ TDelphiAIDevAIFacade = class
+ private
+ FAiUse: TC4DAiAvailable;
+ FSettings: TDelphiAIDevSettings;
+ FResponse: IDelphiAIDevAIResponse;
+ public
+ constructor Create;
+ destructor Destroy; override;
+ function AiUse(const Value: TC4DAiAvailable): TDelphiAIDevAIFacade;
+ function ProcessSend(const AQuestion: string): TDelphiAIDevAIFacade;
+ function Response: IDelphiAIDevAIResponse;
+ end;
+
+implementation
+
+constructor TDelphiAIDevAIFacade.Create;
+begin
+ FSettings := TDelphiAIDevSettings.GetInstance;
+ FSettings.LoadData;
+ FAiUse := FSettings.AIDefault;
+ FResponse := TDelphiAIDevAIResponse.New;
+end;
+
+destructor TDelphiAIDevAIFacade.Destroy;
+begin
+ inherited;
+end;
+
+function TDelphiAIDevAIFacade.AiUse(const Value: TC4DAiAvailable): TDelphiAIDevAIFacade;
+begin
+ Result := Self;
+ FAiUse := Value;
+end;
+
+function TDelphiAIDevAIFacade.ProcessSend(const AQuestion: string): TDelphiAIDevAIFacade;
+var
+ LQuestion: string;
+ LRequest: IDelphiAIDevAI;
+begin
+ Result := Self;
+ LQuestion := TUtils.AdjustQuestionToJson(AQuestion);
+
+ if TUtils.DebugMyIsOn then
+ TUtils.AddLogDeleteFileFirst(LQuestion, 'DelphiAIDevAI_ProcessSend');
+
+ case FAiUse of
+ TC4DAiAvailable.Gemini:
+ LRequest := TDelphiAIDevAIGemini.Create(FSettings, FResponse);
+ TC4DAiAvailable.OpenAI:
+ LRequest := TDelphiAIDevAIChatGPT.Create(FSettings, FResponse);
+ TC4DAiAvailable.Groq:
+ LRequest := TDelphiAIDevAIGroq.Create(FSettings, FResponse);
+ TC4DAiAvailable.Mistral:
+ LRequest := TDelphiAIDevAIMistral.Create(FSettings, FResponse);
+ TC4DAiAvailable.Ollama:
+ LRequest := TDelphiAIDevAIOllama.Create(FSettings, FResponse);
+ else
+ FResponse.SetContentText('Default AI not reported in Delphi AI Developer settings');
+ Exit;
+ end;
+
+ LRequest.GetResponse(LQuestion);
+end;
+
+function TDelphiAIDevAIFacade.Response: IDelphiAIDevAIResponse;
+begin
+ Result := FResponse;
+end;
+
+end.
diff --git a/Src/AI/DelphiAIDev.AI.Gemini.pas b/Src/AI/DelphiAIDev.AI.Gemini.pas
index ea58252..ed284cf 100644
--- a/Src/AI/DelphiAIDev.AI.Gemini.pas
+++ b/Src/AI/DelphiAIDev.AI.Gemini.pas
@@ -7,19 +7,21 @@ interface
System.JSON,
System.Classes,
RESTRequest4D,
+ DelphiAIDev.Consts,
DelphiAIDev.Utils,
DelphiAIDev.Settings,
- DelphiAIDev.AI.Interfaces;
+ DelphiAIDev.AI.Interfaces,
+ DelphiAIDev.AI.Response;
type
TDelphiAIDevAIGemini = class(TInterfacedObject, IDelphiAIDevAI)
private
FSettings: TDelphiAIDevSettings;
+ FResponse: IDelphiAIDevAIResponse;
protected
- function GetResponse(const AQuestion: string): string;
+ function GetResponse(const AQuestion: string): IDelphiAIDevAIResponse;
public
- class function New(const ASettings: TDelphiAIDevSettings): IDelphiAIDevAI;
- constructor Create(const ASettings: TDelphiAIDevSettings);
+ constructor Create(const ASettings: TDelphiAIDevSettings; const AResponse: IDelphiAIDevAIResponse);
end;
implementation
@@ -27,45 +29,49 @@ implementation
const
API_JSON_BODY_BASE = '{"contents": [{"parts": [ {"text": "%s"}]}]}';
-class function TDelphiAIDevAIGemini.New(const ASettings: TDelphiAIDevSettings): IDelphiAIDevAI;
-begin
- Result := Self.Create(ASettings);
-end;
-
-constructor TDelphiAIDevAIGemini.Create(const ASettings: TDelphiAIDevSettings);
+constructor TDelphiAIDevAIGemini.Create(const ASettings: TDelphiAIDevSettings; const AResponse: IDelphiAIDevAIResponse);
begin
FSettings := ASettings;
+ FResponse := AResponse;
end;
-function TDelphiAIDevAIGemini.GetResponse(const AQuestion: string): string;
+function TDelphiAIDevAIGemini.GetResponse(const AQuestion: string): IDelphiAIDevAIResponse;
var
LApiUrl: string;
- LQuestion: string;
LResponse: IResponse;
LJsonValueAll: TJSONVALUE;
LJsonArrayCandidates: TJsonArray;
LJsonArrayParts: TJsonArray;
LJsonObjContent: TJsonObject;
LJsonObjParts: TJsonObject;
- LItemCandidates, LItemParts: Integer;
+ LItemCandidates: Integer;
+ LItemParts: Integer;
+ LResult: string;
begin
- Result := '';
- LApiUrl := FSettings.BaseUrlGemini + FSettings.ModelGemini + '?key=' + FSettings.ApiKeyGemini;
- LQuestion := TUtils.AdjustQuestionToJson(AQuestion);
+ Result := FResponse;
+ LApiUrl := FSettings.BaseUrlGemini + FSettings.ModelGemini + '?key=' + FSettings.ApiKeyGemini;
LResponse := TRequest.New
.BaseURL(LApiUrl)
- .Accept('application/json')
- .AddBody(Format(API_JSON_BODY_BASE, [LQuestion]))
+ .Accept(TConsts.APPLICATION_JSON)
+ .AddBody(Format(API_JSON_BODY_BASE, [AQuestion]))
.Post;
+ FResponse.SetStatusCode(LResponse.StatusCode);
+
if LResponse.StatusCode <> 200 then
- Exit('Question cannot be answered' + sLineBreak + 'Return: ' + LResponse.Content);
+ begin
+ FResponse.SetContentText('Question cannot be answered' + sLineBreak + 'Return: ' + LResponse.Content);
+ Exit;
+ end;
LJsonValueAll := TJsonObject.ParseJSONValue(LResponse.Content);
if not(LJsonValueAll is TJSONObject) then
- Exit('The question cannot be answered, return object not found.' + sLineBreak +
+ begin
+ FResponse.SetContentText('The question cannot be answered, return object not found.' + sLineBreak +
'Return: ' + LResponse.Content);
+ Exit;
+ end;
LJsonArrayCandidates := (LJsonValueAll as TJsonObject).GetValue('candidates');
for LItemCandidates := 0 to Pred(LJsonArrayCandidates.Count) do
@@ -75,11 +81,11 @@ function TDelphiAIDevAIGemini.GetResponse(const AQuestion: string): string;
for LItemParts := 0 to Pred(LJsonArrayParts.Count) do
begin
LJsonObjParts := LJsonArrayParts.Items[LItemParts] as TJsonObject;
- Result := Result + LJsonObjParts.GetValue('text').Trim + sLineBreak;
+ LResult := LResult + LJsonObjParts.GetValue('text').Trim + sLineBreak;
end;
end;
- Result := Result.Trim;
+ FResponse.SetContentText(LResult.Trim);
end;
end.
diff --git a/Src/AI/DelphiAIDev.AI.Groq.pas b/Src/AI/DelphiAIDev.AI.Groq.pas
index 599efde..f1a843b 100644
--- a/Src/AI/DelphiAIDev.AI.Groq.pas
+++ b/Src/AI/DelphiAIDev.AI.Groq.pas
@@ -7,6 +7,7 @@ interface
System.JSON,
System.Classes,
RESTRequest4D,
+ DelphiAIDev.Consts,
DelphiAIDev.Utils,
DelphiAIDev.Settings,
DelphiAIDev.AI.Interfaces;
@@ -15,11 +16,11 @@ interface
TDelphiAIDevAIGroq = class(TInterfacedObject, IDelphiAIDevAI)
private
FSettings: TDelphiAIDevSettings;
+ FResponse: IDelphiAIDevAIResponse;
protected
- function GetResponse(const AQuestion: string): string;
+ function GetResponse(const AQuestion: string): IDelphiAIDevAIResponse;
public
- class function New(const ASettings: TDelphiAIDevSettings): IDelphiAIDevAI;
- constructor Create(const ASettings: TDelphiAIDevSettings);
+ constructor Create(const ASettings: TDelphiAIDevSettings; const AResponse: IDelphiAIDevAIResponse);
end;
implementation
@@ -27,54 +28,57 @@ implementation
const
API_JSON_BODY_BASE = '{"messages": [{"role": "user", "content": "%s"}], "model": "%s"}';
-class function TDelphiAIDevAIGroq.New(const ASettings: TDelphiAIDevSettings): IDelphiAIDevAI;
-begin
- Result := Self.Create(ASettings);
-end;
-
-constructor TDelphiAIDevAIGroq.Create(const ASettings: TDelphiAIDevSettings);
+constructor TDelphiAIDevAIGroq.Create(const ASettings: TDelphiAIDevSettings; const AResponse: IDelphiAIDevAIResponse);
begin
FSettings := ASettings;
+ FResponse := AResponse;
end;
-function TDelphiAIDevAIGroq.GetResponse(const AQuestion: string): string;
+function TDelphiAIDevAIGroq.GetResponse(const AQuestion: string): IDelphiAIDevAIResponse;
var
- LQuestion: string;
LResponse: IResponse;
LJsonValueAll: TJSONVALUE;
LJsonArrayChoices: TJsonArray;
LJsonObjMessage: TJsonObject;
LContent: string;
LItemChoices: Integer;
+ LResult: string;
begin
- Result := '';
- LQuestion := TUtils.AdjustQuestionToJson(AQuestion);
+ Result := FResponse;
LResponse := TRequest.New
.BaseURL(FSettings.BaseUrlGroq)
- .ContentType('application/json')
- .Accept('application/json')
+ .ContentType(TConsts.APPLICATION_JSON)
+ .Accept(TConsts.APPLICATION_JSON)
.Token('Bearer ' + FSettings.ApiKeyGroq)
- .AddBody(Format(API_JSON_BODY_BASE, [LQuestion, FSettings.ModelGroq]))
+ .AddBody(Format(API_JSON_BODY_BASE, [AQuestion, FSettings.ModelGroq]))
.Post;
+ FResponse.SetStatusCode(LResponse.StatusCode);
+
if LResponse.StatusCode <> 200 then
- Exit('Question cannot be answered' + sLineBreak + 'Return: ' + LResponse.Content);
+ begin
+ FResponse.SetContentText('Question cannot be answered' + sLineBreak + 'Return: ' + LResponse.Content);
+ Exit;
+ end;
LJsonValueAll := TJsonObject.ParseJSONValue(LResponse.Content);
if not(LJsonValueAll is TJSONObject) then
- Exit('The question cannot be answered, return object not found.' + sLineBreak +
+ begin
+ FResponse.SetContentText('The question cannot be answered, return object not found.' + sLineBreak +
'Return: ' + LResponse.Content);
+ Exit;
+ end;
LJsonArrayChoices := (LJsonValueAll as TJsonObject).GetValue('choices');
for LItemChoices := 0 to Pred(LJsonArrayChoices.Count) do
begin
LJsonObjMessage := LJsonArrayChoices.Items[LItemChoices].GetValue('message');
LContent := LJsonObjMessage.GetValue('content');
- Result := Result + LContent.Trim + sLineBreak;
+ LResult := LResult + LContent.Trim + sLineBreak;
end;
- Result := Result.Trim;
+ FResponse.SetContentText(LResult.Trim);
end;
end.
diff --git a/Src/AI/DelphiAIDev.AI.Interfaces.pas b/Src/AI/DelphiAIDev.AI.Interfaces.pas
index a06e489..71317c8 100644
--- a/Src/AI/DelphiAIDev.AI.Interfaces.pas
+++ b/Src/AI/DelphiAIDev.AI.Interfaces.pas
@@ -2,10 +2,22 @@
interface
+uses
+ System.Classes;
+
type
+ IDelphiAIDevAIResponse = interface
+ ['{F9E7734A-33FA-4448-9F5D-A3680FFFFFB9}']
+ function Clear: IDelphiAIDevAIResponse;
+ function SetStatusCode(const Value: Integer): IDelphiAIDevAIResponse;
+ function GetStatusCode: Integer;
+ function SetContentText(const Value: string): IDelphiAIDevAIResponse;
+ function GetContent: TStrings;
+ end;
+
IDelphiAIDevAI = interface
['{B82FACA6-66DA-4DC0-877F-8263B5C172C1}']
- function GetResponse(const AQuestion: string): string;
+ function GetResponse(const AQuestion: string): IDelphiAIDevAIResponse;
end;
implementation
diff --git a/Src/AI/DelphiAIDev.AI.Mistral.pas b/Src/AI/DelphiAIDev.AI.Mistral.pas
new file mode 100644
index 0000000..572dcba
--- /dev/null
+++ b/Src/AI/DelphiAIDev.AI.Mistral.pas
@@ -0,0 +1,84 @@
+unit DelphiAIDev.AI.Mistral;
+
+interface
+
+uses
+ System.SysUtils,
+ System.JSON,
+ System.Classes,
+ RESTRequest4D,
+ DelphiAIDev.Consts,
+ DelphiAIDev.Utils,
+ DelphiAIDev.Settings,
+ DelphiAIDev.AI.Interfaces;
+
+type
+ TDelphiAIDevAIMistral = class(TInterfacedObject, IDelphiAIDevAI)
+ private
+ FSettings: TDelphiAIDevSettings;
+ FResponse: IDelphiAIDevAIResponse;
+ protected
+ function GetResponse(const AQuestion: string): IDelphiAIDevAIResponse;
+ public
+ constructor Create(const ASettings: TDelphiAIDevSettings; const AResponse: IDelphiAIDevAIResponse);
+ end;
+
+implementation
+
+const
+ API_JSON_BODY_BASE = '{"messages": [{"role": "user", "content": "%s"}], "model": "%s"}';
+
+constructor TDelphiAIDevAIMistral.Create(const ASettings: TDelphiAIDevSettings; const AResponse: IDelphiAIDevAIResponse);
+begin
+ FSettings := ASettings;
+ FResponse := AResponse;
+end;
+
+function TDelphiAIDevAIMistral.GetResponse(const AQuestion: string): IDelphiAIDevAIResponse;
+var
+ LResponse: IResponse;
+ LJsonValueAll: TJSONVALUE;
+ LJsonArrayChoices: TJsonArray;
+ LJsonObjMessage: TJsonObject;
+ LContent: string;
+ LItemChoices: Integer;
+ LResult: string;
+begin
+ Result := FResponse;
+
+ LResponse := TRequest.New
+ .BaseURL(FSettings.BaseUrlMistral)
+ .ContentType(TConsts.APPLICATION_JSON)
+ .Accept(TConsts.APPLICATION_JSON)
+ .Token('Bearer ' + FSettings.ApiKeyMistral)
+ .AddBody(Format(API_JSON_BODY_BASE, [AQuestion, FSettings.ModelMistral]))
+ .Post;
+
+ FResponse.SetStatusCode(LResponse.StatusCode);
+
+ if LResponse.StatusCode <> 200 then
+ begin
+ FResponse.SetContentText('Question cannot be answered' + sLineBreak + 'Return: ' + LResponse.Content);
+ Exit;
+ end;
+
+ LJsonValueAll := TJsonObject.ParseJSONValue(LResponse.Content);
+ if not(LJsonValueAll is TJSONObject) then
+ begin
+ FResponse.SetContentText('The question cannot be answered, return object not found.' + sLineBreak +
+ 'Return: ' + LResponse.Content);
+ Exit;
+ end;
+
+ LJsonArrayChoices := (LJsonValueAll as TJsonObject).GetValue('choices');
+ for LItemChoices := 0 to Pred(LJsonArrayChoices.Count) do
+ begin
+ LJsonObjMessage := LJsonArrayChoices.Items[LItemChoices].GetValue('message');
+ LContent := LJsonObjMessage.GetValue('content');
+ LResult := LResult + LContent.Trim + sLineBreak;
+ end;
+
+ FResponse.SetContentText(LResult.Trim);
+end;
+
+end.
diff --git a/Src/AI/DelphiAIDev.AI.Ollama.pas b/Src/AI/DelphiAIDev.AI.Ollama.pas
new file mode 100644
index 0000000..e1496bc
--- /dev/null
+++ b/Src/AI/DelphiAIDev.AI.Ollama.pas
@@ -0,0 +1,96 @@
+unit DelphiAIDev.AI.Ollama;
+
+interface
+
+uses
+ System.SysUtils,
+ System.JSON,
+ System.Classes,
+ RESTRequest4D,
+ DelphiAIDev.Consts,
+ DelphiAIDev.Utils,
+ DelphiAIDev.Settings,
+ DelphiAIDev.AI.Interfaces;
+
+type
+ TDelphiAIDevAIOllama = class(TInterfacedObject, IDelphiAIDevAI)
+ private
+ FSettings: TDelphiAIDevSettings;
+ FResponse: IDelphiAIDevAIResponse;
+ protected
+ function GetResponse(const AQuestion: string): IDelphiAIDevAIResponse;
+ public
+ constructor Create(const ASettings: TDelphiAIDevSettings; const AResponse: IDelphiAIDevAIResponse);
+ end;
+
+implementation
+
+const
+ API_JSON_BODY_BASE =
+ '{"model": "%s", '+
+ '"messages": [{"role": "user", "content": "%s"}], '+
+ '"options": {"seed": 101, "temperature": 0}, '+
+ '"stream": false}';
+
+constructor TDelphiAIDevAIOllama.Create(const ASettings: TDelphiAIDevSettings; const AResponse: IDelphiAIDevAIResponse);
+begin
+ FSettings := ASettings;
+ FResponse := AResponse;
+end;
+
+function TDelphiAIDevAIOllama.GetResponse(const AQuestion: string): IDelphiAIDevAIResponse;
+var
+ LResponse: IResponse;
+ LJsonValueAll: TJSONVALUE;
+ LJsonValueMessage: TJSONValue;
+ LJsonObjMessage: TJsonObject;
+begin
+ Result := FResponse;
+
+ try
+ LResponse := TRequest.New
+ .BaseURL(FSettings.BaseUrlOllama)
+ .ContentType(TConsts.APPLICATION_JSON)
+ .Accept(TConsts.APPLICATION_JSON)
+ //.Token('Bearer ' + FSettings.ApiKeyOllama)
+ .AddBody(Format(API_JSON_BODY_BASE, [FSettings.ModelOllama, AQuestion]))
+ .Post;
+ except
+ on E: Exception do
+ begin
+ FResponse.SetStatusCode(LResponse.StatusCode)
+ .SetContentText('The question cannot be answered, return object not found.' + sLineBreak +
+ 'Return: ' + LResponse.Content);
+ Exit;
+ end;
+ end;
+
+ FResponse.SetStatusCode(LResponse.StatusCode);
+
+ if LResponse.StatusCode <> 200 then
+ begin
+ FResponse.SetContentText('Question cannot be answered' + sLineBreak + 'Return: ' + LResponse.Content);
+ Exit;
+ end;
+
+ LJsonValueAll := TJSONObject.ParseJSONValue(TEncoding.UTF8.GetBytes(LResponse.Content), 0);
+ if not(LJsonValueAll is TJSONObject) then
+ begin
+ FResponse.SetContentText('The question cannot be answered, return object not found.' + sLineBreak +
+ 'Return: ' + LResponse.Content);
+ Exit;
+ end;
+
+ LJsonValueMessage := (LJsonValueAll as TJSONObject).GetValue('message');
+ if not(LJsonValueMessage is TJSONObject) then
+ begin
+ FResponse.SetContentText('The question cannot be answered, return object not found.' + sLineBreak +
+ 'Return: ' + LResponse.Content);
+ Exit;
+ end;
+
+ LJsonObjMessage := LJsonValueMessage as TJSONObject;
+ FResponse.SetContentText(TJSONString(LJsonObjMessage.GetValue('content')).Value.Trim);
+end;
+
+end.
diff --git a/Src/AI/DelphiAIDev.AI.Response.pas b/Src/AI/DelphiAIDev.AI.Response.pas
new file mode 100644
index 0000000..1481f03
--- /dev/null
+++ b/Src/AI/DelphiAIDev.AI.Response.pas
@@ -0,0 +1,75 @@
+unit DelphiAIDev.AI.Response;
+
+interface
+
+uses
+ System.SysUtils,
+ System.Classes,
+ DelphiAIDev.AI.Interfaces;
+
+type
+ TDelphiAIDevAIResponse = class(TInterfacedObject, IDelphiAIDevAIResponse)
+ private
+ FStatusCode: Integer;
+ FContent: TStrings;
+ protected
+ function Clear: IDelphiAIDevAIResponse;
+ function SetStatusCode(const Value: Integer): IDelphiAIDevAIResponse;
+ function GetStatusCode: Integer;
+ function SetContentText(const Value: string): IDelphiAIDevAIResponse;
+ function GetContent: TStrings;
+ public
+ class function New: IDelphiAIDevAIResponse;
+ constructor Create;
+ destructor Destroy; override;
+ end;
+
+implementation
+
+class function TDelphiAIDevAIResponse.New: IDelphiAIDevAIResponse;
+begin
+ Result := Self.Create;
+end;
+
+constructor TDelphiAIDevAIResponse.Create;
+begin
+ FContent := TStringList.Create;
+ Self.Clear;
+end;
+
+destructor TDelphiAIDevAIResponse.Destroy;
+begin
+ FContent.Free;
+ inherited;
+end;
+
+function TDelphiAIDevAIResponse.Clear: IDelphiAIDevAIResponse;
+begin
+ Result := Self;
+ FStatusCode := 0;
+ FContent.Clear;
+end;
+
+function TDelphiAIDevAIResponse.SetStatusCode(const Value: Integer): IDelphiAIDevAIResponse;
+begin
+ Result := Self;
+ FStatusCode := Value;
+end;
+
+function TDelphiAIDevAIResponse.GetStatusCode: Integer;
+begin
+ Result := FStatusCode;
+end;
+
+function TDelphiAIDevAIResponse.SetContentText(const Value: string): IDelphiAIDevAIResponse;
+begin
+ Result := Self;
+ FContent.Text := Value;
+end;
+
+function TDelphiAIDevAIResponse.GetContent: TStrings;
+begin
+ Result := FContent;
+end;
+
+end.
diff --git a/Src/Chat/DelphiAIDev.Chat.ProcessResponse.pas b/Src/Chat/DelphiAIDev.Chat.ProcessResponse.pas
index 73c75f9..060ef51 100644
--- a/Src/Chat/DelphiAIDev.Chat.ProcessResponse.pas
+++ b/Src/Chat/DelphiAIDev.Chat.ProcessResponse.pas
@@ -121,14 +121,14 @@ procedure TDelphiAIDevChatProcessResponse.BoldInWordsBetweenBacktick(const ALine
if not LCodeStarted then
begin
- if(LCurrentLetter = BACKTICK)and(LNextLetter <> BACKTICK)then
+ if (LCurrentLetter = BACKTICK) and (LNextLetter <> BACKTICK) then
begin
LCodeStarted := True;
Continue;
end;
end;
- if(LCurrentLetter = BACKTICK)and(LNextLetter <> BACKTICK)then
+ if (LCurrentLetter = BACKTICK) and (LNextLetter <> BACKTICK) then
begin
LCodeStarted := False;
FRichEdit.SelAttributes.Style := [];
@@ -177,7 +177,7 @@ procedure TDelphiAIDevChatProcessResponse.BoldInWordsBetweenTwoAsterisk(const AL
if not LCodeStarted then
begin
- if(LCurrentLetter = ASTERISK)and(LNextLetter = ASTERISK)then
+ if (LCurrentLetter = ASTERISK) and (LNextLetter = ASTERISK) then
begin
LCodeStarted := True;
Inc(LPosLetter, 2);
@@ -185,7 +185,7 @@ procedure TDelphiAIDevChatProcessResponse.BoldInWordsBetweenTwoAsterisk(const AL
end;
end;
- if(LCurrentLetter = ASTERISK)and(LNextLetter = ASTERISK)then
+ if (LCurrentLetter = ASTERISK) and (LNextLetter = ASTERISK) then
begin
LCodeStarted := False;
FRichEdit.SelAttributes.Style := [];
diff --git a/Src/Chat/DelphiAIDev.Chat.View.dfm b/Src/Chat/DelphiAIDev.Chat.View.dfm
index 9c5c1b6..e98bf09 100644
--- a/Src/Chat/DelphiAIDev.Chat.View.dfm
+++ b/Src/Chat/DelphiAIDev.Chat.View.dfm
@@ -12,7 +12,6 @@ object DelphiAIDevChatView: TDelphiAIDevChatView
Font.Name = 'Tahoma'
Font.Style = []
KeyPreview = True
- OldCreateOrder = False
Position = poScreenCenter
ShowHint = True
OnActivate = FormActivate
@@ -22,7 +21,6 @@ object DelphiAIDevChatView: TDelphiAIDevChatView
DesignSize = (
975
661)
- PixelsPerInch = 96
TextHeight = 13
object pnBack: TPanel
Left = 0
@@ -67,7 +65,7 @@ object DelphiAIDevChatView: TDelphiAIDevChatView
Ctl3D = True
Font.Charset = ANSI_CHARSET
Font.Color = clWindow
- Font.Height = -12
+ Font.Height = -13
Font.Name = 'Courier New'
Font.Style = []
Lines.Strings = (
@@ -80,7 +78,6 @@ object DelphiAIDevChatView: TDelphiAIDevChatView
ScrollBars = ssVertical
ShowHint = True
TabOrder = 1
- Zoom = 100
end
object pnBackQuestion: TPanel
Left = 18
@@ -109,7 +106,7 @@ object DelphiAIDevChatView: TDelphiAIDevChatView
Align = alClient
Font.Charset = DEFAULT_CHARSET
Font.Color = clWindowText
- Font.Height = -11
+ Font.Height = -13
Font.Name = 'Tahoma'
Font.Style = []
ParentFont = False
@@ -119,7 +116,7 @@ object DelphiAIDevChatView: TDelphiAIDevChatView
OnKeyUp = mmQuestionKeyUp
end
end
- object pnBackStatusBar: TPanel
+ object pnBackButtons: TPanel
Left = 18
Top = 634
Width = 938
@@ -818,6 +815,16 @@ object DelphiAIDevChatView: TDelphiAIDevChatView
Caption = 'Groq'
OnClick = Gemini1Click
end
+ object Mistral1: TMenuItem
+ Tag = 3
+ Caption = 'Mistral'
+ OnClick = Gemini1Click
+ end
+ object Ollama1: TMenuItem
+ Tag = 4
+ Caption = 'Ollama (offline)'
+ OnClick = Gemini1Click
+ end
end
object pMenuMoreActions: TPopupMenu
Images = ImageList1
diff --git a/Src/Chat/DelphiAIDev.Chat.View.pas b/Src/Chat/DelphiAIDev.Chat.View.pas
index fe424a3..7896092 100644
--- a/Src/Chat/DelphiAIDev.Chat.View.pas
+++ b/Src/Chat/DelphiAIDev.Chat.View.pas
@@ -26,7 +26,7 @@ interface
Clipbrd,
DelphiAIDev.Types,
DelphiAIDev.Consts,
- DelphiAIDev.Chat,
+ DelphiAIDev.AI.Facade,
DelphiAIDev.Settings,
DelphiAIDev.ModuleCreator,
DelphiAIDev.DefaultsQuestions.PopupMenu,
@@ -52,7 +52,7 @@ TDelphiAIDevChatView = class(TDockableForm)
pMenuCurrentAI: TPopupMenu;
Gemini1: TMenuItem;
ChatGPT1: TMenuItem;
- pnBackStatusBar: TPanel;
+ pnBackButtons: TPanel;
lbCurrentAI: TLabel;
StatusBar1: TStatusBar;
pnCommands: TPanel;
@@ -74,6 +74,8 @@ TDelphiAIDevChatView = class(TDockableForm)
pMenuQuestions: TPopupMenu;
btnCleanAll: TSpeedButton;
Groq1: TMenuItem;
+ Mistral1: TMenuItem;
+ Ollama1: TMenuItem;
procedure FormShow(Sender: TObject);
procedure cBoxSizeFontKeyPress(Sender: TObject; var Key: Char);
procedure Cut1Click(Sender: TObject);
@@ -102,7 +104,7 @@ TDelphiAIDevChatView = class(TDockableForm)
procedure Clear1Click(Sender: TObject);
procedure btnCleanAllClick(Sender: TObject);
private
- FChat: TDelphiAIDevChat;
+ FAI: TDelphiAIDevAIFacade;
FSettings: TDelphiAIDevSettings;
FProcessResponse: TDelphiAIDevChatProcessResponse;
FPopupMenuQuestions: TDelphiAIDevDefaultsQuestionsPopupMenu;
@@ -128,7 +130,6 @@ TDelphiAIDevChatView = class(TDockableForm)
procedure DoProcessClickInItemDefaultQuestions(ACodeOnly: Boolean; AQuestion: string);
procedure ProcessWordWrap;
procedure ConfScreenOnCreate;
- procedure ValidateRegistrationOfSelectedAI;
public
constructor Create(AOwner: TComponent); override;
destructor Destroy; override;
@@ -159,10 +160,10 @@ implementation
procedure RegisterSelf;
begin
- if(not Assigned(DelphiAIDevChatView))then
+ if not Assigned(DelphiAIDevChatView) then
DelphiAIDevChatView := TDelphiAIDevChatView.Create(nil);
- if(@RegisterFieldAddress <> nil)then
+ if @RegisterFieldAddress <> nil then
RegisterFieldAddress(DelphiAIDevChatView.Name, @DelphiAIDevChatView);
RegisterDesktopFormClass(TDelphiAIDevChatView, DelphiAIDevChatView.Name, DelphiAIDevChatView.Name);
@@ -170,7 +171,7 @@ procedure RegisterSelf;
procedure Unregister;
begin
- if(@UnRegisterFieldAddress <> nil)then
+ if @UnRegisterFieldAddress <> nil then
UnRegisterFieldAddress(@DelphiAIDevChatView);
FreeAndNil(DelphiAIDevChatView);
end;
@@ -188,7 +189,7 @@ constructor TDelphiAIDevChatView.Create(AOwner: TComponent);
AutoSave := True;
SaveStateNecessary := True;
- FChat := TDelphiAIDevChat.Create;
+ FAI := TDelphiAIDevAIFacade.Create;
FSettings := TDelphiAIDevSettings.GetInstance;
FProcessResponse := TDelphiAIDevChatProcessResponse.Create(mmReturn);
FPopupMenuQuestions := TDelphiAIDevDefaultsQuestionsPopupMenu.Create;
@@ -203,7 +204,7 @@ destructor TDelphiAIDevChatView.Destroy;
Self.SaveMemoReturnInFile;
FPopupMenuQuestions.Free;
FProcessResponse.Free;
- FChat.Free;
+ FAI.Free;
inherited;
end;
@@ -241,6 +242,10 @@ procedure TDelphiAIDevChatView.ConfScreenOnCreate;
ShapeCommands.Top := 0;
ShapeCommands.Width := ShapeCommands.Parent.Width;
ShapeCommands.Height := ShapeCommands.Parent.Height;
+
+ {$IF CompilerVersion >= 34} //Sydney
+ pnWaitCaption.StyleElements := pnWaitCaption.StyleElements - [seFont];
+ {$ENDIF}
end;
procedure TDelphiAIDevChatView.ConfScreenOnShow;
@@ -279,7 +284,7 @@ procedure TDelphiAIDevChatView.mmQuestionChange(Sender: TObject);
procedure TDelphiAIDevChatView.mmQuestionKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState);
begin
- if (ssCtrl in Shift)and(Key = VK_RETURN) then
+ if (ssCtrl in Shift) and (Key = VK_RETURN) then
begin
btnSend.Click;
Key := 0;
@@ -288,7 +293,7 @@ procedure TDelphiAIDevChatView.mmQuestionKeyDown(Sender: TObject; var Key: Word;
procedure TDelphiAIDevChatView.mmQuestionKeyUp(Sender: TObject; var Key: Word; Shift: TShiftState);
begin
- if (ssCtrl in Shift)and(Key = 65) then
+ if (ssCtrl in Shift) and (Key = 65) then
begin
mmQuestion.SelectAll;
Key := 0;
@@ -344,7 +349,7 @@ procedure TDelphiAIDevChatView.FormResize(Sender: TObject);
procedure TDelphiAIDevChatView.FillMemoReturnWithFile;
begin
- if(FileExists(TUtils.GetPathFileChat))then
+ if FileExists(TUtils.GetPathFileChat) then
mmReturn.Lines.LoadFromFile(TUtils.GetPathFileChat)
end;
@@ -423,7 +428,7 @@ procedure TDelphiAIDevChatView.ProcessSend;
if mmQuestion.Lines.Text.Trim.IsEmpty then
TUtils.ShowMsgAndAbort('No questions have been added', mmQuestion);
- Self.ValidateRegistrationOfSelectedAI;
+ FSettings.ValidateFillingSelectedAI;
mmReturn.Lines.Clear;
Self.WaitingFormON;
@@ -434,7 +439,10 @@ procedure TDelphiAIDevChatView.ProcessSend;
LQuestion := TUtilsOTA.GetSelectedBlockOrAllCodeUnit.Trim + sLineBreak;
if btnCodeOnly.ImageIndex = CodeOnly_ImageIndex_ON then
- LQuestion := LQuestion + FSettings.LanguageQuestions.GetMsgCodeOnly;
+ LQuestion := LQuestion + FSettings.LanguageQuestions.GetMsgCodeOnly + sLineBreak;
+
+ if not FSettings.DefaultPrompt.Trim.IsEmpty then
+ LQuestion := LQuestion + FSettings.DefaultPrompt + sLineBreak;
LQuestion := LQuestion + mmQuestion.Lines.Text;
@@ -443,7 +451,7 @@ procedure TDelphiAIDevChatView.ProcessSend;
begin
try
try
- FChat.ProcessSend(LQuestion);
+ FAI.AiUse(FSettings.AIDefault).ProcessSend(LQuestion);
except
on E: Exception do
TThread.Synchronize(nil,
@@ -460,7 +468,7 @@ procedure TDelphiAIDevChatView.ProcessSend;
mmReturn.Lines.BeginUpdate;
try
//Optional use of one of the following lines
- FProcessResponse.AddResponseComplete(FChat.Response);
+ FProcessResponse.AddResponseComplete(FAI.Response.GetContent);
Self.Last;
//Self.AddResponseSimple(FChat.Response.Text);
finally
@@ -478,37 +486,6 @@ procedure TDelphiAIDevChatView.ProcessSend;
LTask.Start;
end;
-procedure TDelphiAIDevChatView.ValidateRegistrationOfSelectedAI;
-const
- MSG = '"%s" for IA %s not specified in settings.' + sLineBreak + sLineBreak +
- 'Access menu > AI Developer > Settings';
-begin
- case FSettings.AIDefault of
- TC4DAIsAvailable.Gemini:
- begin
- if FSettings.BaseUrlGemini.Trim.IsEmpty then
- TUtils.ShowMsgAndAbort(Format(MSG, ['Base URL', 'Gemini']));
-
- if FSettings.ModelGemini.Trim.IsEmpty then
- TUtils.ShowMsgAndAbort(Format(MSG, ['Model', 'Gemini']));
-
- if FSettings.ApiKeyGemini.Trim.IsEmpty then
- TUtils.ShowMsgAndAbort(Format(MSG, ['API Key', 'Gemini']));
- end;
- TC4DAIsAvailable.OpenAI:
- begin
- if FSettings.BaseUrlOpenAI.Trim.IsEmpty then
- TUtils.ShowMsgAndAbort(Format(MSG, ['Base URL', 'ChatGPT']));
-
- if FSettings.ModelOpenAI.Trim.IsEmpty then
- TUtils.ShowMsgAndAbort(Format(MSG, ['Model', 'ChatGPT']));
-
- if FSettings.ApiKeyOpenAI.Trim.IsEmpty then
- TUtils.ShowMsgAndAbort(Format(MSG, ['API Key', 'ChatGPT']));
- end;
- end;
-end;
-
procedure TDelphiAIDevChatView.AddResponseSimple(const AString: string);
begin
Self.Last;
@@ -518,116 +495,6 @@ procedure TDelphiAIDevChatView.AddResponseSimple(const AString: string);
Self.Last;
end;
-////Add line-by-line response to color where Delphi code is
-//procedure TDelphiAIDevChatView.AddResponseComplete(const AStrings: TStrings);
-//var
-// LLineNum: Integer;
-// LLineStr: string;
-// LCodeStarted: Boolean;
-//begin
-// mmReturn.Lines.Clear;
-// mmReturn.SelAttributes.Color := TUtilsOTA.ActiveThemeColorDefault;
-// mmReturn.SelAttributes.Style := [];
-//
-// LCodeStarted := False;
-// for LLineNum := 0 to Pred(AStrings.Count) do
-// begin
-// LLineStr := AStrings[LLineNum].TrimRight;
-//
-// if not LCodeStarted then
-// begin
-// if TUtils.CodeIdMarkBeginCode(LLineStr) then
-// begin
-// LCodeStarted := True;
-// Continue;
-// end;
-// end;
-//
-// if LLineStr.Trim = TConsts.MARK_END then
-// begin
-// LCodeStarted := False;
-// mmReturn.SelAttributes.Color := TUtilsOTA.ActiveThemeColorDefault;
-// Continue;
-// end;
-//
-// if LCodeStarted then
-// begin
-// if (FSettings.ColorHighlightCodeDelphiUse) and (FSettings.ColorHighlightCodeDelphi <> clNone) then
-// mmReturn.SelAttributes.Color := FSettings.ColorHighlightCodeDelphi
-// else
-// mmReturn.SelAttributes.Color := TUtilsOTA.ActiveThemeForCode;
-// end
-// else
-// mmReturn.SelAttributes.Color := TUtilsOTA.ActiveThemeColorDefault;
-//
-// //Optional use of one of the following lines
-// //mmReturn.Lines.Add(LLineStr);
-// Self.AddResponseLine(LLineStr); //.Replace(TConsts.MARK_BEGIN_PASCAL2, '', [rfReplaceAll, rfIgnoreCase])
-// end;
-// Self.Last;
-//end;
-//
-////Bold in words between Backtick
-//procedure TDelphiAIDevChatView.AddResponseLine(const ALineStr: string);
-//const
-// BACKTICK = '`';
-//var
-// i: Integer;
-// LCurrentLetter: Char;
-// LNextLetter: Char;
-// LLineStarted: Boolean;
-// LCodeStarted: Boolean;
-//begin
-// if not ALineStr.Contains(BACKTICK) then
-// begin
-// mmReturn.Lines.Add(IFThen(ALineStr.IsEmpty, ' ', ALineStr));
-// Exit;
-// end;
-//
-// LLineStarted := False;
-// LCodeStarted := False;
-// for i := 0 to ALineStr.Length do
-// begin
-// LCurrentLetter := ALineStr[i];
-// LNextLetter := ALineStr[Succ(i)];
-//
-// if not LCodeStarted then
-// begin
-// if(LCurrentLetter = BACKTICK)and(LNextLetter <> BACKTICK)then
-// begin
-// LCodeStarted := True;
-// Continue;
-// end;
-// end;
-//
-// if(LCurrentLetter = BACKTICK)and(LNextLetter <> BACKTICK)then
-// begin
-// LCodeStarted := False;
-// mmReturn.SelAttributes.Style := [];
-// Continue;
-// end;
-//
-// SendMessage(mmReturn.Handle, WM_VSCROLL, SB_BOTTOM, 0);
-// if LCodeStarted then
-// mmReturn.SelAttributes.Style := [fsBold]
-// else
-// mmReturn.SelAttributes.Style := [];
-//
-// if LLineStarted then
-// mmReturn.SelText := LCurrentLetter
-// else
-// begin
-// mmReturn.Lines.Add('');
-// mmReturn.SelText := LCurrentLetter;
-//
-// LLineStarted := True;
-// end;
-// SendMessage(mmReturn.Handle, WM_VSCROLL, SB_BOTTOM, 0);
-// end;
-// mmReturn.SelText := ' ';
-// SendMessage(mmReturn.Handle, WM_VSCROLL, SB_BOTTOM, 0);
-//end;
-
procedure TDelphiAIDevChatView.WaitingFormON;
begin
pnWait.Visible := False;
@@ -746,13 +613,19 @@ procedure TDelphiAIDevChatView.pMenuCurrentAIPopup(Sender: TObject);
Gemini1.Checked := False;
ChatGPT1.Checked := False;
Groq1.Checked := False;
+ Mistral1.Checked := False;
+ Ollama1.Checked := False;
case FSettings.AIDefault of
- TC4DAIsAvailable.Gemini:
+ TC4DAiAvailable.Gemini:
Gemini1.Checked := True;
- TC4DAIsAvailable.OpenAI:
+ TC4DAiAvailable.OpenAI:
ChatGPT1.Checked := True;
- TC4DAIsAvailable.Groq:
+ TC4DAiAvailable.Groq:
Groq1.Checked := True;
+ TC4DAiAvailable.Mistral:
+ Mistral1.Checked := True;
+ TC4DAiAvailable.Ollama:
+ Ollama1.Checked := True;
end;
end;
@@ -761,12 +634,16 @@ procedure TDelphiAIDevChatView.ConfLabelCurrentAI;
lbCurrentAI.Caption := FSettings.AIDefault.ToString;
case FSettings.AIDefault of
- TC4DAIsAvailable.Gemini:
+ TC4DAiAvailable.Gemini:
lbCurrentAI.Hint := FSettings.ModelGemini;
- TC4DAIsAvailable.OpenAI:
+ TC4DAiAvailable.OpenAI:
lbCurrentAI.Hint := FSettings.ModelOpenAI;
- TC4DAIsAvailable.Groq:
+ TC4DAiAvailable.Groq:
lbCurrentAI.Hint := FSettings.ModelGroq;
+ TC4DAiAvailable.Mistral:
+ lbCurrentAI.Hint := FSettings.ModelMistral;
+ TC4DAiAvailable.Ollama:
+ lbCurrentAI.Hint := FSettings.ModelOllama;
end;
lbCurrentAI.Repaint;
@@ -779,10 +656,10 @@ procedure TDelphiAIDevChatView.Gemini1Click(Sender: TObject);
begin
//*SEVERAL
LTag := TMenuItem(Sender).Tag;
- if not(LTag in [0, 1, 2])then
+ if not(LTag in [0, 1, 2, 3, 4])then
Exit;
- FSettings.AIDefault := TC4DAIsAvailable(LTag);
+ FSettings.AIDefault := TC4DAiAvailable(LTag);
FSettings.SaveData;
Self.ConfLabelCurrentAI;
end;
diff --git a/Src/Chat/DelphiAIDev.Chat.pas b/Src/Chat/DelphiAIDev.Chat.pas
deleted file mode 100644
index 614e282..0000000
--- a/Src/Chat/DelphiAIDev.Chat.pas
+++ /dev/null
@@ -1,62 +0,0 @@
-unit DelphiAIDev.Chat;
-
-interface
-
-uses
- System.SysUtils,
- System.Classes,
- DelphiAIDev.Types,
- DelphiAIDev.Settings,
- DelphiAIDev.AI.Gemini,
- DelphiAIDev.AI.ChatGPT,
- DelphiAIDev.AI.Groq;
-
-type
- TDelphiAIDevChat = class
- private
- FSettings: TDelphiAIDevSettings;
- FResponse: TStrings;
- public
- constructor Create;
- destructor Destroy; override;
- procedure ProcessSend(const AQuestion: string);
- function Response: TStrings;
- end;
-
-implementation
-
-constructor TDelphiAIDevChat.Create;
-begin
- FSettings := TDelphiAIDevSettings.GetInstance;
- FSettings.LoadData;
- FResponse := TStringList.Create;
-end;
-
-destructor TDelphiAIDevChat.Destroy;
-begin
- FResponse.Free;
- inherited;
-end;
-
-procedure TDelphiAIDevChat.ProcessSend(const AQuestion: string);
-begin
- FResponse.Clear;
-
- case FSettings.AIDefault of
- TC4DAIsAvailable.Gemini:
- FResponse.Text := TDelphiAIDevAIGemini.New(FSettings).GetResponse(AQuestion);
- TC4DAIsAvailable.OpenAI:
- FResponse.Text := TDelphiAIDevAIChatGPT.New(FSettings).GetResponse(AQuestion);
- TC4DAIsAvailable.Groq:
- FResponse.Text := TDelphiAIDevAIGroq.New(FSettings).GetResponse(AQuestion);
- else
- FResponse.Add('Default AI not reported in Delphi AI Developer settings');
- end;
-end;
-
-function TDelphiAIDevChat.Response: TStrings;
-begin
- Result := FResponse;
-end;
-
-end.
diff --git a/Src/CodeCompletion/DelphiAIDev.CodeCompletion.KeyTab.pas b/Src/CodeCompletion/DelphiAIDev.CodeCompletion.KeyTab.pas
new file mode 100644
index 0000000..1835795
--- /dev/null
+++ b/Src/CodeCompletion/DelphiAIDev.CodeCompletion.KeyTab.pas
@@ -0,0 +1,65 @@
+unit DelphiAIDev.CodeCompletion.KeyTab;
+
+interface
+
+uses
+ System.SysUtils,
+ System.Classes,
+ ToolsAPI,
+ DelphiAIDev.CodeCompletion.Vars;
+
+type
+ IDelphiAIDevCodeCompletionKeyTab = interface
+ ['{A032D6DE-E66D-4088-B384-5FEE82F65160}']
+ procedure Process(const AContext: IOTAKeyContext);
+ end;
+
+ TDelphiAIDevCodeCompletionKeyTab = class(TInterfacedObject, IDelphiAIDevCodeCompletionKeyTab)
+ private
+ FVars: TDelphiAIDevCodeCompletionVars;
+ protected
+ procedure Process(const AContext: IOTAKeyContext);
+ public
+ class function New: IDelphiAIDevCodeCompletionKeyTab;
+ constructor Create;
+ end;
+
+implementation
+
+class function TDelphiAIDevCodeCompletionKeyTab.New: IDelphiAIDevCodeCompletionKeyTab;
+begin
+ Result := Self.Create;
+end;
+
+constructor TDelphiAIDevCodeCompletionKeyTab.Create;
+begin
+ FVars := TDelphiAIDevCodeCompletionVars.GetInstance;
+end;
+
+procedure TDelphiAIDevCodeCompletionKeyTab.Process(const AContext: IOTAKeyContext);
+var
+ i: Integer;
+ LTextLine: string;
+begin
+ try
+ if FVars.Contents.Count > 1 then
+ AContext.EditBuffer.EditPosition.Delete(Pred(FVars.Contents.Count));
+
+ for i := 0 to Pred(FVars.Contents.Count) do
+ begin
+ LTextLine := FVars.Contents[i].Trim;
+
+ if FVars.Contents.Count > 1 then
+ begin
+ AContext.EditBuffer.EditPosition.MoveEOL;
+ LTextLine := FVars.Contents[i];
+ end;
+
+ AContext.EditBuffer.EditPosition.InsertText(LTextLine + sLineBreak);
+ end;
+ finally
+ FVars.Clear;
+ end;
+end;
+
+end.
diff --git a/Src/CodeCompletion/DelphiAIDev.CodeCompletion.Search.pas b/Src/CodeCompletion/DelphiAIDev.CodeCompletion.Search.pas
new file mode 100644
index 0000000..b7c6daf
--- /dev/null
+++ b/Src/CodeCompletion/DelphiAIDev.CodeCompletion.Search.pas
@@ -0,0 +1,134 @@
+unit DelphiAIDev.CodeCompletion.Search;
+
+interface
+
+uses
+ System.SysUtils,
+ System.Classes,
+ Vcl.Forms,
+ Vcl.Controls,
+ ToolsAPI,
+ DelphiAIDev.Types,
+ DelphiAIDev.Consts,
+ DelphiAIDev.Settings,
+ DelphiAIDev.Utils,
+ DelphiAIDev.Utils.OTA,
+ DelphiAIDev.CodeCompletion.Vars,
+ DelphiAIDev.AI.Facade;
+
+type
+ IDelphiAIDevCodeCompletionSearch = interface
+ ['{5F8BDEE9-14DC-4C8C-BA7A-681A94844AD8}']
+ procedure Process(const AContext: IOTAKeyContext);
+ end;
+
+ TDelphiAIDevCodeCompletionSearch = class(TInterfacedObject, IDelphiAIDevCodeCompletionSearch)
+ private
+ FSettings: TDelphiAIDevSettings;
+ FQuestions: TStrings;
+ FAIRequest: TDelphiAIDevAIFacade;
+ FVars: TDelphiAIDevCodeCompletionVars;
+ FIOTAEditPosition: IOTAEditPosition;
+ procedure ProcessQuestions(const AContext: IOTAKeyContext);
+ procedure ProcessResponse;
+ protected
+ procedure Process(const AContext: IOTAKeyContext);
+ public
+ class function New: IDelphiAIDevCodeCompletionSearch;
+ constructor Create;
+ destructor Destroy; override;
+ end;
+
+implementation
+
+class function TDelphiAIDevCodeCompletionSearch.New: IDelphiAIDevCodeCompletionSearch;
+begin
+ Result := Self.Create;
+end;
+
+constructor TDelphiAIDevCodeCompletionSearch.Create;
+begin
+ FSettings := TDelphiAIDevSettings.GetInstance;
+ FAIRequest := TDelphiAIDevAIFacade.Create;
+ FQuestions := TStringList.Create;
+ FVars := TDelphiAIDevCodeCompletionVars.GetInstance;
+end;
+
+destructor TDelphiAIDevCodeCompletionSearch.Destroy;
+begin
+ FQuestions.Free;
+ FAIRequest.Free;
+ inherited;
+end;
+
+procedure TDelphiAIDevCodeCompletionSearch.Process(const AContext: IOTAKeyContext);
+begin
+ FSettings.ValidateFillingSelectedAICodeCompletion(TShowMsg.No);
+
+ Screen.Cursor := crHourGlass;
+ try
+ Self.ProcessQuestions(AContext);
+
+ try
+ FAIRequest.AiUse(FSettings.CodeCompletionAIDefault).ProcessSend(FQuestions.Text);
+ except
+ Abort;
+ end;
+
+ Self.ProcessResponse;
+ finally
+ Screen.Cursor := crDefault;
+ end;
+end;
+
+procedure TDelphiAIDevCodeCompletionSearch.ProcessQuestions(const AContext: IOTAKeyContext);
+begin
+ FQuestions.Clear;
+ FQuestions.Add(FSettings.LanguageQuestions.GetLanguageDefinition);
+ FQuestions.Add(FSettings.LanguageQuestions.GetMsgCodeCompletionSuggestion);
+ FQuestions.Add(FSettings.LanguageQuestions.GetMsgCodeOnly);
+ if not FSettings.CodeCompletionDefaultPrompt.Trim.IsEmpty then
+ FQuestions.Add(FSettings.CodeCompletionDefaultPrompt);
+
+ FIOTAEditPosition := AContext.EditBuffer.EditPosition;
+ FIOTAEditPosition.InsertText(TConsts.TAG_CODE_COMPLETION);
+ try
+ FQuestions.Add(TUtilsOTA.GetSelectedBlockOrAllCodeUnit.Trim);
+ finally
+ FIOTAEditPosition.BackspaceDelete(TConsts.TAG_CODE_COMPLETION.Length);
+ end;
+end;
+
+procedure TDelphiAIDevCodeCompletionSearch.ProcessResponse;
+var
+ LRow: Integer;
+ LColumn: Integer;
+ LBlankTextLines: string;
+ i: Integer;
+begin
+ if FAIRequest.Response.GetStatusCode <> 200 then
+ begin
+ TUtils.ShowMsg('Unable to perform AI request.',
+ Format('Code: %d %s Message: %s', [FAIRequest.Response.GetStatusCode, sLineBreak, FAIRequest.Response.GetContent.Text]));
+ Exit;
+ end;
+
+ FVars.Module := TUtilsOTA.GetCurrentModule;
+ FVars.Contents.Text := TUtils.ConfReturnAI(FAIRequest.Response.GetContent.Text);
+ LRow := FIOTAEditPosition.Row;
+ LColumn := FIOTAEditPosition.Column;
+
+ FVars.Row := LRow;
+ FVars.Column := LColumn;
+ FVars.LineIni := LRow;
+ FVars.LineEnd := FVars.LineIni + FVars.Contents.Count;
+
+ LBlankTextLines := '';
+ for i := 1 to Pred(FVars.Contents.Count) do
+ LBlankTextLines := LBlankTextLines + sLineBreak;
+
+ FIOTAEditPosition.InsertText(LBlankTextLines);
+ FIOTAEditPosition.Move(FVars.LineIni, LColumn);
+end;
+
+end.
diff --git a/Src/CodeCompletion/DelphiAIDev.CodeCompletion.Vars.pas b/Src/CodeCompletion/DelphiAIDev.CodeCompletion.Vars.pas
new file mode 100644
index 0000000..e4f13e6
--- /dev/null
+++ b/Src/CodeCompletion/DelphiAIDev.CodeCompletion.Vars.pas
@@ -0,0 +1,76 @@
+unit DelphiAIDev.CodeCompletion.Vars;
+
+interface
+
+uses
+ System.SysUtils,
+ System.Classes,
+ ToolsAPI;
+
+type
+ TDelphiAIDevCodeCompletionVars = class
+ private
+ FRelease: Boolean;
+ FModule: IOTAModule;
+ FLineIni: Integer;
+ FLineEnd: Integer;
+ FRow: Integer;
+ FColumn: Integer;
+ FContents: TStrings;
+ constructor Create;
+ public
+ class function GetInstance: TDelphiAIDevCodeCompletionVars;
+ destructor Destroy; override;
+ procedure Clear;
+ property Release: Boolean read FRelease write FRelease;
+ property Module: IOTAModule read FModule write FModule;
+ property LineIni: Integer read FLineIni write FLineIni;
+ property LineEnd: Integer read FLineEnd write FLineEnd;
+ property Row: Integer read FRow write FRow;
+ property Column: Integer read FColumn write FColumn;
+ property Contents: TStrings read FContents write FContents;
+ end;
+
+implementation
+
+var
+ Instance: TDelphiAIDevCodeCompletionVars;
+
+class function TDelphiAIDevCodeCompletionVars.GetInstance: TDelphiAIDevCodeCompletionVars;
+begin
+ if not Assigned(Instance) then
+ Instance := Self.Create;
+
+ Result := Instance;
+end;
+
+constructor TDelphiAIDevCodeCompletionVars.Create;
+begin
+ FContents := TStringList.Create;
+ Self.Clear;
+end;
+
+destructor TDelphiAIDevCodeCompletionVars.Destroy;
+begin
+ FContents.Free;
+ inherited;
+end;
+
+procedure TDelphiAIDevCodeCompletionVars.Clear;
+begin
+ FRelease := False;
+ FModule := nil;
+ FLineIni := 0;
+ FLineEnd := 0;
+ FRow := 0;
+ FColumn := 0;
+ FContents.Clear;
+end;
+
+initialization
+
+finalization
+ if Assigned(Instance) then
+ FreeAndNil(Instance);
+
+end.
diff --git a/Src/Conn/C4D.Conn.Configs.pas b/Src/Conn/C4D.Conn.Configs.pas
new file mode 100644
index 0000000..48192cf
--- /dev/null
+++ b/Src/Conn/C4D.Conn.Configs.pas
@@ -0,0 +1,184 @@
+unit C4D.Conn.Configs;
+
+interface
+
+uses
+ System.SysUtils,
+ System.Classes,
+ C4D.Conn.Types,
+ DelphiAIDev.Types;
+
+type
+ TC4DConnConfigs = class
+ private
+ FComponentConnection: TComponentConnection;
+ FDriverID: TC4DDriverID;
+ FHost: string;
+ FUserName: string;
+ FPassword: string;
+ FDatabase: string;
+ FPort: Integer;
+ FVendorLib: string;
+ procedure Clear;
+ public
+ constructor Create;
+ destructor Destroy; override;
+ function ComponentConnection: TComponentConnection;
+ function DriverID: TC4DDriverID; overload;
+ function DriverID(Value: TC4DDriverID): TC4DConnConfigs; overload;
+ function Host: string; overload;
+ function Host(Value: string): TC4DConnConfigs; overload;
+ function UserName: string; overload;
+ function UserName(Value: string): TC4DConnConfigs; overload;
+ function Password: string; overload;
+ function Password(Value: string): TC4DConnConfigs; overload;
+ function Database: string; overload;
+ function Database(Value: string): TC4DConnConfigs; overload;
+ function Port: Integer; overload;
+ function Port(Value: Integer): TC4DConnConfigs; overload;
+ function VendorLib: string; overload;
+ function VendorLib(Value: string): TC4DConnConfigs; overload;
+ function TestFieldFilling: TC4DConnConfigs;
+ end;
+
+implementation
+
+constructor TC4DConnConfigs.Create;
+begin
+ Self.Clear;
+
+ {$IFDEF C4D_ZEOS}
+ FComponentConnection := TComponentConnection.Zeos;
+ {$ELSE}
+ FComponentConnection := TComponentConnection.FireDac;
+ {$ENDIF}
+end;
+
+destructor TC4DConnConfigs.Destroy;
+begin
+ inherited;
+end;
+
+procedure TC4DConnConfigs.Clear;
+begin
+ FDriverID := TC4DDriverID.None;;
+ FHost := '';
+ FUserName := '';
+ FPassword := '';
+ FDatabase := '';
+ FPort := 0;
+ FVendorLib := '';
+end;
+
+function TC4DConnConfigs.ComponentConnection: TComponentConnection;
+begin
+ if FComponentConnection = TComponentConnection.Empty then
+ raise Exception.Create('Component for connection to the bank not informed');
+
+ Result := FComponentConnection;
+end;
+
+function TC4DConnConfigs.DriverID: TC4DDriverID;
+begin
+ Result := FDriverID;
+end;
+
+function TC4DConnConfigs.DriverID(Value: TC4DDriverID): TC4DConnConfigs;
+begin
+ Result := Self;
+ FDriverID := Value;
+end;
+
+function TC4DConnConfigs.Host: string;
+begin
+ Result := FHost;
+end;
+
+function TC4DConnConfigs.Host(Value: string): TC4DConnConfigs;
+begin
+ Result := Self;
+ FHost := Value;
+end;
+
+function TC4DConnConfigs.UserName: string;
+begin
+ Result := FUserName;
+end;
+
+function TC4DConnConfigs.UserName(Value: string): TC4DConnConfigs;
+begin
+ Result := Self;
+ FUserName := Value;
+end;
+
+function TC4DConnConfigs.Password: string;
+begin
+ Result := FPassword;
+end;
+
+function TC4DConnConfigs.Password(Value: string): TC4DConnConfigs;
+begin
+ Result := Self;
+ FPassword := Value;
+end;
+
+function TC4DConnConfigs.Database: string;
+begin
+ Result := FDatabase;
+end;
+
+function TC4DConnConfigs.Database(Value: string): TC4DConnConfigs;
+begin
+ Result := Self;
+ FDatabase := Value;
+end;
+
+function TC4DConnConfigs.Port: Integer;
+begin
+ Result := FPort;
+end;
+
+function TC4DConnConfigs.Port(Value: Integer): TC4DConnConfigs;
+begin
+ Result := Self;
+ FPort := Value;
+end;
+
+function TC4DConnConfigs.VendorLib: string;
+begin
+ Result := FVendorLib;
+end;
+
+function TC4DConnConfigs.VendorLib(Value: string): TC4DConnConfigs;
+begin
+ Result := Self;
+ FVendorLib := Value;
+end;
+
+function TC4DConnConfigs.TestFieldFilling: TC4DConnConfigs;
+var
+ LTemp: string;
+begin
+ Result := Self;
+ LTemp := '';
+
+ if FDriverID = TC4DDriverID.None then
+ LTemp := LTemp + 'Driver ID. ';
+
+ if FHost.Trim.IsEmpty then
+ LTemp := LTemp + 'Host. ';
+
+ if FUserName.Trim.IsEmpty then
+ LTemp := LTemp + 'User. ';
+
+ if FPassword.Trim.IsEmpty then
+ LTemp := LTemp + 'Password. ';
+
+ if FDatabase.Trim.IsEmpty then
+ LTemp := LTemp + 'Database name.';
+
+ if not LTemp.Trim.IsEmpty then
+ raise Exception.Create('To connect to the database, the following data must be filled in: ' + LTemp);
+end;
+
+end.
diff --git a/Src/Conn/C4D.Conn.Firedac.Query.pas b/Src/Conn/C4D.Conn.Firedac.Query.pas
new file mode 100644
index 0000000..e998cc1
--- /dev/null
+++ b/Src/Conn/C4D.Conn.Firedac.Query.pas
@@ -0,0 +1,433 @@
+unit C4D.Conn.Firedac.Query;
+
+interface
+
+uses
+ System.SysUtils,
+ System.StrUtils,
+ System.Classes,
+ System.Generics.Collections,
+ Data.DB,
+ Firedac.Stan.Intf,
+ Firedac.Stan.Option,
+ Firedac.Stan.Param,
+ Firedac.Stan.Error,
+ Firedac.DatS,
+ Firedac.Phys.Intf,
+ Firedac.DApt.Intf,
+ Firedac.Stan.Async,
+ Firedac.DApt,
+ Firedac.Comp.DataSet,
+ Firedac.Comp.Client,
+ Firedac.Stan.Def,
+ C4D.Conn.Interfaces,
+ C4D.Conn.Firedac,
+ C4D.Conn.Utils;
+
+type
+ TC4DConnFiredacQuery = class(TInterfacedObject, IC4DConnQuery)
+ private
+ FC4DConnection: IC4DConnection;
+ FQuery: TFDQuery;
+ FListCond: TStringList;
+ FListCondParam: TDictionary;
+ FListGroup: TStringList;
+ FListOrder: TStringList;
+ FListLimit: TStringList;
+ procedure ProcessaListCond;
+ procedure ProcessaListGroup;
+ procedure ProcessaListOrder;
+ procedure ProcessListLimit;
+ protected
+ function Close: IC4DConnQuery;
+ function Clear: IC4DConnQuery;
+ function CloseClear: IC4DConnQuery;
+ function Add(Value: string): IC4DConnQuery;
+ function AddParam(Param: string; Value: Variant): IC4DConnQuery;
+ function AddCond(ACond: string): IC4DConnQuery;
+ function AddCondParam(Param: string; Value: Variant): IC4DConnQuery;
+ function AddGroup(ACond: string): IC4DConnQuery;
+ function AddOrder(ACond: string): IC4DConnQuery;
+ function AddLimit(ACond: string): IC4DConnQuery;
+ function Text(Value: string): IC4DConnQuery;
+ function SQL: TStrings;
+ function ExecSQL: IC4DConnQuery; overload;
+ function ExecSQL(const ASQL: string): IC4DConnQuery; overload;
+ function Open: IC4DConnQuery; overload;
+ function Open(const ASQL: string): IC4DConnQuery; overload;
+
+ function DataSet: TDataSet;
+ function DataSource(Value: TDataSource): IC4DConnQuery;
+ function DataSourceMasterDetail(Value: TDataSource): IC4DConnQuery;
+
+ function Append: IC4DConnQuery;
+ function Edit: IC4DConnQuery;
+ function Post: IC4DConnQuery;
+ function Delete: IC4DConnQuery;
+
+ function Eof: Boolean;
+ function Bof: Boolean;
+ function Prior: IC4DConnQuery;
+ function Next: IC4DConnQuery;
+ function First: IC4DConnQuery;
+ function Last: IC4DConnQuery;
+ function IsEmpty: Boolean;
+ function RowsAffected: Integer;
+ function FieldByName(Value: string): TField;
+ function RecNo: Integer;
+ function RecordCount: Integer;
+ function RecordCountStr(ANumZerosLeft: Integer = 6): string;
+ function IndexFieldNames: string; overload;
+ function IndexFieldNames(Value: string): IC4DConnQuery; overload;
+ function GetLastAutoGenValue(const AName: string): Variant;
+ public
+ class function New(AC4DConnection: IC4DConnection; ANameQuery: string): IC4DConnQuery;
+ constructor Create(AC4DConnection: IC4DConnection; ANameQuery: string);
+ destructor Destroy; override;
+ end;
+
+implementation
+
+class function TC4DConnFiredacQuery.New(AC4DConnection: IC4DConnection; ANameQuery: string): IC4DConnQuery;
+begin
+ Result := Self.Create(AC4DConnection, ANameQuery);
+end;
+
+constructor TC4DConnFiredacQuery.Create(AC4DConnection: IC4DConnection; ANameQuery: string);
+begin
+ FC4DConnection := AC4DConnection;
+
+ FQuery := TFDQuery.Create(nil);
+ FQuery.Name := ANameQuery;
+ FQuery.FetchOptions.Mode := fmAll;
+ FQuery.Connection := TFDConnection(FC4DConnection.Component);
+ FQuery.Close;
+ FQuery.SQL.Clear;
+
+ FListCond := TStringList.Create;
+ FListCondParam := TDictionary.Create;
+ FListGroup := TStringList.Create;
+ FListOrder := TStringList.Create;
+ FListLimit := TStringList.Create;
+end;
+
+destructor TC4DConnFiredacQuery.Destroy;
+begin
+ FListLimit.Free;
+ FListOrder.Free;
+ FListGroup.Free;
+ FListCondParam.Free;
+ FListCond.Free;
+ FreeAndNil(FQuery);
+ inherited;
+end;
+
+function TC4DConnFiredacQuery.Close: IC4DConnQuery;
+begin
+ Result := Self;
+ FQuery.Close;
+end;
+
+function TC4DConnFiredacQuery.Clear: IC4DConnQuery;
+begin
+ Result := Self;
+ FQuery.SQL.Clear;
+ FListCond.Clear;
+ FListCondParam.Clear;
+ FListLimit.Clear;
+ FListGroup.Clear;
+ FListOrder.Clear;
+end;
+
+function TC4DConnFiredacQuery.CloseClear: IC4DConnQuery;
+begin
+ Result := Self;
+ Self.Close;
+ Self.Clear;
+end;
+
+function TC4DConnFiredacQuery.Add(Value: string): IC4DConnQuery;
+begin
+ Result := Self;
+ FQuery.SQL.Add(Value);
+end;
+
+function TC4DConnFiredacQuery.AddParam(Param: string; Value: Variant): IC4DConnQuery;
+begin
+ Result := Self;
+ FQuery.ParamByName(Param).Value := Value;
+end;
+
+function TC4DConnFiredacQuery.AddCond(ACond: string): IC4DConnQuery;
+begin
+ Result := Self;
+ FListCond.Add(ACond);
+end;
+
+function TC4DConnFiredacQuery.AddCondParam(Param: string; Value: Variant): IC4DConnQuery;
+begin
+ Result := Self;
+ FListCondParam.Add(Param, Value);
+end;
+
+function TC4DConnFiredacQuery.AddGroup(ACond: string): IC4DConnQuery;
+begin
+ Result := Self;
+ FListGroup.Add(ACond);
+end;
+
+function TC4DConnFiredacQuery.AddOrder(ACond: string): IC4DConnQuery;
+begin
+ Result := Self;
+ FListOrder.Add(ACond);
+end;
+
+function TC4DConnFiredacQuery.AddLimit(ACond: string): IC4DConnQuery;
+begin
+ Result := Self;
+ FListLimit.Add(ACond);
+end;
+
+function TC4DConnFiredacQuery.Text(Value: string): IC4DConnQuery;
+begin
+ Result := Self;
+ FQuery.SQL.Text := Value;
+end;
+
+function TC4DConnFiredacQuery.ExecSQL: IC4DConnQuery;
+begin
+ Result := Self;
+ FQuery.ExecSQL;
+end;
+
+function TC4DConnFiredacQuery.ExecSQL(const ASQL: string): IC4DConnQuery;
+begin
+ Result := Self;
+ FQuery.ExecSQL(ASQL);
+end;
+
+function TC4DConnFiredacQuery.Open: IC4DConnQuery;
+begin
+ Result := Self;
+ Self.ProcessaListCond;
+ Self.ProcessaListGroup;
+ Self.ProcessaListOrder;
+ Self.ProcessListLimit;
+ FQuery.Open;
+end;
+
+function TC4DConnFiredacQuery.Open(const ASQL: string): IC4DConnQuery;
+begin
+ Result := Self;
+ FQuery.Close;
+ FQuery.SQL.Clear;
+ FQuery.SQL.Add(ASQL);
+ FQuery.Open;
+ //FQuery.Open(ASQL);
+end;
+
+procedure TC4DConnFiredacQuery.ProcessaListCond;
+var
+ i: Integer;
+ LKey: string;
+ LValue: Variant;
+ LCond: string;
+begin
+ if FListCond.Count <= 0 then
+ Exit;
+
+ LCond := '';
+ for i := 0 to Pred(FListCond.Count)do
+ LCond := LCond + FListCond.Strings[i] + sLineBreak;
+
+ LCond := TC4DConnUtils.SQLConfBusca(LCond);
+ FQuery.SQL.Add(LCond);
+
+ for LKey in FListCondParam.Keys do
+ begin
+ if FListCondParam.TryGetValue(LKey, LValue) then
+ Self.AddParam(LKey, LValue);
+ end;
+end;
+
+procedure TC4DConnFiredacQuery.ProcessaListGroup;
+var
+ i: Integer;
+ LGroup: string;
+begin
+ if FListGroup.Count <= 0 then
+ Exit;
+
+ LGroup := '';
+ for i := 0 to Pred(FListGroup.Count)do
+ LGroup := LGroup + FListGroup.Strings[i].Trim + ', ';
+
+ if pos(LGroup, 'group by') <= 0 then
+ LGroup := 'group by ' + LGroup;
+
+ LGroup := LGroup.Trim;
+ System.Delete(LGroup, LGroup.Length, 1);
+ FQuery.SQL.Add(LGroup);
+end;
+
+procedure TC4DConnFiredacQuery.ProcessaListOrder;
+var
+ i: Integer;
+ LOrdem: string;
+begin
+ if FListOrder.Count <= 0 then
+ Exit;
+
+ LOrdem := '';
+ for i := 0 to Pred(FListOrder.Count)do
+ LOrdem := LOrdem + FListOrder.Strings[i].Trim + ', ';
+
+ if pos(LOrdem, 'order by') <= 0 then
+ LOrdem := 'order by ' + LOrdem;
+
+ LOrdem := LOrdem.Trim;
+ System.Delete(LOrdem, LOrdem.Length, 1);
+ FQuery.SQL.Add(LOrdem);
+end;
+
+procedure TC4DConnFiredacQuery.ProcessListLimit;
+var
+ i: Integer;
+begin
+ for i := 0 to Pred(FListLimit.Count)do
+ FQuery.SQL.Add(FListLimit.Strings[i]);
+end;
+
+function TC4DConnFiredacQuery.DataSet: TDataSet;
+begin
+ Result := FQuery;
+end;
+
+function TC4DConnFiredacQuery.DataSource(Value: TDataSource): IC4DConnQuery;
+begin
+ Result := Self;
+ Value.DataSet := FQuery;
+end;
+
+function TC4DConnFiredacQuery.DataSourceMasterDetail(Value: TDataSource): IC4DConnQuery;
+begin
+ Result := Self;
+ FQuery.MasterSource := Value;
+end;
+
+function TC4DConnFiredacQuery.Append: IC4DConnQuery;
+begin
+ Result := Self;
+ FQuery.Append;
+end;
+
+function TC4DConnFiredacQuery.Edit: IC4DConnQuery;
+begin
+ Result := Self;
+ FQuery.Edit;
+end;
+
+function TC4DConnFiredacQuery.Post: IC4DConnQuery;
+begin
+ Result := Self;
+ FQuery.Post;
+end;
+
+function TC4DConnFiredacQuery.Delete: IC4DConnQuery;
+begin
+ Result := Self;
+ FQuery.Delete;
+end;
+
+function TC4DConnFiredacQuery.Eof: Boolean;
+begin
+ Result := FQuery.Eof;
+end;
+
+function TC4DConnFiredacQuery.Bof: Boolean;
+begin
+ Result := FQuery.Bof;
+end;
+
+function TC4DConnFiredacQuery.Prior: IC4DConnQuery;
+begin
+ Result := Self;
+ FQuery.Prior;
+end;
+
+function TC4DConnFiredacQuery.Next: IC4DConnQuery;
+begin
+ Result := Self;
+ FQuery.Next;
+end;
+
+function TC4DConnFiredacQuery.First: IC4DConnQuery;
+begin
+ Result := Self;
+ FQuery.First;
+end;
+
+function TC4DConnFiredacQuery.Last: IC4DConnQuery;
+begin
+ Result := Self;
+ FQuery.Last;
+end;
+
+function TC4DConnFiredacQuery.IsEmpty: Boolean;
+begin
+ Result := FQuery.IsEmpty;
+end;
+
+function TC4DConnFiredacQuery.RowsAffected: Integer;
+begin
+ Result := FQuery.RowsAffected;
+end;
+
+function TC4DConnFiredacQuery.SQL: TStrings;
+begin
+ Result := FQuery.SQL;
+end;
+
+function TC4DConnFiredacQuery.FieldByName(Value: string): TField;
+begin
+ Result := FQuery.FieldByName(Value);
+end;
+
+function TC4DConnFiredacQuery.RecNo: Integer;
+begin
+ Result := FQuery.RecNo;
+end;
+
+function TC4DConnFiredacQuery.RecordCount: Integer;
+begin
+ Result := FQuery.RecordCount;
+end;
+
+function TC4DConnFiredacQuery.RecordCountStr(ANumZerosLeft: Integer = 6): string;
+begin
+ Result := Format('%'+ ANumZerosLeft.ToString +'.'+ ANumZerosLeft.ToString +'d',[FQuery.RecordCount]);
+end;
+
+function TC4DConnFiredacQuery.IndexFieldNames: string;
+begin
+ Result := FQuery.IndexFieldNames;
+end;
+
+function TC4DConnFiredacQuery.IndexFieldNames(Value: string): IC4DConnQuery;
+begin
+ Result := Self;
+ FQuery.IndexFieldNames := Value;
+end;
+
+//AName = PARA MYSQL E FIREDAC NOME DO CAMPO
+function TC4DConnFiredacQuery.GetLastAutoGenValue(const AName: string): Variant;
+begin
+ try
+ Result := FQuery.Connection.GetLastAutoGenValue(AName);
+ except
+ on E: Exception do
+ raise Exception.Create('Unable to retrieve the last code/id inserted into the database: ' + E.Message);
+ end;
+end;
+
+end.
diff --git a/Src/Conn/C4D.Conn.Firedac.pas b/Src/Conn/C4D.Conn.Firedac.pas
new file mode 100644
index 0000000..c6ccf1a
--- /dev/null
+++ b/Src/Conn/C4D.Conn.Firedac.pas
@@ -0,0 +1,203 @@
+unit C4D.Conn.Firedac;
+
+interface
+
+uses
+ {$IFNDEF CONSOLE}
+ Firedac.VCLUI.Wait,
+ {$ENDIF}
+ System.Classes,
+ System.SysUtils,
+ System.Generics.Collections,
+ Data.DB,
+ Firedac.Stan.Intf,
+ Firedac.Stan.Option,
+ Firedac.Stan.Error,
+ Firedac.UI.Intf,
+ Firedac.Phys.Intf,
+ Firedac.Stan.Def,
+ Firedac.Stan.Pool,
+ Firedac.Stan.Async,
+ Firedac.Phys,
+ Firedac.Comp.Client,
+ Firedac.DApt,
+ Firedac.Comp.UI,
+ //FIREBIRD
+ FireDAC.Phys.IBBase,
+ FireDAC.Phys.FB,
+ //MySQL
+ Firedac.Phys.MySQLDef,
+ Firedac.Phys.MySQL,
+ C4D.Conn.Interfaces,
+ C4D.Conn.Configs,
+ DelphiAIDev.Types,
+ DelphiAIDev.Utils;
+
+type
+ TC4DConnFiredac = class(TInterfacedObject, IC4DConnection)
+ private
+ [weak]
+ FC4DConnConfigs: TC4DConnConfigs;
+ FConnection: TFDConnection;
+ FMySQLDriverLink: TFDPhysMySQLDriverLink;
+ FFBDriverLink: TFDPhysFBDriverLink;
+ function TestFieldsComponentConnection: IC4DConnection;
+ procedure ConfigDrivers;
+ protected
+ function Component: TComponent;
+ function Open: IC4DConnection;
+ function Close: IC4DConnection;
+ function StartTransaction: IC4DConnection;
+ function Commit: IC4DConnection;
+ function Rollback: IC4DConnection;
+ function TestConnection: Boolean;
+ function LoadConnectionConfig: IC4DConnection;
+ public
+ class function New(AC4DConnConfigs: TC4DConnConfigs): IC4DConnection;
+ constructor Create(AC4DConnConfigs: TC4DConnConfigs);
+ destructor Destroy; override;
+ end;
+
+implementation
+
+class function TC4DConnFiredac.New(AC4DConnConfigs: TC4DConnConfigs): IC4DConnection;
+begin
+ Result := Self.Create(AC4DConnConfigs);
+end;
+
+constructor TC4DConnFiredac.Create(AC4DConnConfigs: TC4DConnConfigs);
+begin
+ FC4DConnConfigs := AC4DConnConfigs;
+ FConnection := TFDConnection.Create(nil);
+ FConnection.LoginPrompt := False;
+
+ FMySQLDriverLink := TFDPhysMySQLDriverLink.Create(nil);
+ FFBDriverLink := TFDPhysFBDriverLink.Create(nil);
+
+ Self.LoadConnectionConfig;
+end;
+
+destructor TC4DConnFiredac.Destroy;
+begin
+ FFBDriverLink.Free;
+ FMySQLDriverLink.Free;
+
+ FConnection.Close;
+ FreeAndNil(FConnection);
+
+ inherited;
+end;
+
+function TC4DConnFiredac.LoadConnectionConfig: IC4DConnection;
+begin
+ Result := Self;
+ FConnection.Close;
+ FConnection.Params.Clear;
+ FConnection.Params.DriverID := FC4DConnConfigs.DriverID.ToStringID; //'MySQL';
+ FConnection.Params.Database := FC4DConnConfigs.Database;
+ FConnection.Params.UserName := FC4DConnConfigs.UserName;
+ FConnection.Params.Password := FC4DConnConfigs.Password;
+ FConnection.Params.Add('Server=' + FC4DConnConfigs.Host);
+ if FC4DConnConfigs.Port > 0 then
+ FConnection.Params.Add('Port=' + FC4DConnConfigs.Port.ToString);
+
+// FConnection.TXOptions.AutoStart := True;
+// FConnection.TXOptions.AutoStop := True;
+// FConnection.TXOptions.AutoCommit := True;
+// FConnection.TxOptions.StopOptions := [xoIfAutoStarted, xoFinishRetaining];
+// FConnection.UpdateOptions.AutoCommitUpdates := True;
+// FConnection.UpdateOptions.RefreshMode := rmAll;
+
+ Self.ConfigDrivers;
+end;
+
+procedure TC4DConnFiredac.ConfigDrivers;
+begin
+ FMySQLDriverLink.VendorLib := '';
+ FFBDriverLink.VendorLib := '';
+
+ case FC4DConnConfigs.DriverID of
+ TC4DDriverID.MySQL:
+ FMySQLDriverLink.VendorLib := FC4DConnConfigs.VendorLib;
+ TC4DDriverID.Firebird:
+ FFBDriverLink.VendorLib := FC4DConnConfigs.VendorLib;
+ end;
+end;
+
+function TC4DConnFiredac.Component: TComponent;
+begin
+ Result := FConnection;
+end;
+
+function TC4DConnFiredac.Open: IC4DConnection;
+begin
+ Result := Self;
+ Self.TestFieldsComponentConnection;
+ FConnection.Open;
+end;
+
+function TC4DConnFiredac.Close: IC4DConnection;
+begin
+ Result := Self;
+ FConnection.Close;
+end;
+
+function TC4DConnFiredac.StartTransaction: IC4DConnection;
+begin
+ FConnection.StartTransaction;
+end;
+
+function TC4DConnFiredac.Commit: IC4DConnection;
+begin
+ FConnection.Commit;
+end;
+
+function TC4DConnFiredac.Rollback: IC4DConnection;
+begin
+ FConnection.Rollback;
+end;
+
+function TC4DConnFiredac.TestConnection: Boolean;
+var
+ LConnectedOld: Boolean;
+begin
+ Self.TestFieldsComponentConnection;
+ try
+ Self.LoadConnectionConfig;
+ LConnectedOld := FConnection.Connected;
+ FConnection.Close;
+ FConnection.Open;
+ Result := FConnection.Connected;
+
+ if FConnection.Connected <> LConnectedOld then
+ FConnection.Connected := LConnectedOld;
+ except
+ on E: exception do
+ raise exception.Create('Unsuccessful Connection! ' + sLineBreak + E.Message);
+ end;
+end;
+
+function TC4DConnFiredac.TestFieldsComponentConnection: IC4DConnection;
+var
+ LEmptyFields: string;
+begin
+ Result := Self;
+
+ LEmptyFields := '';
+ if FC4DConnConfigs.Host.Trim.IsEmpty then
+ LEmptyFields := LEmptyFields + 'Host. ';
+
+ if FC4DConnConfigs.UserName.Trim.IsEmpty then
+ LEmptyFields := LEmptyFields + 'UserName. ';
+
+ if FC4DConnConfigs.Password.Trim.IsEmpty then
+ LEmptyFields := LEmptyFields + 'Password. ';
+
+ if FC4DConnConfigs.Database.Trim.IsEmpty then
+ LEmptyFields := LEmptyFields + 'Database.';
+
+ if not LEmptyFields.Trim.IsEmpty then
+ raise exception.Create('To connect to the database, the following data must be filled in: ' + LEmptyFields);
+end;
+
+end.
diff --git a/Src/Conn/C4D.Conn.Interfaces.pas b/Src/Conn/C4D.Conn.Interfaces.pas
new file mode 100644
index 0000000..bc5d018
--- /dev/null
+++ b/Src/Conn/C4D.Conn.Interfaces.pas
@@ -0,0 +1,82 @@
+unit C4D.Conn.Interfaces;
+
+interface
+
+uses
+ Data.DB,
+ System.Classes,
+ C4D.Conn.Configs;
+
+type
+ IC4DConnection = interface
+ ['{5B72EBFB-CE76-42F6-B716-226E5149F572}']
+ function Component: TComponent;
+ function Open: IC4DConnection;
+ function Close: IC4DConnection;
+ function StartTransaction: IC4DConnection;
+ function Commit: IC4DConnection;
+ function Rollback: IC4DConnection;
+
+ function TestConnection: Boolean;
+ function LoadConnectionConfig: IC4DConnection;
+ end;
+
+ IC4DConnQuery = interface
+ ['{8C098AA7-288F-4458-AFDB-E44CC95E5441}']
+ function Close: IC4DConnQuery;
+ function Clear: IC4DConnQuery;
+ function CloseClear: IC4DConnQuery;
+ function Add(Value: string): IC4DConnQuery;
+ function AddParam(Param: string; Value: Variant): IC4DConnQuery;
+ function AddCond(ACond: string): IC4DConnQuery;
+ function AddCondParam(Param: string; Value: Variant): IC4DConnQuery;
+ function AddGroup(ACond: string): IC4DConnQuery;
+ function AddOrder(ACond: string): IC4DConnQuery;
+ function AddLimit(ACond: string): IC4DConnQuery;
+ function Text(Value: string): IC4DConnQuery;
+ function SQL: TStrings;
+ function ExecSQL: IC4DConnQuery; overload;
+ function ExecSQL(const ASQL: string): IC4DConnQuery; overload;
+ function Open: IC4DConnQuery; overload;
+ function Open(const ASQL: string): IC4DConnQuery; overload;
+
+ function DataSet: TDataSet;
+ function DataSource(Valeu: TDataSource): IC4DConnQuery;
+ function DataSourceMasterDetail(Value: TDataSource): IC4DConnQuery;
+
+ function Append: IC4DConnQuery;
+ function Edit: IC4DConnQuery;
+ function Post: IC4DConnQuery;
+ function Delete: IC4DConnQuery;
+
+ function Eof: Boolean;
+ function Bof: Boolean;
+ function Prior: IC4DConnQuery;
+ function Next: IC4DConnQuery;
+ function First: IC4DConnQuery;
+ function Last: IC4DConnQuery;
+ function IsEmpty: Boolean;
+ function RowsAffected: Integer;
+ function FieldByName(Value: string): TField;
+ function RecNo: Integer;
+ function RecordCount: Integer;
+ function RecordCountStr(ANumZerosLeft: Integer = 6): string;
+ function IndexFieldNames: string; overload;
+ function IndexFieldNames(Value: string): IC4DConnQuery; overload;
+
+ //AName = PARA MYSQL E ZEOS NOME DA TABELA
+ //AName = PARA MYSQL E FIREDAC NOME DO CAMPO
+ function GetLastAutoGenValue(const AName: string): Variant;
+ end;
+
+ IC4DConn = interface
+ ['{71342615-E414-4D66-9280-67218D5FB27A}']
+ function Configs: TC4DConnConfigs;
+ function Connection: IC4DConnection;
+ function Query: IC4DConnQuery; overload;
+ function Query(const ANameQuery: string): IC4DConnQuery; overload;
+ end;
+
+implementation
+
+end.
diff --git a/Src/Conn/C4D.Conn.Types.pas b/Src/Conn/C4D.Conn.Types.pas
new file mode 100644
index 0000000..13f1d9d
--- /dev/null
+++ b/Src/Conn/C4D.Conn.Types.pas
@@ -0,0 +1,12 @@
+unit C4D.Conn.Types;
+
+interface
+
+type
+ {$SCOPEDENUMS ON}
+ TComponentConnection = (Empty, FireDac {$IFDEF C4D_ZEOS}, Zeos {$ENDIF});
+ {$SCOPEDENUMS OFF}
+
+implementation
+
+end.
diff --git a/Src/Conn/C4D.Conn.Utils.pas b/Src/Conn/C4D.Conn.Utils.pas
new file mode 100644
index 0000000..32dab91
--- /dev/null
+++ b/Src/Conn/C4D.Conn.Utils.pas
@@ -0,0 +1,57 @@
+unit C4D.Conn.Utils;
+
+interface
+
+uses
+ System.SysUtils,
+ System.StrUtils;
+
+type
+ TC4DConnUtils = class
+ public
+ class function SQLConfBusca(const ASql: string): string;
+ class function SQLTratar(const ASql: string): string;
+ end;
+
+implementation
+
+class function TC4DConnUtils.SQLConfBusca(const ASql: string): string;
+begin
+ Result := ASql.Trim;
+
+ if Result.IsEmpty then
+ Exit;
+
+ if copy(Result, 1, 3) = 'and' then
+ begin
+ Delete(Result, 1, 3);
+ Result := 'where '+ Result;
+ end
+ else if copy(Result, 1, 2) = 'or' then
+ begin
+ Delete(Result, 1, 2);
+ Result := 'where '+ Result;
+ end
+ else if (copy(Result, 1, 5) <> 'where')
+ and(copy(Result, 1, 5) <> 'limit')
+ and(copy(Result, 1, 8) <> 'order by')
+ and(copy(Result, 1, 8) <> 'group by')
+ then
+ Result := 'where '+ Result;
+
+ Result := Self.SQLTratar(Result) + ' ';
+end;
+
+class function TC4DConnUtils.SQLTratar(const ASql: string): string;
+begin
+ Result := ASql;
+ Result := StringReplace(Result, ' ALTER ', ' ALTERA ', [rfReplaceAll, rfIgnoreCase]);
+ Result := StringReplace(Result, 'ALTER TABLE', 'ALTERA TABLE', [rfReplaceAll, rfIgnoreCase]);
+
+ Result := StringReplace(Result, ' DROP ', ' DROPE ', [rfReplaceAll, rfIgnoreCase]);
+ Result := StringReplace(Result, 'DROP TABLE', 'DROPE TABLE', [rfReplaceAll, rfIgnoreCase]);
+ Result := StringReplace(Result, 'DROP PROCEDURE', 'DROPE PROCEDURE', [rfReplaceAll, rfIgnoreCase]);
+ Result := StringReplace(Result, 'DROP FUNCTION', 'DROPE FUNCTION', [rfReplaceAll, rfIgnoreCase]);
+end;
+
+end.
diff --git a/Src/Conn/C4D.Conn.Zeos.Query.pas b/Src/Conn/C4D.Conn.Zeos.Query.pas
new file mode 100644
index 0000000..434a5fb
--- /dev/null
+++ b/Src/Conn/C4D.Conn.Zeos.Query.pas
@@ -0,0 +1,427 @@
+unit C4D.Conn.Zeos.Query;
+
+interface
+
+uses
+ System.SysUtils,
+ System.StrUtils,
+ System.Classes,
+ System.Generics.Collections,
+ ZAbstractConnection,
+ ZConnection,
+ Data.DB,
+ ZAbstractRODataset,
+ ZAbstractDataset,
+ ZDataset,
+ C4D.Conn.Interfaces,
+ C4D.Conn.Zeos,
+ C4D.Conn.Utils;
+
+type
+ TC4DConnZeosQuery = class(TInterfacedObject, IC4DConnQuery)
+ private
+ FC4DConnection: IC4DConnection;
+ FQuery: TZQuery;
+ FListCond: TStringList;
+ FListCondParam: TDictionary;
+ FListGroup: TStringList;
+ FListOrder: TStringList;
+ FListLimit: TStringList;
+ procedure ProcessaListCond;
+ procedure ProcessaListGroup;
+ procedure ProcessaListOrder;
+ procedure ProcessaListLimit;
+ protected
+ function Close: IC4DConnQuery;
+ function Clear: IC4DConnQuery;
+ function CloseClear: IC4DConnQuery;
+ function Add(Value: string): IC4DConnQuery;
+ function AddParam(Param: string; Value: Variant): IC4DConnQuery;
+ function AddCond(ACond: string): IC4DConnQuery;
+ function AddCondParam(Param: string; Value: Variant): IC4DConnQuery;
+ function AddGroup(ACond: string): IC4DConnQuery;
+ function AddOrder(ACond: string): IC4DConnQuery;
+ function AddLimit(ACond: string): IC4DConnQuery;
+ function Text(Value: string): IC4DConnQuery;
+ function SQL: TStrings;
+ function ExecSQL: IC4DConnQuery; overload;
+ function ExecSQL(const ASQL: string): IC4DConnQuery; overload;
+ function Open: IC4DConnQuery; overload;
+ function Open(const ASQL: string): IC4DConnQuery; overload;
+
+ function DataSet: TDataSet;
+ function DataSource(Value: TDataSource): IC4DConnQuery;
+ function DataSourceMasterDetail(Value: TDataSource): IC4DConnQuery;
+
+ function Append: IC4DConnQuery;
+ function Edit: IC4DConnQuery;
+ function Post: IC4DConnQuery;
+ function Delete: IC4DConnQuery;
+
+ function Eof: Boolean;
+ function Bof: Boolean;
+ function Prior: IC4DConnQuery;
+ function Next: IC4DConnQuery;
+ function First: IC4DConnQuery;
+ function Last: IC4DConnQuery;
+ function IsEmpty: Boolean;
+ function RowsAffected: Integer;
+ function FieldByName(Value: string): TField;
+ function RecNo: Integer;
+ function RecordCount: Integer;
+ function RecordCountStr(ANumZerosLeft: Integer = 6): string;
+ function GetLastAutoGenValue(const AName: string): Variant;
+ public
+ class function New(AC4DConnection: IC4DConnection; ANameQuery: string): IC4DConnQuery;
+ constructor Create(AC4DConnection: IC4DConnection; ANameQuery: string);
+ destructor Destroy; override;
+ end;
+
+implementation
+
+class function TC4DConnZeosQuery.New(AC4DConnection: IC4DConnection; ANameQuery: string): IC4DConnQuery;
+begin
+ Result := Self.Create(AC4DConnection, ANameQuery);
+end;
+
+constructor TC4DConnZeosQuery.Create(AC4DConnection: IC4DConnection; ANameQuery: string);
+begin
+ FC4DConnection := AC4DConnection;
+
+ FQuery := TZQuery.Create(nil);
+ FQuery.Name := ANameQuery;
+ FQuery.Connection := TZConnection(FC4DConnection.Component);
+
+ FQuery.Close;
+ FQuery.SQL.Clear;
+
+ FListCond := TStringList.Create;
+ FListCondParam := TDictionary.Create;
+ FListGroup := TStringList.Create;
+ FListOrder := TStringList.Create;
+ FListLimit := TStringList.Create;
+end;
+
+destructor TC4DConnZeosQuery.Destroy;
+begin
+ FListLimit.Free;
+ FListOrder.Free;
+ FListGroup.Free;
+ FListCondParam.Free;
+ FListCond.Free;
+ FreeAndNil(FQuery);
+ inherited;
+end;
+
+function TC4DConnZeosQuery.Close: IC4DConnQuery;
+begin
+ Result := Self;
+ FQuery.Close;
+end;
+
+function TC4DConnZeosQuery.Clear: IC4DConnQuery;
+begin
+ Result := Self;
+ FQuery.SQL.Clear;
+ FListCond.Clear;
+ FListCondParam.Clear;
+ FListLimit.Clear;
+ FListGroup.Clear;
+ FListOrder.Clear;
+end;
+
+function TC4DConnZeosQuery.CloseClear: IC4DConnQuery;
+begin
+ Result := Self;
+ Self.Close;
+ Self.Clear;
+end;
+
+function TC4DConnZeosQuery.Add(Value: string): IC4DConnQuery;
+begin
+ Result := Self;
+ FQuery.SQL.Add(Value);
+end;
+
+function TC4DConnZeosQuery.AddParam(Param: string; Value: Variant): IC4DConnQuery;
+begin
+ Result := Self;
+ FQuery.ParamByName(Param).Value := Value;
+end;
+
+function TC4DConnZeosQuery.AddCond(ACond: string): IC4DConnQuery;
+begin
+ Result := Self;
+ FListCond.Add(ACond);
+end;
+
+function TC4DConnZeosQuery.AddCondParam(Param: string; Value: Variant): IC4DConnQuery;
+begin
+ Result := Self;
+ FListCondParam.Add(Param, Value);
+end;
+
+function TC4DConnZeosQuery.AddGroup(ACond: string): IC4DConnQuery;
+begin
+ Result := Self;
+ FListGroup.Add(ACond);
+end;
+
+function TC4DConnZeosQuery.AddOrder(ACond: string): IC4DConnQuery;
+begin
+ Result := Self;
+ FListOrder.Add(ACond);
+end;
+
+function TC4DConnZeosQuery.AddLimit(ACond: string): IC4DConnQuery;
+begin
+ Result := Self;
+ FListLimit.Add(ACond);
+end;
+
+function TC4DConnZeosQuery.Text(Value: string): IC4DConnQuery;
+begin
+ Result := Self;
+ FQuery.SQL.Text := Value;
+end;
+
+function TC4DConnZeosQuery.ExecSQL: IC4DConnQuery;
+begin
+ Result := Self;
+ FQuery.ExecSQL;
+end;
+
+function TC4DConnZeosQuery.ExecSQL(const ASQL: string): IC4DConnQuery;
+begin
+ Result := Self;
+ FQuery.Close;
+ FQuery.SQL.Clear;
+ FQuery.SQL.Add(ASQL);
+ FQuery.ExecSQL;
+end;
+
+function TC4DConnZeosQuery.Open: IC4DConnQuery;
+begin
+ Result := Self;
+ Self.ProcessaListCond;
+ Self.ProcessaListGroup;
+ Self.ProcessaListOrder;
+ Self.ProcessaListLimit;
+ FQuery.Open;
+end;
+
+function TC4DConnZeosQuery.Open(const ASQL: string): IC4DConnQuery;
+begin
+ Result := Self;
+ FQuery.Close;
+ FQuery.SQL.Clear;
+ FQuery.SQL.Add(ASQL);
+ FQuery.Open;
+end;
+
+procedure TC4DConnZeosQuery.ProcessaListCond;
+var
+ i: Integer;
+ LKey: string;
+ LValue: Variant;
+ LCond: string;
+begin
+ if(FListCond.Count <= 0)then
+ Exit;
+
+ LCond := '';
+ for i := 0 to Pred(FListCond.Count)do
+ LCond := LCond + FListCond.Strings[i] + sLineBreak;
+
+ LCond := TC4DConnUtils.SQLConfBusca(LCond);
+ FQuery.SQL.Add(LCond);
+
+ for LKey in FListCondParam.Keys do
+ if FListCondParam.TryGetValue(LKey, LValue) then
+ Self.AddParam(LKey, LValue);
+end;
+
+procedure TC4DConnZeosQuery.ProcessaListGroup;
+var
+ i: Integer;
+ LGroup: string;
+begin
+ if FListGroup.Count <= 0 then
+ Exit;
+
+ LGroup := '';
+ for i := 0 to Pred(FListGroup.Count)do
+ LGroup := LGroup + FListGroup.Strings[i].Trim + ', ';
+
+ if pos('group by', LGroup) <= 0 then
+ LGroup := 'group by ' + LGroup;
+
+ LGroup := LGroup.Trim;
+ System.Delete(LGroup, LGroup.Length, 1);
+ FQuery.SQL.Add(LGroup);
+end;
+
+procedure TC4DConnZeosQuery.ProcessaListOrder;
+var
+ i: Integer;
+ LOrdem: string;
+begin
+ if FListOrder.Count <= 0 then
+ Exit;
+
+ LOrdem := '';
+ for i := 0 to Pred(FListOrder.Count)do
+ LOrdem := LOrdem + FListOrder.Strings[i].Trim + ', ';
+
+ if pos('order by', LOrdem) <= 0 then
+ LOrdem := 'order by ' + LOrdem;
+
+ LOrdem := LOrdem.Trim;
+ System.Delete(LOrdem, LOrdem.Length, 1);
+ FQuery.SQL.Add(LOrdem);
+end;
+
+procedure TC4DConnZeosQuery.ProcessaListLimit;
+var
+ i: Integer;
+begin
+ for i := 0 to Pred(FListLimit.Count)do
+ FQuery.SQL.Add(FListLimit.Strings[i]);
+end;
+
+function TC4DConnZeosQuery.DataSet: TDataSet;
+begin
+ Result := FQuery;
+end;
+
+function TC4DConnZeosQuery.DataSource(Value: TDataSource): IC4DConnQuery;
+begin
+ Result := Self;
+ Value.DataSet := FQuery;
+end;
+
+function TC4DConnZeosQuery.DataSourceMasterDetail(Value: TDataSource): IC4DConnQuery;
+begin
+ Result := Self;
+ FQuery.DataSource := Value;
+end;
+
+function TC4DConnZeosQuery.Append: IC4DConnQuery;
+begin
+ Result := Self;
+ FQuery.Append;
+end;
+
+function TC4DConnZeosQuery.Edit: IC4DConnQuery;
+begin
+ Result := Self;
+ FQuery.Edit;
+end;
+
+function TC4DConnZeosQuery.Post: IC4DConnQuery;
+begin
+ Result := Self;
+ FQuery.Post;
+end;
+
+function TC4DConnZeosQuery.Delete: IC4DConnQuery;
+begin
+ Result := Self;
+ FQuery.Delete;
+end;
+
+function TC4DConnZeosQuery.Eof: Boolean;
+begin
+ Result := FQuery.Eof;
+end;
+
+function TC4DConnZeosQuery.Bof: Boolean;
+begin
+ Result := FQuery.Bof;
+end;
+
+function TC4DConnZeosQuery.Prior: IC4DConnQuery;
+begin
+ Result := Self;
+ FQuery.Prior;
+end;
+
+function TC4DConnZeosQuery.Next: IC4DConnQuery;
+begin
+ Result := Self;
+ FQuery.Next;
+end;
+
+function TC4DConnZeosQuery.First: IC4DConnQuery;
+begin
+ Result := Self;
+ FQuery.First;
+end;
+
+function TC4DConnZeosQuery.Last: IC4DConnQuery;
+begin
+ Result := Self;
+ FQuery.Last;
+end;
+
+function TC4DConnZeosQuery.IsEmpty: Boolean;
+begin
+ Result := FQuery.IsEmpty;
+end;
+
+function TC4DConnZeosQuery.RowsAffected: Integer;
+begin
+ Result := FQuery.RowsAffected
+end;
+
+function TC4DConnZeosQuery.SQL: TStrings;
+begin
+ Result := FQuery.SQL;
+end;
+
+function TC4DConnZeosQuery.FieldByName(Value: string): TField;
+begin
+ Result := FQuery.FieldByName(Value);
+end;
+
+function TC4DConnZeosQuery.RecNo: Integer;
+begin
+ Result := FQuery.RecNo;
+end;
+
+function TC4DConnZeosQuery.RecordCount: Integer;
+begin
+ Result := FQuery.RecordCount;
+end;
+
+function TC4DConnZeosQuery.RecordCountStr(ANumZerosLeft: Integer = 6): string;
+begin
+ Result := FQuery.RecordCount.ToString;
+end;
+
+//AName = PARA MYSQL E ZEOS NOME DA TABELA
+function TC4DConnZeosQuery.GetLastAutoGenValue(const AName: string): Variant;
+var
+ LQuery: TZQuery;
+begin
+ LQuery := TZQuery.Create(nil);
+ try
+ try
+ LQuery.Connection := FQuery.Connection;
+ LQuery.Close;
+ LQuery.SQL.Clear;
+ LQuery.SQL.Add('Select Last_Insert_ID() as Last_Insert_ID from ' + AName);
+ LQuery.Open;
+
+ Result := LQuery.FieldByName('Last_Insert_ID').AsInteger;
+ LQuery.Close;
+ except
+ on E: Exception do
+ raise Exception.Create('Unable to retrieve the last code/id inserted into the database: ' + E.Message);
+ end;
+ finally
+ FreeAndNil(LQuery);
+ end;
+end;
+
+end.
diff --git a/Src/Conn/C4D.Conn.Zeos.pas b/Src/Conn/C4D.Conn.Zeos.pas
new file mode 100644
index 0000000..eb411fd
--- /dev/null
+++ b/Src/Conn/C4D.Conn.Zeos.pas
@@ -0,0 +1,160 @@
+unit C4D.Conn.Zeos;
+
+interface
+
+uses
+ System.Classes,
+ System.SysUtils,
+ System.Generics.Collections,
+ ZAbstractConnection,
+ ZConnection,
+ C4D.Conn.Interfaces,
+ C4D.Conn.Configs;
+
+type
+ TC4DConnZeos = class(TInterfacedObject, IC4DConnection)
+ private
+ [weak]
+ FC4DConnConfigs: TC4DConnConfigs;
+ FConnection: TZConnection;
+ function TestFieldsComponentConnection: IC4DConnection;
+ protected
+ function Component: TComponent;
+ function Open: IC4DConnection;
+ function Close: IC4DConnection;
+ function StartTransaction: IC4DConnection;
+ function Commit: IC4DConnection;
+ function Rollback: IC4DConnection;
+ function TestConnection: Boolean;
+ function TestConnectionOnly: Boolean;
+ function LoadConnectionConfig: IC4DConnection;
+ public
+ class function New(AC4DConnConfigs: TC4DConnConfigs): IC4DConnection;
+ constructor Create(AC4DConnConfigs: TC4DConnConfigs);
+ destructor Destroy; override;
+ end;
+
+implementation
+
+class function TC4DConnZeos.New(AC4DConnConfigs: TC4DConnConfigs): IC4DConnection;
+begin
+ Result := Self.Create(AC4DConnConfigs);
+end;
+
+constructor TC4DConnZeos.Create(AC4DConnConfigs: TC4DConnConfigs);
+begin
+ FC4DConnConfigs := AC4DConnConfigs;
+ FConnection := TZConnection.Create(nil);
+ Self.LoadConnectionConfig;
+end;
+
+destructor TC4DConnZeos.Destroy;
+begin
+ FConnection.Connected := False;
+ FreeAndNil(FConnection);
+
+ inherited;
+end;
+
+function TC4DConnZeos.LoadConnectionConfig: IC4DConnection;
+begin
+ Result := Self;
+ FConnection.Connected := False;
+ FConnection.Protocol := 'mysql';
+ FConnection.Database := FC4DConnConfigs.Database;
+ FConnection.User := FC4DConnConfigs.UserName;
+ FConnection.Password := FC4DConnConfigs.Password;
+ FConnection.HostName := FC4DConnConfigs.Host;
+ FConnection.Port := FC4DConnConfigs.Port;
+ //FConnection.TransactIsolationLevel := tiReadCommitted;
+end;
+
+function TC4DConnZeos.Component: TComponent;
+begin
+ Result := FConnection;
+end;
+
+function TC4DConnZeos.Open: IC4DConnection;
+begin
+ Result := Self;
+ Self.TestFieldsComponentConnection;
+ FConnection.Connected := True;
+end;
+
+function TC4DConnZeos.Close: IC4DConnection;
+begin
+ Result := Self;
+ FConnection.Connected := False;
+end;
+
+function TC4DConnZeos.StartTransaction: IC4DConnection;
+begin
+ FConnection.StartTransaction;
+end;
+
+function TC4DConnZeos.Commit: IC4DConnection;
+begin
+ FConnection.Commit;
+end;
+
+function TC4DConnZeos.Rollback: IC4DConnection;
+begin
+ FConnection.Rollback;
+end;
+
+function TC4DConnZeos.TestConnection: Boolean;
+var
+ LConnectedOld: Boolean;
+begin
+ Self.TestFieldsComponentConnection;
+ try
+ LConnectedOld := FConnection.Connected;
+ FConnection.Connected := True;
+ Result := FConnection.Connected;
+ if(FConnection.Connected <> LConnectedOld)then
+ FConnection.Connected := LConnectedOld;
+ except
+ on E: exception do
+ raise exception.Create('Conexo no pode ser realizada: ' + E.Message);
+ end;
+end;
+
+function TC4DConnZeos.TestConnectionOnly: Boolean;
+var
+ LConnectedOld: Boolean;
+begin
+ Result := False;
+ try
+ LConnectedOld := FConnection.Connected;
+ FConnection.Connected := True;
+ Result := FConnection.Connected;
+ if(FConnection.Connected <> LConnectedOld)then
+ FConnection.Connected := LConnectedOld;
+ except
+ end;
+end;
+
+function TC4DConnZeos.TestFieldsComponentConnection: IC4DConnection;
+var
+ LEmptyFields: string;
+begin
+ Result := Self;
+ LEmptyFields := '';
+
+ if FConnection.HostName.Trim.IsEmpty then
+ LEmptyFields := LEmptyFields + 'HostName. ';
+
+ if FConnection.User.Trim.IsEmpty then
+ LEmptyFields := LEmptyFields + 'User. ';
+
+ if FConnection.Password.Trim.IsEmpty then
+ LEmptyFields := LEmptyFields + 'Password. ';
+
+ if FConnection.Database.Trim.IsEmpty then
+ LEmptyFields := LEmptyFields + 'Database.';
+
+ if not LEmptyFields.IsEmpty then
+ raise exception.Create('To connect to the database, the following data must be filled in: ' + LEmptyFields);
+end;
+
+end.
diff --git a/Src/Conn/C4D.Conn.pas b/Src/Conn/C4D.Conn.pas
new file mode 100644
index 0000000..af36471
--- /dev/null
+++ b/Src/Conn/C4D.Conn.pas
@@ -0,0 +1,118 @@
+unit C4D.Conn;
+
+interface
+
+uses
+ System.SysUtils,
+ System.Classes,
+ C4D.Conn.Interfaces,
+ C4D.Conn.Types,
+ C4D.Conn.Configs,
+ {$IFDEF C4D_ZEOS}
+ C4D.Conn.Zeos,
+ C4D.Conn.Zeos.Query,
+ {$ENDIF}
+ C4D.Conn.Firedac,
+ C4D.Conn.Firedac.Query;
+
+type
+ IC4DConn = C4D.Conn.Interfaces.IC4DConn;
+ IC4DConnQuery = C4D.Conn.Interfaces.IC4DConnQuery;
+
+ TC4DConn = class(TInterfacedObject, IC4DConn)
+ private
+ FC4DConnConfigs: TC4DConnConfigs;
+ FC4DConnInstance: IC4DConnection;
+ FCountNameQuery: Integer;
+ function CountNameQuery: Integer;
+ function QueryInternal(const ANameQuery: string): IC4DConnQuery;
+ protected
+ function Configs: TC4DConnConfigs;
+ function Connection: IC4DConnection;
+ function Query: IC4DConnQuery; overload;
+ function Query(const ANameQuery: string): IC4DConnQuery; overload;
+ public
+ class function New: IC4DConn;
+ constructor Create;
+ destructor Destroy; override;
+ end;
+
+//function C4DConn: IC4DConn;
+
+//var
+// Instance: IC4DConn;
+
+implementation
+
+uses
+ DelphiAIDev.Utils;
+
+class function TC4DConn.New: IC4DConn;
+begin
+ Result := Self.Create;
+end;
+
+constructor TC4DConn.Create;
+begin
+ FCountNameQuery := 0;
+ FC4DConnConfigs := TC4DConnConfigs.Create;
+end;
+
+destructor TC4DConn.Destroy;
+begin
+ FC4DConnConfigs.Free;
+ inherited;
+end;
+
+//function C4DConn: IC4DConn;
+//begin
+// if not Assigned(Instance) then
+// Instance := TC4DConn.New;
+//
+// Result := Instance;
+//end;
+
+function TC4DConn.Configs: TC4DConnConfigs;
+begin
+ Result := FC4DConnConfigs;
+end;
+
+function TC4DConn.CountNameQuery: Integer;
+begin
+ Inc(FCountNameQuery);
+ Result := FCountNameQuery;
+end;
+
+function TC4DConn.Connection: IC4DConnection;
+begin
+ {$IFDEF C4D_ZEOS}
+ if not Assigned(FC4DConnInstance) then
+ FC4DConnInstance := TC4DConnZeos.New(FC4DConnConfigs);
+ {$ELSE}
+ if not Assigned(FC4DConnInstance) then
+ FC4DConnInstance := TC4DConnFiredac.New(FC4DConnConfigs);
+ {$ENDIF}
+
+ Result := FC4DConnInstance;
+end;
+
+function TC4DConn.Query: IC4DConnQuery;
+begin
+ Result := Self.QueryInternal('Query' + Self.CountNameQuery.ToString);
+end;
+
+function TC4DConn.Query(const ANameQuery: string): IC4DConnQuery;
+begin
+ Result := Self.QueryInternal(ANameQuery);
+end;
+
+function TC4DConn.QueryInternal(const ANameQuery: string): IC4DConnQuery;
+begin
+ {$IFDEF C4D_ZEOS}
+ Result := TC4DConnZeosQuery.New(Self.Connection, ANameQuery);
+ {$ELSE}
+ Result := TC4DConnFiredacQuery.New(Self.Connection, ANameQuery);
+ {$ENDIF}
+end;
+
+end.
diff --git a/Src/Consts/DelphiAIDev.Consts.pas b/Src/Consts/DelphiAIDev.Consts.pas
index ea69fe7..c052748 100644
--- a/Src/Consts/DelphiAIDev.Consts.pas
+++ b/Src/Consts/DelphiAIDev.Consts.pas
@@ -5,40 +5,60 @@ interface
type
TConsts = class
public const
- SEMANTIC_VERSION = '1.8.0';
+ SEMANTIC_VERSION = '2.4.0';
SEMANTIC_VERSION_LB = 'Version: ' + SEMANTIC_VERSION;
WIN_CONTROL_FOCU_NIL = nil;
DELPHI_AI_DEVELOPER_DPROJ = 'DelphiAIDeveloper.dproj';
DELPHI_AI_DEVELOPER_BPL = 'DelphiAIDeveloper.bpl';
C4D_PROJECT_GROUP1 = 'ProjectGroup1.groupproj';
NAME_FOLDER_TEMP = 'Temp';
+ NAME_FOLDER_MetaInfo = 'MetaInfo';
GITHUB_Code4Delphi = 'https://github.com/Code4Delphi';
GITHUB_PROJECT = 'https://github.com/Code4Delphi/Delphi-AI-Developer';
+ APPLICATION_JSON = 'application/json';
+ SHORTCUT_CHAT_DEFAULT = 'Ctrl+Shift+Alt+A';
+ CODE_COMPLETION_SUGGESTION_COLOR = $777777;
+ CODE_COMPLETION_SHORTCUT_INVOKE = 'Alt+Enter';
MARK_BEGIN_DELPHI = '```delphi';
MARK_BEGIN_PASCAL = '```objectpascal';
MARK_BEGIN_PASCAL2 = '``pascal';
+ MARK_BEGIN_SQL = '```sql';
+ MARK_BEGIN_SQL2 = '``sql';
MARK_END = '```';
+ PREFIX_NAME_SEPARATOR = 'DelphiAIDevSeparator';
+ TAG_CODE_COMPLETION = '//Suggestion_Code_Delphi';
//SETTINGS
KEY_SETTINGS_IN_WINDOWS_REGISTRY = '\SOFTWARE\DelphiAIDeveloper';
BASE_URL_GEMINI_DEFAULT = 'https://generativelanguage.googleapis.com/';
MODEL_GEMINI_DEFAULT = 'v1/models/gemini-1.5-flash:generateContent';
BASE_URL_OPEN_AI = 'https://api.openai.com/v1/chat/completions/';
+ MODEL_OPEN_AI_DEFAULT = 'gpt-4o-2024-08-06';
BASE_URL_GROQ = 'https://api.groq.com/openai/v1/chat/completions';
+ MODEL_GROQ_DEFAULT = 'llama3-70b-8192'; //'llama3-8b-8192';;
+
+ BASE_URL_Mistral = 'https://api.mistral.ai/v1/chat/completions';
+ MODEL_Mistral_DEFAULT = 'mistral-small-latest';
+
+ BASE_URL_OLLAMA = 'http://localhost:11434/api/chat';
+ MODEL_OLLAMA_DEFAULT = ''; //'tinyllama' 'mistral';
//NAMES FILES .INI
FILE_INI_GENERAL_SETTINGS = 'delphi-ai-developer.ini';
//NAMES FILES .rtf
FILE_RTF_CHAT = 'chat.rtf';
+ FILE_RTF_CHAT_DB = 'chat_db.rtf';
- //NAMES FILE Database
+ //NAMES FILE JSON
FILE_JSON_DEFAULTS_QUESTIONS = 'delphi_ai_developer_questions.json';
+ FILE_JSON_DATABASES = 'delphi_ai_developer_databases.json';
+ FILE_JSON_PROJECTS = 'delphi_ai_developer_projects.json';
//ABOUT AND SPLASH
ABOUT_TITLE = 'Delphi AI Developer';
- ABOUT_COPY_RIGHT = 'Copyright 2024 Code4Delphi Team.';
+ ABOUT_COPY_RIGHT = 'Copyright 2025 Code4Delphi Team.';
ABOUT_DESCRIPTION = 'Plugin designed to be used in the Delphi IDE.';
PLUGIN_LICENSE = 'MIT license';
IS_UNREGISTERED = False;
@@ -50,6 +70,13 @@ TConsts = class
ITEM_MENU_C4DDelphiAIDev_NAME = 'C4DDelphiAIDevItemMenu';
ITEM_MENU_C4DDelphiAIDev_CAPTION = 'AI Developer';
+ //CODE4D-WIZARD INFORMATION
+ //ITEM_MENU_Code4D_CAPTION = 'Code4D';
+
+ //CAPTIONS ITENS POPUPMENU PROJ
+ ITEM_POPUP_MENU_PROJ_CAPTION = 'AI Developer';
+ ITEM_POPUP_MENU_PROJ_EditInformation_CAPTION = 'Edit Information';
+
//MAIN MENU IDE NAME AND CAPTIONS
MENU_IDE_CHAT_NAME = 'DelphiAIDevChat1';
MENU_IDE_CHAT_CAPTION = 'Chat';
@@ -57,6 +84,11 @@ TConsts = class
MENU_IDE_DEFAULTS_QUESTIONS_NAME = 'DelphiAIDevDefaultsQuestions1';
MENU_IDE_DEFAULTS_QUESTIONS_CAPTION = 'Defaults questions';
+ MENU_IDE_DEFAULTS_DATABASES_ADD_NAME = 'DelphiAIDevDatabasesAdd1';
+ MENU_IDE_DEFAULTS_DATABASES_ADD_CAPTION = 'Databases Registers';
+ MENU_IDE_DEFAULTS_DATABASES_CHAT_NAME = 'DelphiAIDevDatabasesChat1';
+ MENU_IDE_DEFAULTS_DATABASES_CHAT_CAPTION = 'Databases Chat';
+
MENU_IDE_CHAT_SETTINGS_NAME = 'DelphiAIDevSettings1';
MENU_IDE_CHAT_SETTINGS_CAPTION = 'Settings';
MENU_IDE_SETTINGS_NAME = 'C4DWizarSettings1';
diff --git a/Src/DB/Chat/DelphiAIDev.DB.Chat.View.dfm b/Src/DB/Chat/DelphiAIDev.DB.Chat.View.dfm
new file mode 100644
index 0000000..2fd2bc6
--- /dev/null
+++ b/Src/DB/Chat/DelphiAIDev.DB.Chat.View.dfm
@@ -0,0 +1,1044 @@
+object DelphiAIDevDBChatView: TDelphiAIDevDBChatView
+ Left = 0
+ Top = 0
+ BorderIcons = [biSystemMenu, biMaximize]
+ Caption = 'AI DB Chat'
+ ClientHeight = 661
+ ClientWidth = 975
+ Color = clBtnFace
+ Font.Charset = DEFAULT_CHARSET
+ Font.Color = clWindowText
+ Font.Height = -11
+ Font.Name = 'Tahoma'
+ Font.Style = []
+ KeyPreview = True
+ Position = poScreenCenter
+ ShowHint = True
+ OnActivate = FormActivate
+ OnClose = FormClose
+ OnResize = FormResize
+ OnShow = FormShow
+ DesignSize = (
+ 975
+ 661)
+ TextHeight = 13
+ object pnBack: TPanel
+ Left = 0
+ Top = 0
+ Width = 956
+ Height = 661
+ Margins.Left = 0
+ Margins.Top = 0
+ Margins.Right = 0
+ Margins.Bottom = 0
+ Align = alClient
+ BevelEdges = []
+ BevelOuter = bvNone
+ Padding.Left = 18
+ Padding.Top = 15
+ ParentBackground = False
+ TabOrder = 0
+ object Splitter1: TSplitter
+ Left = 18
+ Top = 153
+ Width = 938
+ Height = 3
+ Cursor = crVSplit
+ Align = alTop
+ ExplicitLeft = 0
+ ExplicitTop = 2
+ ExplicitWidth = 528
+ end
+ object Splitter2: TSplitter
+ Left = 18
+ Top = 498
+ Width = 938
+ Height = 3
+ Cursor = crVSplit
+ Align = alBottom
+ ExplicitLeft = 12
+ ExplicitTop = 340
+ end
+ object mmReturn: TRichEdit
+ AlignWithMargins = True
+ Left = 18
+ Top = 183
+ Width = 938
+ Height = 285
+ Hint = 'Response returned'
+ Margins.Left = 0
+ Margins.Top = 0
+ Margins.Right = 0
+ ParentCustomHint = False
+ Align = alClient
+ BevelInner = bvNone
+ BevelOuter = bvNone
+ Ctl3D = True
+ Font.Charset = ANSI_CHARSET
+ Font.Color = clWindow
+ Font.Height = -13
+ Font.Name = 'Courier New'
+ Font.Style = []
+ Lines.Strings = (
+ 'iii'
+ 'www')
+ ParentCtl3D = False
+ ParentFont = False
+ ParentShowHint = False
+ PopupMenu = pMenuMemoReturn
+ ScrollBars = ssVertical
+ ShowHint = True
+ TabOrder = 1
+ end
+ object pnBackQuestion: TPanel
+ Left = 18
+ Top = 15
+ Width = 938
+ Height = 138
+ Margins.Left = 0
+ Margins.Top = 0
+ Margins.Right = 0
+ Margins.Bottom = 0
+ Align = alTop
+ BevelOuter = bvNone
+ Padding.Top = 5
+ ParentBackground = False
+ TabOrder = 0
+ object Label2: TLabel
+ Left = 0
+ Top = 5
+ Width = 938
+ Height = 17
+ Align = alTop
+ AutoSize = False
+ Caption = 'Question / prompt'
+ end
+ object mmQuestion: TMemo
+ AlignWithMargins = True
+ Left = 0
+ Top = 22
+ Width = 938
+ Height = 116
+ Hint = 'Insert question'
+ Margins.Left = 0
+ Margins.Top = 0
+ Margins.Right = 0
+ Margins.Bottom = 0
+ Align = alClient
+ Font.Charset = DEFAULT_CHARSET
+ Font.Color = clWindowText
+ Font.Height = -13
+ Font.Name = 'Tahoma'
+ Font.Style = []
+ ParentFont = False
+ ParentShowHint = False
+ ShowHint = True
+ TabOrder = 0
+ OnChange = mmQuestionChange
+ OnKeyDown = mmQuestionKeyDown
+ OnKeyUp = mmQuestionKeyUp
+ end
+ end
+ object pnBackButtonsSearch: TPanel
+ Left = 18
+ Top = 156
+ Width = 938
+ Height = 27
+ Margins.Left = 0
+ Margins.Top = 0
+ Margins.Right = 0
+ Margins.Bottom = 0
+ Align = alTop
+ BevelOuter = bvNone
+ Padding.Top = 3
+ Padding.Bottom = 2
+ ParentBackground = False
+ TabOrder = 2
+ object lbCurrentAI: TLabel
+ Left = 0
+ Top = 3
+ Width = 56
+ Height = 22
+ Cursor = crHandPoint
+ Hint = 'AI being used'
+ Margins.Left = 0
+ Margins.Top = 0
+ Margins.Right = 0
+ Margins.Bottom = 0
+ Align = alLeft
+ Caption = 'lbCurrentAI'
+ PopupMenu = pMenuCurrentAI
+ OnClick = lbCurrentAIClick
+ ExplicitHeight = 13
+ end
+ object btnSend: TButton
+ AlignWithMargins = True
+ Left = 864
+ Top = 3
+ Width = 74
+ Height = 22
+ Cursor = crHandPoint
+ Margins.Top = 0
+ Margins.Right = 0
+ Margins.Bottom = 0
+ Align = alRight
+ Caption = 'Send'
+ TabOrder = 0
+ OnClick = btnSendClick
+ end
+ object pnBackConfigurableButtons: TPanel
+ Left = 395
+ Top = 3
+ Width = 466
+ Height = 22
+ Align = alRight
+ BevelOuter = bvNone
+ TabOrder = 1
+ object btnUseCurrentUnitCode: TButton
+ AlignWithMargins = True
+ Left = 261
+ Top = 0
+ Width = 205
+ Height = 22
+ Cursor = crHandPoint
+ Hint = 'Use data from current unit in query'
+ Margins.Top = 0
+ Margins.Right = 0
+ Margins.Bottom = 0
+ Align = alRight
+ Caption = '* Use current unit code in query * '
+ ImageIndex = 0
+ Images = ImageList1
+ TabOrder = 0
+ OnClick = btnUseCurrentUnitCodeClick
+ end
+ object btnCodeOnly: TButton
+ AlignWithMargins = True
+ Left = 149
+ Top = 0
+ Width = 109
+ Height = 22
+ Cursor = crHandPoint
+ Hint = 'Return only code without comments or explanations'
+ Margins.Top = 0
+ Margins.Right = 0
+ Margins.Bottom = 0
+ Align = alRight
+ Caption = '* SQL only *'
+ ImageIndex = 3
+ Images = ImageList1
+ TabOrder = 1
+ OnClick = btnCodeOnlyClick
+ end
+ object btnDefaultsQuestions: TButton
+ AlignWithMargins = True
+ Left = 56
+ Top = 0
+ Width = 90
+ Height = 22
+ Cursor = crHandPoint
+ Hint = 'Defaults Questions'
+ Margins.Top = 0
+ Margins.Right = 0
+ Margins.Bottom = 0
+ Align = alRight
+ Caption = '*Questions*'
+ ImageIndex = 4
+ Images = ImageList1
+ PopupMenu = pMenuQuestions
+ TabOrder = 2
+ OnClick = btnDefaultsQuestionsClick
+ end
+ end
+ end
+ object pnGridBack: TPanel
+ Left = 18
+ Top = 501
+ Width = 938
+ Height = 160
+ Align = alBottom
+ BevelOuter = bvNone
+ ParentBackground = False
+ TabOrder = 3
+ object DBGrid1: TDBGrid
+ Left = 0
+ Top = 0
+ Width = 938
+ Height = 133
+ Align = alClient
+ BorderStyle = bsNone
+ DataSource = DataSource1
+ Options = [dgTitles, dgIndicator, dgColumnResize, dgColLines, dgRowLines, dgTabs, dgConfirmDelete, dgCancelOnExit, dgTitleClick, dgTitleHotTrack]
+ PopupMenu = pMenuGrid
+ TabOrder = 0
+ TitleFont.Charset = DEFAULT_CHARSET
+ TitleFont.Color = clWindowText
+ TitleFont.Height = -11
+ TitleFont.Name = 'Tahoma'
+ TitleFont.Style = []
+ OnDrawColumnCell = DBGrid1DrawColumnCell
+ OnTitleClick = DBGrid1TitleClick
+ end
+ object Panel9: TPanel
+ Left = 0
+ Top = 133
+ Width = 938
+ Height = 27
+ Align = alBottom
+ BevelOuter = bvNone
+ Padding.Left = 3
+ Padding.Top = 3
+ Padding.Right = 3
+ Padding.Bottom = 3
+ ParentBackground = False
+ TabOrder = 1
+ object lbCount: TLabel
+ Left = 899
+ Top = 3
+ Width = 36
+ Height = 21
+ Align = alRight
+ Caption = '000000'
+ Layout = tlCenter
+ ExplicitHeight = 13
+ end
+ object Label3: TLabel
+ Left = 863
+ Top = 3
+ Width = 36
+ Height = 21
+ Align = alRight
+ Caption = 'Count: '
+ Layout = tlCenter
+ ExplicitHeight = 13
+ end
+ end
+ end
+ object Panel1: TPanel
+ Left = 18
+ Top = 471
+ Width = 938
+ Height = 27
+ Margins.Left = 0
+ Margins.Top = 0
+ Margins.Right = 0
+ Margins.Bottom = 0
+ Align = alBottom
+ BevelOuter = bvNone
+ Padding.Bottom = 2
+ ParentBackground = False
+ TabOrder = 4
+ object Label1: TLabel
+ Left = 337
+ Top = 0
+ Width = 85
+ Height = 25
+ Align = alLeft
+ Caption = ' Last generation: '
+ Layout = tlCenter
+ ExplicitHeight = 13
+ end
+ object lbLastGeneration: TLabel
+ AlignWithMargins = True
+ Left = 422
+ Top = 0
+ Width = 81
+ Height = 25
+ Margins.Left = 0
+ Margins.Top = 0
+ Margins.Right = 5
+ Margins.Bottom = 0
+ Align = alLeft
+ Caption = 'lbLastGeneration'
+ Layout = tlCenter
+ ExplicitHeight = 13
+ end
+ object btnExecuteSQL: TButton
+ AlignWithMargins = True
+ Left = 825
+ Top = 0
+ Width = 113
+ Height = 25
+ Cursor = crHandPoint
+ Margins.Top = 0
+ Margins.Right = 0
+ Margins.Bottom = 0
+ Align = alRight
+ Caption = 'Execute SQL'
+ ImageIndex = 5
+ ImageMargins.Left = 5
+ Images = ImageList1
+ TabOrder = 0
+ OnClick = btnExecuteSQLClick
+ end
+ object cBoxDatabases: TComboBox
+ AlignWithMargins = True
+ Left = 3
+ Top = 3
+ Width = 331
+ Height = 21
+ Align = alLeft
+ Style = csDropDownList
+ TabOrder = 1
+ OnClick = cBoxDatabasesClick
+ end
+ object btnGenerateDatabaseReference: TButton
+ AlignWithMargins = True
+ Left = 508
+ Top = 0
+ Width = 61
+ Height = 25
+ Cursor = crHandPoint
+ Margins.Left = 0
+ Margins.Top = 0
+ Margins.Bottom = 0
+ Align = alLeft
+ Caption = 'Generate'
+ TabOrder = 2
+ OnClick = btnGenerateDatabaseReferenceClick
+ end
+ end
+ end
+ object pnWait: TPanel
+ Left = 413
+ Top = 208
+ Width = 125
+ Height = 35
+ BevelOuter = bvNone
+ BiDiMode = bdLeftToRight
+ Caption = 'Wait for loading...'
+ ParentBiDiMode = False
+ ParentBackground = False
+ TabOrder = 1
+ Visible = False
+ object ShapeWait: TShape
+ Left = 0
+ Top = 0
+ Width = 125
+ Height = 35
+ Align = alClient
+ Brush.Color = 16770222
+ Pen.Color = 12615680
+ Pen.Style = psInsideFrame
+ Pen.Width = 2
+ ExplicitLeft = 32
+ ExplicitTop = 19
+ ExplicitWidth = 228
+ ExplicitHeight = 49
+ end
+ object pnWaitCaption: TPanel
+ Left = 0
+ Top = 0
+ Width = 125
+ Height = 35
+ Align = alClient
+ BevelOuter = bvNone
+ Caption = 'Wait for loading...'
+ TabOrder = 0
+ end
+ end
+ object StatusBar1: TStatusBar
+ Left = 956
+ Top = 0
+ Width = 19
+ Height = 661
+ Align = alRight
+ Panels = <
+ item
+ Width = 50
+ end>
+ end
+ object pnCommands: TPanel
+ Left = 947
+ Top = 174
+ Width = 26
+ Height = 115
+ Margins.Left = 0
+ Margins.Top = 0
+ Margins.Right = 0
+ Margins.Bottom = 0
+ Anchors = [akTop, akRight]
+ BevelOuter = bvNone
+ ParentBackground = False
+ TabOrder = 3
+ DesignSize = (
+ 26
+ 115)
+ object ShapeCommands: TShape
+ Left = 0
+ Top = 0
+ Width = 26
+ Height = 115
+ Margins.Left = 0
+ Margins.Top = 0
+ Margins.Right = 0
+ Margins.Bottom = 0
+ Anchors = [akLeft, akTop, akRight, akBottom]
+ Brush.Style = bsClear
+ Pen.Color = clGray
+ Pen.Style = psInsideFrame
+ ExplicitHeight = 73
+ end
+ object btnCopy: TSpeedButton
+ AlignWithMargins = True
+ Left = 0
+ Top = 46
+ Width = 26
+ Height = 23
+ Cursor = crHandPoint
+ Hint = 'Copy'
+ Margins.Left = 0
+ Margins.Top = 0
+ Margins.Right = 0
+ Margins.Bottom = 0
+ Align = alTop
+ Flat = True
+ Glyph.Data = {
+ 36030000424D3603000000000000360000002800000010000000100000000100
+ 1800000000000003000000000000000000000000000000000000FF00FFFF00FF
+ FF00FFFF00FFFF00FFB58C8C8C5A5A8C5A5A8C5A5A8C5A5A8C5A5A8C5A5A8C5A
+ 5A8C5A5A8C5A5AFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFB58C8CFFF7E7F7
+ EFDEF7EFDEF7EFDEF7EFDEF7EFDEF7EFDEF7E7CE8C5A5AFF00FFFF00FFFF00FF
+ FF00FFFF00FFFF00FFB58C8CF7EFDEF7DECEF7DEC6F7DEC6F7DEC6F7DEC6EFDE
+ CEEFDECE8C5A5AFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFB58C8CFFF7E7FF
+ D6A5FFD6A5FFD6A5FFD6A5FFD6A5FFD6A5EFDECE8C5A5AFF00FFFF00FFB58C8C
+ 8C5A5A8C5A5A8C5A5AB58C8CFFF7EFF7DEC6F7DEC6F7DEC6F7DEC6F7DEBDF7E7
+ CEEFDECE9C6B63FF00FFFF00FFB58C8CFFF7E7F7EFDEF7EFDEB58C8CFFF7EFF7
+ E7CEF7DEC6F7DEC6F7DEC6F7DEC6F7E7D6EFDECE9C6B6BFF00FFFF00FFB58C8C
+ F7EFDEF7DECEF7DEC6B58C8CFFFFF7FFD6A5FFD6A5FFD6A5FFD6A5FFD6A5FFD6
+ A5EFE7D6A57B73FF00FFFF00FFB58C8CFFF7E7FFD6A5FFD6A5B58C8CFFFFF7FF
+ E7D6FFE7D6F7E7D6F7E7CEFFE7D6FFF7E7EFDEDEA57B73FF00FFFF00FFB58C8C
+ FFF7EFF7DEC6F7DEC6B58C8CFFFFFFFFFFFFFFFFFFFFFFF7FFFFF7EFDEDED6C6
+ C6BDADADB58473FF00FFFF00FFB58C8CFFF7EFF7E7CEF7DEC6B58C8CFFFFFFFF
+ FFFFFFFFFFFFFFF7FFFFF7B58C8CB58C8CB58C8CB58C8CFF00FFFF00FFB58C8C
+ FFFFF7FFD6A5FFD6A5B58C8CFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFB58C8CEFB5
+ 6BC68C7BFF00FFFF00FFFF00FFB58C8CFFFFF7FFE7D6FFE7D6B58C8CB58C8CB5
+ 8C8CB58C8CB58C8CB58C8CB58C8CBD8484FF00FFFF00FFFF00FFFF00FFB58C8C
+ FFFFFFFFFFFFFFFFFFFFFFF7FFFFF7EFDEDED6C6C6BDADADB58473FF00FFFF00
+ FFFF00FFFF00FFFF00FFFF00FFB58C8CFFFFFFFFFFFFFFFFFFFFFFF7FFFFF7B5
+ 8C8CB58C8CB58C8CB58C8CFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFB58C8C
+ FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFB58C8CEFB56BC68C7BFF00FFFF00FFFF00
+ FFFF00FFFF00FFFF00FFFF00FFB58C8CB58C8CB58C8CB58C8CB58C8CB58C8CB5
+ 8C8CBD8484FF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FF}
+ OnClick = btnCopyClick
+ ExplicitLeft = -8
+ ExplicitTop = 55
+ end
+ object btnInsertAtCursor: TSpeedButton
+ AlignWithMargins = True
+ Left = 0
+ Top = 0
+ Width = 26
+ Height = 23
+ Cursor = crHandPoint
+ Hint = 'Insert Selected Text at Cursor'
+ Margins.Left = 0
+ Margins.Top = 0
+ Margins.Right = 0
+ Margins.Bottom = 0
+ Align = alTop
+ Flat = True
+ Glyph.Data = {
+ 8E010000424D8E010000000000008E0000002800000010000000100000000100
+ 08000000000000010000120B0000120B0000160000001600000000000000FFFF
+ FF00FF00FF00811E0000BD4C0000FFFBF800FFE9D300FFF6ED00FEE0C000FEE3
+ C500FEE6CB00FFF0E000FFF3E600FEDEB800FEEAD100FEEED900FFF7ED00FEFB
+ F700FFFAF200FFFEFB00004B000031C758000202020202020202020202020202
+ 02020404040404040402020202020202020211100B0E090D0402020202020202
+ 020213120C0F0A08040202020202020202020105070B06090402020202020202
+ 0202030303030303040202020202020202020202020202020202140204030303
+ 03030202020202020214140204100B0E090D0202020202021415140204120C0F
+ 0A08020202020202021414020405070B06090202020202020202140204030303
+ 03030303030303030402020202020202020211100B0E090D0402020202020202
+ 020213120C0F0A08040202020202020202020105070B06090402020202020202
+ 020204040404040404020202020202020202}
+ OnClick = btnInsertAtCursorClick
+ end
+ object btnMoreActions: TSpeedButton
+ AlignWithMargins = True
+ Left = 0
+ Top = 92
+ Width = 26
+ Height = 23
+ Cursor = crHandPoint
+ Hint = 'More actions...'
+ Margins.Left = 0
+ Margins.Top = 0
+ Margins.Right = 0
+ Margins.Bottom = 0
+ Align = alTop
+ Caption = '...'
+ Flat = True
+ PopupMenu = pMenuMoreActions
+ OnClick = btnMoreActionsClick
+ ExplicitTop = 46
+ end
+ object btnCreateNewUnit: TSpeedButton
+ AlignWithMargins = True
+ Left = 0
+ Top = 23
+ Width = 26
+ Height = 23
+ Cursor = crHandPoint
+ Hint = 'Create new unit with selected code'
+ Margins.Left = 0
+ Margins.Top = 0
+ Margins.Right = 0
+ Margins.Bottom = 0
+ Align = alTop
+ Flat = True
+ Glyph.Data = {
+ 36030000424D3603000000000000360000002800000010000000100000000100
+ 1800000000000003000000000000000000000000000000000000FF00FFFF00FF
+ FF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00
+ FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFAD7384B58484B58484B58484B5
+ 8484B58484B58484B58484B58484B58484B58484B58484FF00FFFF00FFFF00FF
+ FF00FFAD7384FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+ FFFFFFFFB58484FF00FFFF00FFFF00FFFF00FFAD7384FFFFFFFFFFFFFFFFFFFF
+ FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFB58484FF00FFFF00FFFF00FF
+ FF00FFAD7384FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+ FFFFFFFFB58484FF00FFFF00FFFF00FFFF00FFAD7384FFFFFFFFFFFFFFFFFFFF
+ FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFB58484FF00FFFF00FFFF00FF
+ FF00FFAD7384FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+ FFFFFFFFB58484FF00FFFF00FFFF00FFFF00FFAD7384FFFFFFFFFFFFFFFFFFFF
+ FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFB58484FF00FFFF00FFFF00FF
+ FF00FFAD7384FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+ FFFFFFFFB58484FF00FFFF00FFFF00FF3184FF3184FF3184FFF7F7F7F7F7F7F7
+ F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7B58484FF00FFFF00FFFF00FF
+ 3184FF42B5F73184FFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEF
+ EFEFEFEFB58484FF00FF3184FF3184FF3184FF42B5F73184FF3184FF3184FFE7
+ E7E7E7E7E7E7E7E7E7E7E7B58473B5948CB58C84B58484FF00FF3184FF8CD6F7
+ B5DEF7B5DEF7B5DEF78CD6F73184FFDEDEDEDEDEDEDEDEDEC6C6C6B58473FFFF
+ FFFFFFFFB58484FF00FF3184FF3184FF3184FFB5DEF73184FF3184FF3184FFD6
+ D6D6D6D6D6D6D6D6C6C6C6B58473FFFFFFB58484FF00FFFF00FFFF00FFFF00FF
+ 3184FFB5DEF73184FFCECECECECECECECECECECECECECECEC6C6C6B58473B584
+ 84FF00FFFF00FFFF00FFFF00FFFF00FF3184FF3184FF3184FFEFD6C6EFD6C6EF
+ D6C6EFD6C6EFD6C6D6BDB5B58473FF00FFFF00FFFF00FFFF00FF}
+ OnClick = btnCreateNewUnitClick
+ end
+ object btnCleanAll: TSpeedButton
+ AlignWithMargins = True
+ Left = 0
+ Top = 69
+ Width = 26
+ Height = 23
+ Cursor = crHandPoint
+ Hint = 'Clean all and start a new chat'
+ Margins.Left = 0
+ Margins.Top = 0
+ Margins.Right = 0
+ Margins.Bottom = 0
+ Align = alTop
+ Flat = True
+ Glyph.Data = {
+ 1A020000424D1A020000000000001A0100002800000010000000100000000100
+ 08000000000000010000210B0000210B00003900000039000000EA8F3100B66A
+ 5000AB735800C07B5800EAA15800FFB65800AB6A6000B67B6000C0846000A16A
+ 6A00A1736A00C0846A00A17B7300B68F7B00EAC07B00F4C07B00B68F8400EAC0
+ 8400F4C08400F4CA8400B6988F00C0988F00F4CA8F00C0A19800CAA19800B6AB
+ 9800F4CA9800F4D49800CAABA100D4ABA100D4B6A100E0B6A100EAB6A100EAC0
+ A100F4CAA100F4D4A100FFD4A100EAC0AB00F4D4AB00E0D4B600F4D4B600F4E0
+ B600E0C0C000E0CAC000F4E0C000E0CACA00F4E0CA00FFE0CA00FFEACA00FFEA
+ D400FFEAE000FFF4E000FFF4EA00FFF4F400FFFFF400FF00FF00FFFFFF003737
+ 0909090909090909090909090937373710302926231A16110E0E0E1309373737
+ 10302C2826221611110E0E110937373714322E2C2826221A11110E1109373737
+ 14332E2C292823221A11110E093737371736322E2E2C2826221A111109373737
+ 183834322E2C2928261A1616093737371C383534312E2C292826221A09373737
+ 1C38383534322E2C28262323093737371D3838383532312E2C28282209373737
+ 1E3838383835323131302719093737371F383838383834342E0D0C0A09373737
+ 1F383838383838362A0204000137373725383838383838382B07050337373737
+ 1F353434343434342A070B37373737371F212121211F1F211C0637373737}
+ OnClick = btnCleanAllClick
+ ExplicitTop = 92
+ end
+ end
+ object ImageList1: TImageList
+ Left = 96
+ Top = 200
+ Bitmap = {
+ 494C010106003000040010001000FFFFFFFFFF10FFFFFFFFFFFFFFFF424D3600
+ 0000000000003600000028000000400000002000000001002000000000000020
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 000000000000F0CAA600F0CAA600C0C0C000C0C0C000CCCC9900F0CAA6000000
+ 000000000000000000000000000000000000000000FF000000FF000000FF0000
+ 00FF000000FF000000FF000000FF000000FF000000FF00660000003300000033
+ 00000033000000660000000000FF000000FF0000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000F0CA
+ A600D7D7D700E3E3E300E3E3E300CBCBCB00C0C0C000C0C0C000B2B2B200A4A0
+ A000F0CAA600000000000000000000000000000000FF000000FF000000FF0066
+ 9900006699000066990000669900006699000066000000800000009900000099
+ 0000008000000066000000330000000000FF0000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000F0CAA600EAEA
+ EA00F0FBFF00F0CAA600CC666600CC663300CC663300CC666600CC999900B2B2
+ B200A4A0A000CC9999000000000000000000000000FF000000FF0066990033CC
+ FF0000CCFF0033CCFF0066CCFF0000663300009933000099330099CC99003399
+ 3300009900000099000000660000006600000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 00000000000000000000000000000000000000000000F0CAA600F1F1F100FFFF
+ FF00CC996600CC330000CC333300FFCCCC00F0CAA600CC330000CC330000CC66
+ 6600B2B2B200B2B2B200F0CAA60000000000000000FF0066990066FFFF0033CC
+ FF0000CCFF0033CCFF0066CCFF000099000000CC330000993300FFFFFF00FFFF
+ FF0033CC66000099000000990000006600000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 00000000000000000000000000000000000000000000E3E3E300FFFFFF00CC99
+ 6600CC330000CC333300CC663300CC999900CC999900CC333300CC333300CC33
+ 0000CC996600C0C0C000C0C0C00000000000000000FF0066990066FFFF0033CC
+ FF0000CCFF0033CCFF0066CCFF000099000033CC660000993300FFFFFF00FFFF
+ FF00FFFFFF0033CC330000990000006600000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000F0CAA600FFFFFF00FFECCC00CC66
+ 3300CC333300CC333300CC663300CC999900CC996600CC333300CC663300CC33
+ 3300CC663300B2B2B200CBCBCB00F0CAA600000000FF0066990066FFFF0033CC
+ FF0000CCFF0033CCFF0066CCFF000099000066CC990000993300FFFFFF00FFFF
+ FF0033CC66000099000000990000006600000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000FFCCCC00FFFFFF00CC999900CC66
+ 3300CC663300CC663300CC663300F8F8F800EAEAEA00CC663300CC330000CC66
+ 3300CC330000CC996600D7D7D700F0CAA600000000FF0066990099FFFF0099FF
+ FF00CCFFFF00CCFFFF00F0FBFF003399330066CC990066CC660099CC990033CC
+ 6600009933000099330000993300006600000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000FFCCCC00FFFFFF00CC996600CC66
+ 3300CC663300CC663300CC663300F0CAA600FFFFFF00F0CAA600CC663300CC33
+ 0000CC330000CC666600EAEAEA00F0CAA600000000FF0066990099FFFF003399
+ CC000099CC000099CC000099CC00008080000099000099CC990066CC990066CC
+ 660033CC66000099330000993300000000FF0000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000FFCCCC00FFFFFF00CC996600CC66
+ 3300CC663300CC663300CC663300CC663300F0CAA600FFFFFF00FFECCC00CC66
+ 3300CC330000CC666600F1F1F100F0CAA600000000FF0066990033CCCC0033CC
+ FF0000CCFF0033CCFF0066CCFF0066CCFF003399990000993300009900000099
+ 00000099000000993300000000FF000000FF0000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000FFCCCC00FFFFFF00F0CAA600CC66
+ 3300CC993300CC996600CC663300CC663300CC663300F0CAA600FFFFFF00CC99
+ 6600CC330000CC996600F0FBFF00F0CAA600000000FF0066990066FFFF0033CC
+ FF0000CCFF0033CCFF0066CCFF0066CCFF003399CC000099CC00006699000000
+ 00FF000000FF000000FF000000FF000000FF0000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000FFCCCC00F8F8F800EAEAEA00CC99
+ 6600F0CAA600FFFFFF00CC996600CC663300CC663300CC996600FFFFFF00CC99
+ 9900CC663300FFCCCC00F1F1F100F0CAA600000000FF0066990066FFFF0033CC
+ FF0000CCFF0033CCFF0066CCFF0066CCFF003399CC000099CC00006699000000
+ 00FF000000FF000000FF000000FF000000FF0000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 00000000000000000000000000000000000000000000E3E3E300FFFFFF00F0CA
+ A600FF999900FFFFFF00F8F8F800F0CAA600F0CAA600F8F8F800F8F8F800CC66
+ 3300CC996600FFFFFF00FFCCCC0000000000000000FF0066990066FFFF0033CC
+ FF0000CCFF0033CCFF0066CCFF0066CCFF003399CC000099CC00006699000000
+ 00FF000000FF000000FF000000FF000000FF0000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 00000000000000000000000000000000000000000000F0CAA600F1F1F100FFFF
+ FF00F0CAA600F0CAA600FFECCC00F8F8F800F8F8F800FFECCC00CC996600CC99
+ 9900FFFFFF00EAEAEA00FFCCCC0000000000000000FF0066990066FFFF0066FF
+ FF0066FFFF0066FFFF0066FFFF0099FFFF0033CCFF000099CC00006699000000
+ 00FF000000FF000000FF000000FF000000FF0000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000F0CAA600F1F1
+ F100FFFFFF00FFECCC00F0CAA600F0CAA600F0CAA600F0CAA600FFCCCC00FFFF
+ FF00EAEAEA00F0CAA6000000000000000000000000FF00669900FFFFFF00F0FB
+ FF00CCFFFF0099FFFF0099FFFF0099FFFF0099FFFF0066FFFF00006699000000
+ 00FF000000FF000000FF000000FF000000FF0000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000F0CA
+ A600EAEAEA00F1F1F100FFFFFF00FFFFFF00FFFFFF00F8F8F800F8F8F800E3E3
+ E300E3E3E300000000000000000000000000000000FF000000FF00669900F0FB
+ FF00CCFFFF00CCFFFF0099FFFF0099FFFF0099FFFF0000669900000000FF0000
+ 00FF000000FF000000FF000000FF000000FF0000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 000000000000F0CAA600F0CAA600FFCCCC00FFCCCC00F0CAA600F0CAA6000000
+ 000000000000000000000000000000000000000000FF000000FF000000FF0066
+ 99000066990000669900006699000066990000669900000000FF000000FF0000
+ 00FF000000FF000000FF000000FF000000FF0000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000999999009999
+ 9900999999009999990000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000555555005555
+ 5500555555005555550000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000009696
+ 9600969696009696960000000000000000000000000099999900E3E3E300CCCC
+ CC00C0C0C000C0C0C00096969600000000000000000000000000000000004D4D
+ 4D004D4D4D004D4D4D0000000000000000000000000055555500CBCBCB00A4A0
+ A00096969600969696004D4D4D00000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000666666006666
+ 6600000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000006600000066
+ 0000000000000000000000000000000000000000000000000000969696009999
+ 9900A4A0A000B2B2B2009696960096969600000000009999990096969600CBCB
+ CB00B2B2B200A4A0A000868686000000000000000000000000004D4D4D005555
+ 550066666600777777004D4D4D004D4D4D0000000000555555004D4D4D009999
+ 9900808080006666660042424200000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000066666600777777007777
+ 7700000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000660000008000000066
+ 0000000000000000000000000000000000000000000096969600C0C0C0009999
+ 9900B2B2B200A4A0A000B2B2B200B2B2B20096969600CCCCCC00CBCBCB009696
+ 960096969600868686000000000000000000000000004D4D4D00868686005555
+ 5500777777005F5F5F0066996600777777004D4D4D00A4A0A000999999004D4D
+ 4D004D4D4D003939390000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000006666660086868600868686007777
+ 7700666666000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000066000000800000009900000080
+ 00000033000000000000000000000000000096969600C0C0C000E3E3E3009999
+ 9900B2B2B200A4A0A000A4A0A000B2B2B20096969600B2B2B200CBCBCB00D7D7
+ D700D7D7D700D7D7D700B2B2B200868686004D4D4D0096969600C0C0C0005555
+ 5500777777005F5F5F0033993300666699004D4D4D00FF990000FFCC3300FFCC
+ 6600FFCC6600CC99990077777700393939000000000000000000000000000000
+ 0000000000000000000000000000666666009696960096969600808080008686
+ 8600666666000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000006600000099330000990000008000000080
+ 00000066000000000000000000000000000096969600EAEAEA00D7D7D7009696
+ 9600B2B2B200B2B2B200A4A0A000969696009696960099999900A4A0A000C0C0
+ C000C0C0C000C0C0C000C0C0C000868686004D4D4D00CCCCCC00B2B2B2005555
+ 550077777700777777006666990033669900006699003366660099993300FF99
+ 3300FF993300FF993300FF993300424242000000000000000000000000000000
+ 0000000000000000000077777700A4A0A000A4A0A00077777700666666008686
+ 8600808080000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000660000009933000099330000660000003300000080
+ 00000080000000000000000000000000000096969600EAEAEA00D7D7D7008686
+ 8600999999009999990096969600A4A0A000B2B2B200A4A0A00096969600B2B2
+ B200CCCCCC00CBCBCB00B2B2B200868686004D4D4D00CCCCCC00B2B2B2000033
+ 99003366660033666600006699000066CC003399FF000066CC00006699009999
+ 6600FFCC6600FFCC3300FF993300393939000000000000000000000000000000
+ 0000000000000000000000000000868686007777770000000000000000007777
+ 7700969696006666660000000000000000000000000000000000000000000000
+ 0000000000000000000000000000009933000066000000000000000000000066
+ 00000099000000660000000000000000000096969600EAEAEA00D7D7D7008686
+ 86009696960099999900C0C0C000B2B2B20096969600A4A0A000A4A0A0008686
+ 8600C0C0C000D7D7D700C0C0C000808080004D4D4D00CCCCCC00B2B2B2000033
+ 99000066CC000066CC003399FF003399CC000066990066666600336699000033
+ 990086868600FFCC6600FF993300333333000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000868686008080800000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 00000080000000660000000000000000000096969600EAEAEA00D7D7D7008686
+ 8600A4A0A000B2B2B200B2B2B2009696960096969600CCCCCC00DDDDDD00C0C0
+ C00099999900D7D7D700CBCBCB00777777004D4D4D00D7D7D700B2B2B2000033
+ 99000066FF000099FF003366CC00336666004D4D4D00FFCC6600FFCC99006699
+ 990033669900FFCC6600FFCC3300292929000000000000000000333333003333
+ 3300000000000000000000000000333333003333330000000000000000000000
+ 00003333330033333300333333000000000000000000000000000000FF000000
+ FF000000000000000000000000000000FF000000FF0000000000000000000000
+ 00000000FF000000FF000000FF000000000096969600F1F1F100DDDDDD008686
+ 8600A4A0A000B2B2B200A4A0A0009696960096969600B2B2B200C0C0C000CBCB
+ CB00C0C0C000CCCCCC00CBCBCB00777777004D4D4D00DDDDDD00C0C0C0000033
+ 99000066FF000099FF000066CC00336699004D4D4D008080800099996600A4A0
+ A00099996600CCCC6600CC996600222222000000000033333300000000000000
+ 0000333333000000000033333300000000000000000033333300000000003333
+ 330000000000808080003333330000000000000000000000FF00000000000000
+ 00000000FF00000000000000FF0000000000000000000000FF00000000000000
+ FF0000000000006600000000FF000000000096969600FFFFFF00E3E3E3008686
+ 860086868600868686008686860086868600B2B2B20096969600969696009696
+ 9600969696009696960080808000000000004D4D4D00F1F1F100CBCBCB000033
+ 990000339900003399000033990000339900666699004D4D4D004D4D4D004D4D
+ 4D004D4D4D004D4D4D0039393900000000000000000033333300000000000000
+ 0000000000000000000033333300000000000000000033333300000000003333
+ 330000000000000000003333330000000000000000000000FF00000000000000
+ 000000000000000000000000FF0000000000000000000000FF00000000000000
+ FF0000000000000000000000FF000000000096969600F1F1F100C0C0C0009999
+ 9900CCCCCC0099999900A4A0A000B2B2B200C0C0C00096969600000000000000
+ 0000000000000000000000000000000000004D4D4D00DDDDDD00969696005555
+ 5500A4A0A000555555005F5F5F0077777700969696004D4D4D00000000000000
+ 0000000000000000000000000000000000000000000033333300000000000000
+ 0000333333000000000033333300000000000000000033333300000000003333
+ 330000000000000000003333330066666600000000000000FF00000000000000
+ 00000000FF00000000000000FF0000000000000000000000FF00000000000000
+ FF0000000000000000000000FF000033000096969600CCCCCC00F1F1F100C0C0
+ C000B2B2B200B2B2B200C0C0C000A4A0A000A4A0A00096969600000000000000
+ 0000000000000000000000000000000000004D4D4D00A4A0A000DDDDDD009696
+ 9600777777008080800096969600666666005F5F5F004D4D4D00000000000000
+ 0000000000000000000000000000000000000000000000000000333333003333
+ 3300000000000000000000000000333333003333330000000000000000000000
+ 00003333330033333300333333006666660000000000000000000000FF000000
+ FF000000000000000000000000000000FF000000FF0000000000000000000000
+ 00000000FF000000FF000000FF000033000096969600FFFFFF00FFFFFF00F8F8
+ F800DDDDDD00CCCCCC00C0C0C000C0C0C000C0C0C00096969600000000000000
+ 0000000000000000000000000000000000004D4D4D00FFFFFF00F1F1F100E3E3
+ E300C0C0C000A4A0A0008686860080808000808080004D4D4D00000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000033333300000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000FF0000000000A4A0A00096969600FFFFFF00FFFF
+ FF00FFFFFF00EAEAEA00CCCCCC00969696009696960000000000000000000000
+ 000000000000000000000000000000000000666666004D4D4D00FFFFFF00FFFF
+ FF00F8F8F800D7D7D700A4A0A0004D4D4D004D4D4D0000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000033333300000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000FF00000000000000000000000000969696009696
+ 9600969696009696960096969600000000000000000000000000000000000000
+ 00000000000000000000000000000000000000000000000000004D4D4D004D4D
+ 4D004D4D4D004D4D4D004D4D4D00000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000424D3E000000000000003E000000
+ 2800000040000000200000000100010000000000000100000000000000000000
+ 000000000000000000000000FFFFFF00F81FFF8300000000E007E00100000000
+ C003C00000000000800180000000000080018000000000000000800000000000
+ 0000800000000000000080010000000000008003000000000000801F00000000
+ 0000801F000000008001801F000000008001801F00000000C003801F00000000
+ E007C03F00000000F81FE07F00000000FFC3FFC3FFFFFFFFE381E381FFCFFFCF
+ C081C081FF8FFF8F80038003FF07FF0700000000FE07FE0700000000FC07FC07
+ 00000000FE63FE6300000000FFF3FFF300000000CE71CE7100000000B5A9B5A9
+ 00010001BDADBDAD003F003FB5ACB5AC003F003FCE70CE70003F003FFFFDFFFD
+ 007F007FFFFDFFFDC1FFC1FFFFFFFFFF00000000000000000000000000000000
+ 000000000000}
+ end
+ object pMenuMemoReturn: TPopupMenu
+ Left = 120
+ Top = 248
+ object Cut1: TMenuItem
+ Caption = 'Cut'
+ ShortCut = 16472
+ OnClick = Cut1Click
+ end
+ object Copy1: TMenuItem
+ Caption = 'Copy'
+ ShortCut = 16451
+ OnClick = Copy1Click
+ end
+ object Paste1: TMenuItem
+ Caption = 'Paste'
+ ShortCut = 16470
+ OnClick = Paste1Click
+ end
+ object N2: TMenuItem
+ Caption = '-'
+ end
+ object WordWrap1: TMenuItem
+ AutoCheck = True
+ Caption = 'WordWrap'
+ OnClick = WordWrap1Click
+ end
+ object N1: TMenuItem
+ Caption = '-'
+ end
+ object SelectAll1: TMenuItem
+ Caption = 'Select all'
+ ShortCut = 16449
+ OnClick = SelectAll1Click
+ end
+ object Clear1: TMenuItem
+ Caption = 'Clear'
+ ShortCut = 16430
+ OnClick = Clear1Click
+ end
+ end
+ object pMenuCurrentAI: TPopupMenu
+ OnPopup = pMenuCurrentAIPopup
+ Left = 26
+ Top = 231
+ object Gemini1: TMenuItem
+ Caption = 'Gemini'
+ OnClick = Gemini1Click
+ end
+ object ChatGPT1: TMenuItem
+ Tag = 1
+ Caption = 'ChatGPT'
+ OnClick = Gemini1Click
+ end
+ object Groq1: TMenuItem
+ Tag = 2
+ Caption = 'Groq'
+ OnClick = Gemini1Click
+ end
+ object Mistral1: TMenuItem
+ Tag = 3
+ Caption = 'Mistral'
+ OnClick = Gemini1Click
+ end
+ object Ollama1: TMenuItem
+ Tag = 4
+ Caption = 'Ollama (offline)'
+ OnClick = Gemini1Click
+ end
+ end
+ object pMenuMoreActions: TPopupMenu
+ Images = ImageList1
+ Left = 824
+ Top = 40
+ object SaveContentToFile1: TMenuItem
+ Caption = 'Save content to file'
+ OnClick = SaveContentToFile1Click
+ end
+ end
+ object pMenuQuestions: TPopupMenu
+ Left = 530
+ Top = 531
+ end
+ object DataSource1: TDataSource
+ Left = 170
+ Top = 464
+ end
+ object pMenuGrid: TPopupMenu
+ Left = 794
+ Top = 472
+ object CopyCurrentColumn1: TMenuItem
+ Caption = 'Copy current column'
+ ShortCut = 16451
+ OnClick = CopyCurrentColumn1Click
+ end
+ object CopyCurrentLine1: TMenuItem
+ Caption = 'Copy current line'
+ OnClick = CopyCurrentLine1Click
+ end
+ object CopyAllGridData: TMenuItem
+ Caption = 'Copy all grid data'
+ OnClick = CopyAllGridDataClick
+ end
+ object N3: TMenuItem
+ Caption = '-'
+ end
+ object SaveAllGridDataAsCSV: TMenuItem
+ Caption = 'Save all grid data as CSV'
+ OnClick = SaveAllGridDataAsCSVClick
+ end
+ object SaveAllGridDataAsTXT: TMenuItem
+ Caption = 'Save all grid data as TXT'
+ OnClick = SaveAllGridDataAsTXTClick
+ end
+ end
+end
diff --git a/Src/DB/Chat/DelphiAIDev.DB.Chat.View.pas b/Src/DB/Chat/DelphiAIDev.DB.Chat.View.pas
new file mode 100644
index 0000000..22f5e27
--- /dev/null
+++ b/Src/DB/Chat/DelphiAIDev.DB.Chat.View.pas
@@ -0,0 +1,944 @@
+unit DelphiAIDev.DB.Chat.View;
+
+interface
+
+uses
+ System.SysUtils,
+ System.StrUtils,
+ System.Variants,
+ System.Classes,
+ System.JSON,
+ System.Threading,
+ Vcl.Graphics,
+ Vcl.Controls,
+ Vcl.Forms,
+ Vcl.Dialogs,
+ System.ImageList,
+ Vcl.ImgList,
+ DockForm,
+ Vcl.StdCtrls,
+ Vcl.ExtCtrls,
+ Vcl.ComCtrls,
+ Vcl.Menus,
+ Vcl.Buttons,
+ Winapi.Windows,
+ Winapi.Messages,
+ Clipbrd,
+ DelphiAIDev.Types,
+ DelphiAIDev.Consts,
+ DelphiAIDev.AI.Facade,
+ DelphiAIDev.Settings,
+ DelphiAIDev.ModuleCreator,
+ DelphiAIDev.DefaultsQuestions.PopupMenu,
+ DelphiAIDev.Chat.ProcessResponse,
+ Data.DB,
+ Vcl.Grids,
+ Vcl.DBGrids,
+ DelphiAIDev.DB.Registers.Model,
+ DelphiAIDev.DB.Registers.Fields,
+ C4D.Conn,
+ DelphiAIDev.Utils.DBGrids,
+ DelphiAIDev.Projects.Model,
+ DelphiAIDev.DB.References.View;
+
+type
+ TDelphiAIDevDBChatView = class(TDockableForm)
+ ImageList1: TImageList;
+ pMenuMemoReturn: TPopupMenu;
+ Cut1: TMenuItem;
+ Copy1: TMenuItem;
+ Paste1: TMenuItem;
+ SelectAll1: TMenuItem;
+ pnBack: TPanel;
+ pnBackQuestion: TPanel;
+ mmQuestion: TMemo;
+ N1: TMenuItem;
+ mmReturn: TRichEdit;
+ Splitter1: TSplitter;
+ pnWait: TPanel;
+ ShapeWait: TShape;
+ pnWaitCaption: TPanel;
+ pMenuCurrentAI: TPopupMenu;
+ Gemini1: TMenuItem;
+ ChatGPT1: TMenuItem;
+ pnBackButtonsSearch: TPanel;
+ lbCurrentAI: TLabel;
+ StatusBar1: TStatusBar;
+ pnCommands: TPanel;
+ btnCopy: TSpeedButton;
+ btnInsertAtCursor: TSpeedButton;
+ btnMoreActions: TSpeedButton;
+ ShapeCommands: TShape;
+ btnSend: TButton;
+ pMenuMoreActions: TPopupMenu;
+ SaveContentToFile1: TMenuItem;
+ btnCreateNewUnit: TSpeedButton;
+ Clear1: TMenuItem;
+ N2: TMenuItem;
+ WordWrap1: TMenuItem;
+ pnBackConfigurableButtons: TPanel;
+ btnUseCurrentUnitCode: TButton;
+ btnCodeOnly: TButton;
+ btnDefaultsQuestions: TButton;
+ pMenuQuestions: TPopupMenu;
+ btnCleanAll: TSpeedButton;
+ Groq1: TMenuItem;
+ Mistral1: TMenuItem;
+ pnGridBack: TPanel;
+ DBGrid1: TDBGrid;
+ Splitter2: TSplitter;
+ DataSource1: TDataSource;
+ pMenuGrid: TPopupMenu;
+ CopyCurrentColumn1: TMenuItem;
+ CopyCurrentLine1: TMenuItem;
+ CopyAllGridData: TMenuItem;
+ N3: TMenuItem;
+ SaveAllGridDataAsCSV: TMenuItem;
+ SaveAllGridDataAsTXT: TMenuItem;
+ Panel1: TPanel;
+ btnExecuteSQL: TButton;
+ cBoxDatabases: TComboBox;
+ Label1: TLabel;
+ lbLastGeneration: TLabel;
+ Panel9: TPanel;
+ lbCount: TLabel;
+ Label3: TLabel;
+ Ollama1: TMenuItem;
+ btnGenerateDatabaseReference: TButton;
+ Label2: TLabel;
+ procedure FormShow(Sender: TObject);
+ procedure cBoxSizeFontKeyPress(Sender: TObject; var Key: Char);
+ procedure Cut1Click(Sender: TObject);
+ procedure Copy1Click(Sender: TObject);
+ procedure Paste1Click(Sender: TObject);
+ procedure FormClose(Sender: TObject; var Action: TCloseAction);
+ procedure btnSendClick(Sender: TObject);
+ procedure mmQuestionKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState);
+ procedure btnCopyClick(Sender: TObject);
+ procedure btnInsertAtCursorClick(Sender: TObject);
+ procedure SelectAll1Click(Sender: TObject);
+ procedure mmQuestionChange(Sender: TObject);
+ procedure mmQuestionKeyUp(Sender: TObject; var Key: Word; Shift: TShiftState);
+ procedure FormActivate(Sender: TObject);
+ procedure lbCurrentAIClick(Sender: TObject);
+ procedure Gemini1Click(Sender: TObject);
+ procedure pMenuCurrentAIPopup(Sender: TObject);
+ procedure btnMoreActionsClick(Sender: TObject);
+ procedure SaveContentToFile1Click(Sender: TObject);
+ procedure btnCreateNewUnitClick(Sender: TObject);
+ procedure btnUseCurrentUnitCodeClick(Sender: TObject);
+ procedure FormResize(Sender: TObject);
+ procedure WordWrap1Click(Sender: TObject);
+ procedure btnCodeOnlyClick(Sender: TObject);
+ procedure btnDefaultsQuestionsClick(Sender: TObject);
+ procedure Clear1Click(Sender: TObject);
+ procedure btnCleanAllClick(Sender: TObject);
+ procedure btnExecuteSQLClick(Sender: TObject);
+ procedure cBoxDatabasesClick(Sender: TObject);
+ procedure DBGrid1DrawColumnCell(Sender: TObject; const Rect: TRect; DataCol: Integer; Column: TColumn; State: TGridDrawState);
+ procedure CopyCurrentColumn1Click(Sender: TObject);
+ procedure CopyCurrentLine1Click(Sender: TObject);
+ procedure CopyAllGridDataClick(Sender: TObject);
+ procedure SaveAllGridDataAsCSVClick(Sender: TObject);
+ procedure SaveAllGridDataAsTXTClick(Sender: TObject);
+ procedure DBGrid1TitleClick(Column: TColumn);
+ procedure btnGenerateDatabaseReferenceClick(Sender: TObject);
+ private
+ FAI: TDelphiAIDevAIFacade;
+ FSettings: TDelphiAIDevSettings;
+ FProcessResponse: TDelphiAIDevChatProcessResponse;
+ FPopupMenuQuestions: TDelphiAIDevDefaultsQuestionsPopupMenu;
+ FbtnUseCurrentUnitCodeWidth: Integer;
+ FbtnCodeOnlyWidth: Integer;
+ FbtnDefaultsQuestionsWidth: Integer;
+ FQuestionOnShow: string;
+ FConn: IC4DConn;
+ FQueryExecuteSQL: IC4DConnQuery;
+ procedure FillMemoReturnWithFile;
+ procedure SaveMemoReturnInFile;
+ procedure InitializeRichEditReturn;
+ procedure ProcessSend;
+ procedure AddResponseSimple(const AString: string);
+ procedure Last;
+ function GetSelectedTextOrAllFromReturn: string;
+ function GetSelectedTextOrAllOrAbort: string;
+ procedure WaitingFormOFF;
+ procedure WaitingFormON;
+ procedure ConfLabelCurrentAI;
+ procedure ConfScreenOnShow;
+ procedure ChangeUseCurrentUnitCode;
+ procedure ChangeCodeOnly;
+ procedure AddItemsPopupMenuQuestion;
+ procedure DoProcessClickInItemDefaultQuestions(ACodeOnly: Boolean; AQuestion: string);
+ procedure ProcessWordWrap;
+ procedure ConfScreenOnCreate;
+ procedure ReloadDatabases;
+ procedure FillDateLastReferences;
+ function GetFieldDBSelected: TDelphiAIDevDBRegistersFields;
+ function GetJsonDatabase: string;
+ procedure HandleErrorExecutingSQLCommand(const E: Exception);
+ procedure ValidateIfDatabaseSelected;
+ public
+ constructor Create(AOwner: TComponent); override;
+ destructor Destroy; override;
+ property QuestionOnShow: string write FQuestionOnShow;
+ end;
+
+var
+ DelphiAIDevDBChatView: TDelphiAIDevDBChatView;
+
+procedure RegisterSelf;
+procedure Unregister;
+procedure DelphiAIDevDBChatViewShowDockableForm;
+
+implementation
+
+uses
+ DeskUtil,
+ DelphiAIDev.Utils,
+ DelphiAIDev.Utils.OTA,
+ DelphiAIDev.DB.Utils;
+
+{$R *.dfm}
+
+const
+ UseCurrentUnitCode_ImageIndex_OFF = 0;
+ UseCurrentUnitCode_ImageIndex_ON = 1;
+ CodeOnly_ImageIndex_OFF = 2;
+ CodeOnly_ImageIndex_ON = 3;
+
+procedure RegisterSelf;
+begin
+ if not Assigned(DelphiAIDevDBChatView) then
+ DelphiAIDevDBChatView := TDelphiAIDevDBChatView.Create(nil);
+
+ if @RegisterFieldAddress <> nil then
+ RegisterFieldAddress(DelphiAIDevDBChatView.Name, @DelphiAIDevDBChatView);
+
+ RegisterDesktopFormClass(TDelphiAIDevDBChatView, DelphiAIDevDBChatView.Name, DelphiAIDevDBChatView.Name);
+end;
+
+procedure Unregister;
+begin
+ if @UnRegisterFieldAddress <> nil then
+ UnRegisterFieldAddress(@DelphiAIDevDBChatView);
+ FreeAndNil(DelphiAIDevDBChatView);
+end;
+
+procedure DelphiAIDevDBChatViewShowDockableForm;
+begin
+ ShowDockableForm(DelphiAIDevDBChatView);
+ FocusWindow(DelphiAIDevDBChatView);
+end;
+
+constructor TDelphiAIDevDBChatView.Create(AOwner: TComponent);
+begin
+ inherited;
+ DeskSection := Self.Name;
+ AutoSave := True;
+ SaveStateNecessary := True;
+
+ FAI := TDelphiAIDevAIFacade.Create;
+ FSettings := TDelphiAIDevSettings.GetInstance;
+ FProcessResponse := TDelphiAIDevChatProcessResponse.Create(mmReturn);
+ FPopupMenuQuestions := TDelphiAIDevDefaultsQuestionsPopupMenu.Create;
+ FQuestionOnShow := '';
+
+ FConn := TC4DConn.New;
+ FQueryExecuteSQL := FConn.Query.DataSource(DataSource1);
+
+ Self.ConfScreenOnCreate;
+ Self.FillMemoReturnWithFile;
+ TUtilsDBGrids.ConfDBGrid(DBGrid1);
+end;
+
+destructor TDelphiAIDevDBChatView.Destroy;
+begin
+ Self.SaveMemoReturnInFile;
+ FPopupMenuQuestions.Free;
+ FProcessResponse.Free;
+ FAI.Free;
+ inherited;
+end;
+
+procedure TDelphiAIDevDBChatView.FormShow(Sender: TObject);
+begin
+ Self.ConfScreenOnShow;
+ Self.InitializeRichEditReturn;
+ Self.ProcessWordWrap;
+ Self.AddItemsPopupMenuQuestion;
+ TUtils.MemoFocusOnTheEnd(mmQuestion);
+ Self.ReloadDatabases;
+end;
+
+procedure TDelphiAIDevDBChatView.FormActivate(Sender: TObject);
+begin
+ Self.ConfLabelCurrentAI;
+
+ if not FQuestionOnShow.Trim.IsEmpty then
+ begin
+ mmQuestion.Lines.Clear;
+ mmQuestion.Lines.Add(FQuestionOnShow);
+ FQuestionOnShow := '';
+ end;
+end;
+
+procedure TDelphiAIDevDBChatView.FormClose(Sender: TObject; var Action: TCloseAction);
+begin
+ Self.WaitingFormOFF;
+end;
+
+procedure TDelphiAIDevDBChatView.DBGrid1DrawColumnCell(Sender: TObject;
+ const Rect: TRect; DataCol: Integer; Column: TColumn; State: TGridDrawState);
+begin
+ TUtilsDBGrids.DrawColumnCell(TDBGrid(Sender), Rect, DataCol, Column, Vcl.Grids.TGridDrawState(State));
+end;
+
+procedure TDelphiAIDevDBChatView.ConfScreenOnCreate;
+begin
+ mmReturn.Lines.Clear;
+
+ pnWait.Visible := False;
+ FbtnUseCurrentUnitCodeWidth := btnUseCurrentUnitCode.Width;
+ FbtnCodeOnlyWidth := btnCodeOnly.Width;
+ FbtnDefaultsQuestionsWidth := btnDefaultsQuestions.Width;
+
+ ShapeCommands.Left := 0;
+ ShapeCommands.Top := 0;
+ ShapeCommands.Width := ShapeCommands.Parent.Width;
+ ShapeCommands.Height := ShapeCommands.Parent.Height;
+
+ {$IF CompilerVersion >= 34} //Sydney
+ pnWaitCaption.StyleElements := pnWaitCaption.StyleElements - [seFont];
+ {$ENDIF}
+end;
+
+procedure TDelphiAIDevDBChatView.ConfScreenOnShow;
+begin
+ TUtilsOTA.IDEThemingAll(TDelphiAIDevDBChatView, Self);
+ btnMoreActions.Font.Color := TUtilsOTA.ActiveThemeColorDefault;
+
+ Self.Constraints.MinWidth := 200;
+ Self.Constraints.MinHeight := 300;
+end;
+
+procedure TDelphiAIDevDBChatView.AddItemsPopupMenuQuestion;
+begin
+ FPopupMenuQuestions
+ .ProcessClickInItem(DoProcessClickInItemDefaultQuestions)
+ .CreateMenus(pMenuQuestions);
+end;
+
+procedure TDelphiAIDevDBChatView.DoProcessClickInItemDefaultQuestions(ACodeOnly: Boolean; AQuestion: string);
+begin
+ if ACodeOnly then
+ btnCodeOnly.ImageIndex := CodeOnly_ImageIndex_ON
+ else
+ btnCodeOnly.ImageIndex := CodeOnly_ImageIndex_OFF;
+
+ mmQuestion.Lines.Add(AQuestion);
+end;
+
+procedure TDelphiAIDevDBChatView.mmQuestionChange(Sender: TObject);
+begin
+ if mmQuestion.Lines.Count >= 7 then
+ mmQuestion.ScrollBars := ssVertical
+ else
+ mmQuestion.ScrollBars := ssNone;
+end;
+
+procedure TDelphiAIDevDBChatView.mmQuestionKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState);
+begin
+ if (ssCtrl in Shift)and(Key = VK_RETURN) then
+ begin
+ btnSend.Click;
+ Key := 0;
+ end
+end;
+
+procedure TDelphiAIDevDBChatView.mmQuestionKeyUp(Sender: TObject; var Key: Word; Shift: TShiftState);
+begin
+ if (ssCtrl in Shift) and (Key = 65) then
+ begin
+ mmQuestion.SelectAll;
+ Key := 0;
+ end;
+end;
+
+procedure TDelphiAIDevDBChatView.FormResize(Sender: TObject);
+var
+ LWidth: Integer;
+const
+ CAPTION_UseCurrentUnitCode = 'Use current unit code in query';
+ CAPTION_CodeOnly = 'SQL only';
+ CAPTION_DefaultsQuestions = 'Questions';
+begin
+ if Self.Width > 620 then
+ begin
+ btnUseCurrentUnitCode.Caption := CAPTION_UseCurrentUnitCode;
+ btnUseCurrentUnitCode.Width := FbtnUseCurrentUnitCodeWidth;
+ btnUseCurrentUnitCode.ImageAlignment := TImageAlignment.iaLeft;
+
+ btnCodeOnly.Caption := CAPTION_CodeOnly;
+ btnCodeOnly.Width := FbtnCodeOnlyWidth;
+ btnCodeOnly.ImageAlignment := TImageAlignment.iaLeft;
+
+ btnDefaultsQuestions.Caption := CAPTION_DefaultsQuestions;
+ btnDefaultsQuestions.Width := FbtnDefaultsQuestionsWidth;
+ btnDefaultsQuestions.ImageAlignment := TImageAlignment.iaLeft;
+ end
+ else
+ begin
+ LWidth := btnSend.Width;
+ if Self.Width < 405 then
+ LWidth := 24;
+
+ btnUseCurrentUnitCode.Caption := '';
+ btnUseCurrentUnitCode.Width := LWidth;
+ btnUseCurrentUnitCode.ImageAlignment := TImageAlignment.iaCenter;
+
+ btnCodeOnly.Caption := '';
+ btnCodeOnly.Width := LWidth;
+ btnCodeOnly.ImageAlignment := TImageAlignment.iaCenter;
+
+ btnDefaultsQuestions.Caption := '';
+ btnDefaultsQuestions.Width := LWidth;
+ btnDefaultsQuestions.ImageAlignment := TImageAlignment.iaCenter;
+ end;
+end;
+
+procedure TDelphiAIDevDBChatView.FillMemoReturnWithFile;
+begin
+ if FileExists(TUtils.GetPathFileChatDB) then
+ mmReturn.Lines.LoadFromFile(TUtils.GetPathFileChatDB)
+end;
+
+procedure TDelphiAIDevDBChatView.SaveMemoReturnInFile;
+begin
+ mmReturn.Lines.SaveToFile(TUtils.GetPathFileChatDB);
+end;
+
+procedure TDelphiAIDevDBChatView.SelectAll1Click(Sender: TObject);
+begin
+ mmReturn.SelectAll;
+end;
+
+procedure TDelphiAIDevDBChatView.cBoxSizeFontKeyPress(Sender: TObject; var Key: Char);
+begin
+ if not CharInSet(Key, ['0'..'9', #8]) then
+ Key := #0;
+end;
+
+procedure TDelphiAIDevDBChatView.Cut1Click(Sender: TObject);
+begin
+ mmReturn.CutToClipboard;
+end;
+
+procedure TDelphiAIDevDBChatView.Copy1Click(Sender: TObject);
+begin
+ mmReturn.CopyToClipboard;
+end;
+
+procedure TDelphiAIDevDBChatView.Paste1Click(Sender: TObject);
+begin
+ mmReturn.PasteFromClipboard;
+end;
+
+procedure TDelphiAIDevDBChatView.btnUseCurrentUnitCodeClick(Sender: TObject);
+begin
+ Self.ChangeUseCurrentUnitCode;
+end;
+
+procedure TDelphiAIDevDBChatView.btnDefaultsQuestionsClick(Sender: TObject);
+begin
+ pMenuQuestions.Popup(Mouse.CursorPos.X, Mouse.CursorPos.Y);
+end;
+
+procedure TDelphiAIDevDBChatView.ChangeUseCurrentUnitCode;
+begin
+ if btnUseCurrentUnitCode.ImageIndex = UseCurrentUnitCode_ImageIndex_OFF then
+ btnUseCurrentUnitCode.ImageIndex := UseCurrentUnitCode_ImageIndex_ON
+ else
+ btnUseCurrentUnitCode.ImageIndex := UseCurrentUnitCode_ImageIndex_OFF;
+end;
+
+procedure TDelphiAIDevDBChatView.btnCodeOnlyClick(Sender: TObject);
+begin
+ Self.ChangeCodeOnly;
+end;
+
+procedure TDelphiAIDevDBChatView.ChangeCodeOnly;
+begin
+ if btnCodeOnly.ImageIndex = CodeOnly_ImageIndex_OFF then
+ btnCodeOnly.ImageIndex := CodeOnly_ImageIndex_ON
+ else
+ btnCodeOnly.ImageIndex := CodeOnly_ImageIndex_OFF;
+end;
+
+procedure TDelphiAIDevDBChatView.ReloadDatabases;
+var
+ LGuidDatabaseDefault: string;
+begin
+ LGuidDatabaseDefault := TDelphiAIDevProjectsModel.New.ReadFilePathCurrentProject.GuidDatabaseDefault;
+
+ TDelphiAIDevDBUtils.FillComboBoxDataBases(cBoxDatabases, LGuidDatabaseDefault);
+ Self.FillDateLastReferences;
+end;
+
+procedure TDelphiAIDevDBChatView.AddResponseSimple(const AString: string);
+begin
+ Self.Last;
+ mmReturn.SelAttributes.Color := TUtilsOTA.ActiveThemeColorDefault;
+ mmReturn.SelAttributes.Style := [];
+ mmReturn.Lines.Add(AString);
+ Self.Last;
+end;
+
+procedure TDelphiAIDevDBChatView.WaitingFormON;
+begin
+ pnWait.Visible := False;
+ TUtils.CenterPanel(pnWait, mmReturn);
+ pnWait.Visible := True;
+end;
+
+procedure TDelphiAIDevDBChatView.WordWrap1Click(Sender: TObject);
+begin
+ Self.ProcessWordWrap;
+end;
+
+procedure TDelphiAIDevDBChatView.ProcessWordWrap;
+begin
+ if WordWrap1.Checked then
+ mmReturn.ScrollBars := ssVertical
+ else
+ mmReturn.ScrollBars := ssBoth;
+end;
+
+procedure TDelphiAIDevDBChatView.WaitingFormOFF;
+begin
+ pnWait.Visible := False;
+end;
+
+procedure TDelphiAIDevDBChatView.Last;
+begin
+ SendMessage(mmReturn.Handle, WM_VSCROLL, SB_BOTTOM, 0);
+end;
+
+procedure TDelphiAIDevDBChatView.lbCurrentAIClick(Sender: TObject);
+begin
+ pMenuCurrentAI.Popup(Mouse.CursorPos.X, Mouse.CursorPos.Y);
+end;
+
+function TDelphiAIDevDBChatView.GetSelectedTextOrAllFromReturn: string;
+begin
+ if not mmReturn.SelText.Trim.IsEmpty then
+ Result := mmReturn.SelText
+ else
+ Result := mmReturn.Lines.Text;
+end;
+
+function TDelphiAIDevDBChatView.GetSelectedTextOrAllOrAbort: string;
+begin
+ Result := Self.GetSelectedTextOrAllFromReturn;
+ if Result.Trim.IsEmpty then
+ TUtils.ShowMsgAndAbort('There is no data to be used in this action');
+end;
+
+procedure TDelphiAIDevDBChatView.btnInsertAtCursorClick(Sender: TObject);
+var
+ LText: string;
+begin
+ LText := Self.GetSelectedTextOrAllOrAbort;
+ TUtilsOTA.DeleteBlockTextSelectedInEditor;
+ TUtilsOTA.InsertBlockTextIntoEditor(LText);
+end;
+
+procedure TDelphiAIDevDBChatView.btnCopyClick(Sender: TObject);
+var
+ LText: string;
+begin
+ LText := Self.GetSelectedTextOrAllOrAbort;
+ Clipboard.AsText := LText;
+end;
+
+procedure TDelphiAIDevDBChatView.btnCreateNewUnitClick(Sender: TObject);
+var
+ LText: string;
+begin
+ LText := Self.GetSelectedTextOrAllOrAbort;
+ TDelphiAIDevModuleCreator.New.CreateNewUnit(LText);
+end;
+
+procedure TDelphiAIDevDBChatView.SaveContentToFile1Click(Sender: TObject);
+var
+ LFileName: string;
+begin
+ Self.GetSelectedTextOrAllOrAbort;
+
+ LFileName := TUtils.GetFileName('rtf');
+ mmReturn.Lines.SaveToFile(LFileName);
+ TUtils.ShowV('File saved successfully');
+end;
+
+procedure TDelphiAIDevDBChatView.Clear1Click(Sender: TObject);
+begin
+ mmReturn.Lines.Clear;
+end;
+
+procedure TDelphiAIDevDBChatView.btnMoreActionsClick(Sender: TObject);
+begin
+ pMenuMoreActions.Popup(Mouse.CursorPos.X, Mouse.CursorPos.Y);
+end;
+
+procedure TDelphiAIDevDBChatView.InitializeRichEditReturn;
+begin
+ mmReturn.SelAttributes.Name := 'Courier New';
+ mmReturn.SelAttributes.Size := 10;
+
+ if TUtilsOTA.ActiveThemeIsDark then
+ begin
+ mmReturn.Color := $004A4136;
+ mmReturn.SelAttributes.Color := clWhite;
+ end
+ else
+ begin
+ mmReturn.Color := clWindow;
+ mmReturn.SelAttributes.Color := clWindowText;
+ end;
+end;
+
+procedure TDelphiAIDevDBChatView.pMenuCurrentAIPopup(Sender: TObject);
+begin
+ Gemini1.Checked := False;
+ ChatGPT1.Checked := False;
+ Groq1.Checked := False;
+ Mistral1.Checked := False;
+ Ollama1.Checked := False;
+ case FSettings.AIDefault of
+ TC4DAiAvailable.Gemini:
+ Gemini1.Checked := True;
+ TC4DAiAvailable.OpenAI:
+ ChatGPT1.Checked := True;
+ TC4DAiAvailable.Groq:
+ Groq1.Checked := True;
+ TC4DAiAvailable.Mistral:
+ Mistral1.Checked := True;
+ TC4DAiAvailable.Ollama:
+ Ollama1.Checked := True;
+ end;
+end;
+
+procedure TDelphiAIDevDBChatView.ConfLabelCurrentAI;
+begin
+ lbCurrentAI.Caption := FSettings.AIDefault.ToString;
+
+ case FSettings.AIDefault of
+ TC4DAiAvailable.Gemini:
+ lbCurrentAI.Hint := FSettings.ModelGemini;
+ TC4DAiAvailable.OpenAI:
+ lbCurrentAI.Hint := FSettings.ModelOpenAI;
+ TC4DAiAvailable.Groq:
+ lbCurrentAI.Hint := FSettings.ModelGroq;
+ TC4DAiAvailable.Mistral:
+ lbCurrentAI.Hint := FSettings.ModelMistral;
+ TC4DAiAvailable.Ollama:
+ lbCurrentAI.Hint := FSettings.ModelOllama;
+ end;
+
+ lbCurrentAI.Repaint;
+ Self.Repaint;
+end;
+
+procedure TDelphiAIDevDBChatView.Gemini1Click(Sender: TObject);
+var
+ LTag: Integer;
+begin
+ //*SEVERAL
+ LTag := TMenuItem(Sender).Tag;
+ if not(LTag in [0, 1, 2, 3, 4])then
+ Exit;
+
+ FSettings.AIDefault := TC4DAiAvailable(LTag);
+ FSettings.SaveData;
+ Self.ConfLabelCurrentAI;
+end;
+
+procedure TDelphiAIDevDBChatView.btnCleanAllClick(Sender: TObject);
+begin
+ mmQuestion.Lines.Clear;
+ mmReturn.Lines.Clear;
+end;
+
+procedure TDelphiAIDevDBChatView.cBoxDatabasesClick(Sender: TObject);
+begin
+ Self.FillDateLastReferences;
+end;
+
+procedure TDelphiAIDevDBChatView.FillDateLastReferences;
+begin
+ lbLastGeneration.Caption := '';
+
+ if cBoxDatabases.Items.Count <= 0 then
+ Exit;
+
+ lbLastGeneration.Caption := TUtils.DateTimeToStrEmpty(Self.GetFieldDBSelected.LastReferences);
+end;
+
+procedure TDelphiAIDevDBChatView.btnGenerateDatabaseReferenceClick(Sender: TObject);
+var
+ LView: TDelphiAIDevDBReferencesView;
+ LFields: TDelphiAIDevDBRegistersFields;
+begin
+ Self.ValidateIfDatabaseSelected;
+
+ LFields := Self.GetFieldDBSelected;
+ if LFields = nil then
+ Exit;
+
+ LView := TDelphiAIDevDBReferencesView.Create(nil);
+ try
+ LView.Fields := LFields;
+ if LView.ShowModal = mrOk then
+ Self.FillDateLastReferences;
+ finally
+ LView.Free;
+ end;
+end;
+
+procedure TDelphiAIDevDBChatView.ValidateIfDatabaseSelected;
+begin
+ if cBoxDatabases.Items.Count <= 0 then
+ TUtils.ShowMsgAndAbort('Please select a database to continue', cBoxDatabases);
+end;
+
+function TDelphiAIDevDBChatView.GetFieldDBSelected: TDelphiAIDevDBRegistersFields;
+begin
+ Self.ValidateIfDatabaseSelected;
+ Result := TDelphiAIDevDBRegistersFields(cBoxDatabases.Items.Objects[cBoxDatabases.ItemIndex]);
+end;
+
+procedure TDelphiAIDevDBChatView.btnSendClick(Sender: TObject);
+begin
+ Self.ProcessSend;
+end;
+
+procedure TDelphiAIDevDBChatView.ProcessSend;
+var
+ LTask: ITask;
+ LQuestion: string;
+begin
+ if mmQuestion.Lines.Text.Trim.IsEmpty then
+ TUtils.ShowMsgAndAbort('No questions have been added', mmQuestion);
+
+ FSettings.ValidateFillingSelectedAI;
+
+ mmReturn.Lines.Clear;
+
+ LQuestion := FSettings.LanguageQuestions.GetLanguageDefinition;
+
+ if btnUseCurrentUnitCode.ImageIndex = UseCurrentUnitCode_ImageIndex_ON then
+ LQuestion := TUtilsOTA.GetSelectedBlockOrAllCodeUnit.Trim + sLineBreak;
+
+ if btnCodeOnly.ImageIndex = CodeOnly_ImageIndex_ON then
+ LQuestion := LQuestion + FSettings.LanguageQuestions.GetMsgSQLOnly + sLineBreak;
+
+ LQuestion := LQuestion + FSettings.LanguageQuestions.GetMsgJSONIsDatabaseStructure(Self.GetFieldDBSelected.DriverID.ToString);
+ LQuestion := LQuestion + Self.GetJsonDatabase + sLineBreak;
+ LQuestion := LQuestion + FSettings.LanguageQuestions.GetMsgJSONInformedAnswerQuestion;
+ if not FSettings.DefaultPrompt.Trim.IsEmpty then
+ LQuestion := LQuestion + FSettings.DefaultPrompt + sLineBreak;
+ LQuestion := LQuestion + mmQuestion.Lines.Text;
+
+ Self.WaitingFormON;
+ LTask := TTask.Create(
+ procedure
+ begin
+ try
+ try
+ FAI.AiUse(FSettings.AIDefault).ProcessSend(LQuestion);
+ except
+ on E: Exception do
+ TThread.Synchronize(nil,
+ procedure
+ begin
+ Self.AddResponseSimple('Unable to perform processing.' + sLineBreak + TUtils.GetExceptionMessage(E));
+ Abort;
+ end);
+ end;
+
+ TThread.Synchronize(nil,
+ procedure
+ begin
+ mmReturn.Lines.BeginUpdate;
+ try
+ //Optional use of one of the following lines
+ FProcessResponse.AddResponseComplete(FAI.Response.GetContent);
+ Self.Last;
+ //Self.AddResponseSimple(FChat.Response.Text);
+ finally
+ mmReturn.Lines.EndUpdate;
+ end;
+ end);
+ finally
+ TThread.Synchronize(nil,
+ procedure
+ begin
+ Self.WaitingFormOFF;
+ end);
+ end;
+ end);
+ LTask.Start;
+end;
+
+function TDelphiAIDevDBChatView.GetJsonDatabase: string;
+var
+ LFileName: string;
+ LStringList: TStringList;
+begin
+ LFileName := TUtils.GetPathFolderMetaInfo + Self.GetFieldDBSelected.Guid + '.json';
+
+ if not FileExists(LFileName) then
+ TUtils.ShowMsgAndAbort('File with database structure not found', LFileName);
+
+ LStringList := TStringList.Create;
+ try
+ LStringList.LoadFromFile(LFileName);
+ Result := LStringList.Text;
+ finally
+ LStringList.Free;
+ end;
+end;
+
+procedure TDelphiAIDevDBChatView.btnExecuteSQLClick(Sender: TObject);
+var
+ LCommand: string;
+ LField: TDelphiAIDevDBRegistersFields;
+begin
+ Self.ValidateIfDatabaseSelected;
+
+ LCommand := Trim(mmReturn.Lines.Text);
+ if LCommand.IsEmpty then
+ TUtils.ShowMsgAndAbort('No SQL command informed');
+
+ Screen.Cursor := crHourGlass;
+ try
+ lbCount.Caption := '000000';
+ LField := Self.GetFieldDBSelected;
+
+ FConn.Configs
+ .DriverID(LField.DriverID)
+ .Host(LField.Host)
+ .UserName(LField.User)
+ .Password(LField.Password)
+ .Port(LField.Port)
+ .Database(LField.DatabaseName)
+ .VendorLib(LField.VendorLib);
+
+ try
+ if not FConn.Connection.TestConnection then
+ TUtils.ShowMsgAndAbort('Connection refused');
+ except
+ on E: exception do
+ TUtils.ShowMsgErrorAndAbort(E.Message);
+ end;
+
+ try
+ FQueryExecuteSQL.CloseClear.Add(LCommand).Open;
+ except
+ on E: Exception do
+ Self.HandleErrorExecutingSQLCommand(E);
+ end;
+
+ lbCount.Caption := FQueryExecuteSQL.RecordCountStr;
+ finally
+ Screen.Cursor := crDefault;
+ end;
+end;
+
+procedure TDelphiAIDevDBChatView.HandleErrorExecutingSQLCommand(const E: Exception);
+var
+ LCommand: string;
+ LMsg: string;
+begin
+ LCommand := Trim(mmReturn.Lines.Text).ToLower;
+ LMsg := 'Unable to execute command.';
+
+ if LCommand.Contains('insert') then
+ LMsg := LMsg + sLineBreak + 'Insert commands are blocked';
+
+ if LCommand.Contains('update') then
+ LMsg := LMsg + sLineBreak + 'Update commands are blocked';
+
+ if LCommand.Contains('delete') then
+ LMsg := LMsg + sLineBreak + 'Delete commands are blocked';
+
+ if LCommand.Contains('drop') then
+ LMsg := LMsg + sLineBreak + 'Drop commands are blocked';
+
+ if LCommand.Contains('create') then
+ LMsg := LMsg + sLineBreak + 'Create commands are blocked';
+
+ if LMsg.Trim.IsEmpty then
+ LMsg := LMsg + sLineBreak + E.Message;
+
+ TUtils.ShowMsgErrorAndAbort(LMsg.Trim, E.Message);
+end;
+
+procedure TDelphiAIDevDBChatView.CopyCurrentColumn1Click(Sender: TObject);
+begin
+ TUtilsDBGrids.DBGridToClipboardCurrentColumn(DBGrid1);
+end;
+
+procedure TDelphiAIDevDBChatView.CopyCurrentLine1Click(Sender: TObject);
+begin
+ TUtilsDBGrids.DBGridToClipboardCurrentLine(DBGrid1);
+end;
+
+procedure TDelphiAIDevDBChatView.CopyAllGridDataClick(Sender: TObject);
+begin
+ TUtilsDBGrids.DBGridToClipboardAll(DBGrid1);
+end;
+
+procedure TDelphiAIDevDBChatView.SaveAllGridDataAsCSVClick(Sender: TObject);
+begin
+ if DataSource1.DataSet.IsEmpty then
+ TUtils.ShowMsgAndAbort('There is no data to be exported');
+
+ TUtilsDBGrids.DBGridToCSV(DBGrid1);
+ TUtils.ShowV('File saved successfully');
+end;
+
+procedure TDelphiAIDevDBChatView.SaveAllGridDataAsTXTClick(Sender: TObject);
+begin
+ if DataSource1.DataSet.IsEmpty then
+ TUtils.ShowMsgAndAbort('There is no data to be exported');
+
+ TUtilsDBGrids.DBGridToTxt(DBGrid1);
+ TUtils.ShowV('File saved successfully');
+end;
+
+procedure TDelphiAIDevDBChatView.DBGrid1TitleClick(Column: TColumn);
+var
+ LCampo: string;
+ LOrdem: string;
+begin
+ if DataSource1.DataSet.IsEmpty then
+ Exit;
+
+ LCampo := Column.FieldName.Trim;
+ if (LCampo.IsEmpty) or (Column.Field.FieldKind = fkCalculated) then
+ Exit;
+
+ LOrdem := LCampo + ':D';
+ if FQueryExecuteSQL.IndexFieldNames.Contains(':D') then
+ LOrdem := LCampo;
+
+ FQueryExecuteSQL.IndexFieldNames(LOrdem);
+end;
+
+initialization
+
+finalization
+ Unregister;
+
+end.
diff --git a/Src/DB/References/DelphiAIDev.DB.References.View.dfm b/Src/DB/References/DelphiAIDev.DB.References.View.dfm
new file mode 100644
index 0000000..fd6623d
--- /dev/null
+++ b/Src/DB/References/DelphiAIDev.DB.References.View.dfm
@@ -0,0 +1,136 @@
+object DelphiAIDevDBReferencesView: TDelphiAIDevDBReferencesView
+ Left = 0
+ Top = 0
+ BorderIcons = [biSystemMenu]
+ Caption = 'IA Developer - Databases References'
+ ClientHeight = 161
+ ClientWidth = 295
+ Color = clBtnFace
+ Font.Charset = DEFAULT_CHARSET
+ Font.Color = clWindowText
+ Font.Height = -11
+ Font.Name = 'Tahoma'
+ Font.Style = []
+ KeyPreview = True
+ OldCreateOrder = False
+ Position = poScreenCenter
+ OnCreate = FormCreate
+ OnKeyDown = FormKeyDown
+ OnShow = FormShow
+ PixelsPerInch = 96
+ TextHeight = 13
+ object Bevel2: TBevel
+ AlignWithMargins = True
+ Left = 0
+ Top = 122
+ Width = 295
+ Height = 1
+ Margins.Left = 0
+ Margins.Top = 0
+ Margins.Right = 0
+ Align = alBottom
+ Shape = bsTopLine
+ ExplicitLeft = -87
+ ExplicitTop = 264
+ ExplicitWidth = 665
+ end
+ object pnButtons: TPanel
+ Left = 0
+ Top = 126
+ Width = 295
+ Height = 35
+ Align = alBottom
+ BevelEdges = [beLeft, beRight, beBottom]
+ BevelOuter = bvNone
+ Padding.Left = 2
+ Padding.Top = 2
+ Padding.Right = 2
+ Padding.Bottom = 2
+ ParentBackground = False
+ TabOrder = 0
+ object btnGenerate: TButton
+ AlignWithMargins = True
+ Left = 67
+ Top = 2
+ Width = 110
+ Height = 31
+ Cursor = crHandPoint
+ Margins.Left = 0
+ Margins.Top = 0
+ Margins.Bottom = 0
+ Align = alRight
+ Caption = 'Generate'
+ TabOrder = 0
+ OnClick = btnGenerateClick
+ end
+ object btnClose: TButton
+ AlignWithMargins = True
+ Left = 180
+ Top = 2
+ Width = 110
+ Height = 31
+ Cursor = crHandPoint
+ Margins.Left = 0
+ Margins.Top = 0
+ Margins.Bottom = 0
+ Align = alRight
+ Caption = 'Close'
+ TabOrder = 1
+ OnClick = btnCloseClick
+ end
+ end
+ object pnBody: TPanel
+ Left = 0
+ Top = 0
+ Width = 295
+ Height = 122
+ Align = alClient
+ BevelOuter = bvNone
+ ParentBackground = False
+ TabOrder = 1
+ object Bevel1: TBevel
+ AlignWithMargins = True
+ Left = 0
+ Top = 118
+ Width = 295
+ Height = 1
+ Margins.Left = 0
+ Margins.Top = 0
+ Margins.Right = 0
+ Align = alBottom
+ Shape = bsTopLine
+ ExplicitTop = 444
+ ExplicitWidth = 676
+ end
+ object Label1: TLabel
+ Left = 37
+ Top = 22
+ Width = 79
+ Height = 13
+ Caption = 'Last generation:'
+ end
+ object lbLastGeneration: TLabel
+ Left = 122
+ Top = 22
+ Width = 81
+ Height = 13
+ Caption = 'lbLastGeneration'
+ end
+ object ckAddFieldSize: TCheckBox
+ Left = 37
+ Top = 53
+ Width = 99
+ Height = 17
+ Caption = 'Add Field Length'
+ TabOrder = 0
+ end
+ object ckCompressData: TCheckBox
+ Left = 37
+ Top = 78
+ Width = 93
+ Height = 17
+ Caption = 'Compress Data'
+ TabOrder = 1
+ end
+ end
+end
diff --git a/Src/DB/References/DelphiAIDev.DB.References.View.pas b/Src/DB/References/DelphiAIDev.DB.References.View.pas
new file mode 100644
index 0000000..03eb343
--- /dev/null
+++ b/Src/DB/References/DelphiAIDev.DB.References.View.pas
@@ -0,0 +1,113 @@
+unit DelphiAIDev.DB.References.View;
+
+interface
+
+uses
+ Winapi.Windows,
+ Winapi.Messages,
+ System.SysUtils,
+ System.Variants,
+ System.Classes,
+ Vcl.Graphics,
+ Vcl.Controls,
+ Vcl.Forms,
+ Vcl.Dialogs,
+ Vcl.StdCtrls,
+ Vcl.ExtCtrls,
+ DelphiAIDev.Types,
+ DelphiAIDev.DB.Registers.Fields,
+ DelphiAIDev.MetaInfo;
+
+type
+ TDelphiAIDevDBReferencesView = class(TForm)
+ Bevel2: TBevel;
+ pnButtons: TPanel;
+ btnGenerate: TButton;
+ btnClose: TButton;
+ pnBody: TPanel;
+ Bevel1: TBevel;
+ Label1: TLabel;
+ lbLastGeneration: TLabel;
+ ckAddFieldSize: TCheckBox;
+ ckCompressData: TCheckBox;
+ procedure FormCreate(Sender: TObject);
+ procedure FormShow(Sender: TObject);
+ procedure btnCloseClick(Sender: TObject);
+ procedure btnGenerateClick(Sender: TObject);
+ procedure FormKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState);
+ private
+ FFields: TDelphiAIDevDBRegistersFields;
+ procedure FillScreenFields;
+ public
+ property Fields: TDelphiAIDevDBRegistersFields read FFields write FFields;
+ end;
+
+implementation
+
+uses
+ DelphiAIDev.Consts,
+ DelphiAIDev.Utils,
+ DelphiAIDev.Utils.OTA;
+
+{$R *.dfm}
+
+procedure TDelphiAIDevDBReferencesView.FormCreate(Sender: TObject);
+begin
+ Self.ModalResult := mrCancel;
+ TUtilsOTA.IDEThemingAll(TDelphiAIDevDBReferencesView, Self);
+end;
+
+procedure TDelphiAIDevDBReferencesView.FormKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState);
+begin
+ case Key of
+ VK_F4:
+ if ssAlt in Shift then
+ Key := 0;
+ VK_ESCAPE:
+ if Shift = [] then
+ btnClose.Click;
+ end;
+end;
+
+procedure TDelphiAIDevDBReferencesView.FormShow(Sender: TObject);
+begin
+ Self.FillScreenFields;
+end;
+
+procedure TDelphiAIDevDBReferencesView.FillScreenFields;
+begin
+ lbLastGeneration.Caption := 'Never';
+ if FFields.LastReferences > 0 then
+ lbLastGeneration.Caption := DateTimeToStr(FFields.LastReferences);
+end;
+
+procedure TDelphiAIDevDBReferencesView.btnGenerateClick(Sender: TObject);
+var
+ LMetaInfo: TDelphiAIDevMetaInfo;
+begin
+ Screen.Cursor := crHourGlass;
+ try
+ LMetaInfo := TDelphiAIDevMetaInfo.Create(FFields);
+ try
+ LMetaInfo.AddFieldLength := ckAddFieldSize.Checked;
+ LMetaInfo.CompressData := ckCompressData.Checked;
+ LMetaInfo.Process;
+ finally
+ LMetaInfo.Free;
+ end;
+ finally
+ Screen.Cursor := crDefault;
+ end;
+
+ Self.Close;
+ Self.ModalResult := mrOk;
+end;
+
+procedure TDelphiAIDevDBReferencesView.btnCloseClick(Sender: TObject);
+begin
+ Self.Close;
+ Self.ModalResult := mrCancel;
+end;
+
+end.
+
diff --git a/Src/DB/Registers/DelphiAIDev.DB.Registers.AddEdit.View.dfm b/Src/DB/Registers/DelphiAIDev.DB.Registers.AddEdit.View.dfm
new file mode 100644
index 0000000..db50f99
--- /dev/null
+++ b/Src/DB/Registers/DelphiAIDev.DB.Registers.AddEdit.View.dfm
@@ -0,0 +1,287 @@
+object DelphiAIDevDBRegistersAddEditView: TDelphiAIDevDBRegistersAddEditView
+ Left = 0
+ Top = 0
+ BorderIcons = [biSystemMenu]
+ Caption = 'IA Developer - Databases - [action]'
+ ClientHeight = 303
+ ClientWidth = 665
+ Color = clBtnFace
+ Font.Charset = DEFAULT_CHARSET
+ Font.Color = clWindowText
+ Font.Height = -11
+ Font.Name = 'Tahoma'
+ Font.Style = []
+ KeyPreview = True
+ OldCreateOrder = False
+ Position = poScreenCenter
+ OnCreate = FormCreate
+ OnKeyDown = FormKeyDown
+ OnShow = FormShow
+ PixelsPerInch = 96
+ TextHeight = 13
+ object Bevel2: TBevel
+ AlignWithMargins = True
+ Left = 0
+ Top = 264
+ Width = 665
+ Height = 1
+ Margins.Left = 0
+ Margins.Top = 0
+ Margins.Right = 0
+ Align = alBottom
+ Shape = bsTopLine
+ ExplicitLeft = -5
+ ExplicitTop = 476
+ ExplicitWidth = 676
+ end
+ object Panel1: TPanel
+ Left = 0
+ Top = 268
+ Width = 665
+ Height = 35
+ Align = alBottom
+ BevelEdges = [beLeft, beRight, beBottom]
+ BevelOuter = bvNone
+ Padding.Left = 2
+ Padding.Top = 2
+ Padding.Right = 2
+ Padding.Bottom = 2
+ ParentBackground = False
+ TabOrder = 1
+ object btnConfirm: TButton
+ AlignWithMargins = True
+ Left = 437
+ Top = 2
+ Width = 110
+ Height = 31
+ Cursor = crHandPoint
+ Margins.Left = 0
+ Margins.Top = 0
+ Margins.Bottom = 0
+ Align = alRight
+ Caption = 'Confirm'
+ TabOrder = 0
+ OnClick = btnConfirmClick
+ end
+ object btnClose: TButton
+ AlignWithMargins = True
+ Left = 550
+ Top = 2
+ Width = 110
+ Height = 31
+ Cursor = crHandPoint
+ Margins.Left = 0
+ Margins.Top = 0
+ Margins.Bottom = 0
+ Align = alRight
+ Caption = 'Close'
+ TabOrder = 1
+ OnClick = btnCloseClick
+ end
+ object btnTestConnection: TButton
+ AlignWithMargins = True
+ Left = 2
+ Top = 2
+ Width = 110
+ Height = 31
+ Cursor = crHandPoint
+ Margins.Left = 0
+ Margins.Top = 0
+ Margins.Bottom = 0
+ Align = alLeft
+ Caption = 'Test Connection'
+ TabOrder = 2
+ OnClick = btnTestConnectionClick
+ end
+ end
+ object Panel9: TPanel
+ Left = 0
+ Top = 0
+ Width = 665
+ Height = 264
+ Align = alClient
+ BevelOuter = bvNone
+ ParentBackground = False
+ TabOrder = 0
+ object Bevel1: TBevel
+ AlignWithMargins = True
+ Left = 0
+ Top = 260
+ Width = 665
+ Height = 1
+ Margins.Left = 0
+ Margins.Top = 0
+ Margins.Right = 0
+ Align = alBottom
+ Shape = bsTopLine
+ ExplicitTop = 444
+ ExplicitWidth = 676
+ end
+ object Label2: TLabel
+ Left = 234
+ Top = 25
+ Width = 43
+ Height = 13
+ Caption = 'Driver ID'
+ end
+ object Label3: TLabel
+ Left = 31
+ Top = 25
+ Width = 53
+ Height = 13
+ Caption = 'Description'
+ end
+ object Label1: TLabel
+ Left = 437
+ Top = 25
+ Width = 22
+ Height = 13
+ Caption = 'Host'
+ end
+ object Label5: TLabel
+ Left = 31
+ Top = 69
+ Width = 22
+ Height = 13
+ Caption = 'User'
+ end
+ object Label6: TLabel
+ Left = 234
+ Top = 69
+ Width = 46
+ Height = 13
+ Caption = 'Password'
+ end
+ object Label7: TLabel
+ Left = 437
+ Top = 69
+ Width = 20
+ Height = 13
+ Caption = 'Port'
+ end
+ object Label4: TLabel
+ Left = 31
+ Top = 119
+ Width = 46
+ Height = 13
+ Caption = 'Database'
+ end
+ object Label8: TLabel
+ Left = 31
+ Top = 164
+ Width = 68
+ Height = 13
+ Caption = 'VendorLib (dll)'
+ end
+ object lbAddLocalDatabase: TLabel
+ Left = 465
+ Top = 25
+ Width = 99
+ Height = 13
+ Cursor = crHandPoint
+ Caption = '[Add local database]'
+ OnClick = lbAddLocalDatabaseClick
+ end
+ object cBoxDriverID: TComboBox
+ Left = 234
+ Top = 41
+ Width = 200
+ Height = 21
+ Style = csDropDownList
+ TabOrder = 1
+ end
+ object edtDescription: TEdit
+ Left = 31
+ Top = 41
+ Width = 200
+ Height = 21
+ TabOrder = 0
+ end
+ object edtHost: TEdit
+ Left = 437
+ Top = 41
+ Width = 200
+ Height = 21
+ TabOrder = 2
+ end
+ object edtUser: TEdit
+ Left = 31
+ Top = 85
+ Width = 200
+ Height = 21
+ TabOrder = 3
+ end
+ object edtPassword: TEdit
+ Left = 234
+ Top = 85
+ Width = 164
+ Height = 21
+ PasswordChar = '*'
+ TabOrder = 4
+ end
+ object edtPort: TEdit
+ Left = 437
+ Top = 85
+ Width = 200
+ Height = 21
+ NumbersOnly = True
+ TabOrder = 5
+ end
+ object edtDatabase: TEdit
+ Left = 31
+ Top = 135
+ Width = 581
+ Height = 21
+ TabOrder = 6
+ end
+ object ckVisible: TCheckBox
+ Left = 31
+ Top = 212
+ Width = 53
+ Height = 17
+ Cursor = crHandPoint
+ Caption = 'Visible'
+ TabOrder = 8
+ end
+ object edtPasswordView: TButton
+ Left = 400
+ Top = 84
+ Width = 34
+ Height = 23
+ Cursor = crHandPoint
+ Caption = 'View'
+ TabOrder = 9
+ TabStop = False
+ OnClick = edtPasswordViewClick
+ end
+ object btnVendorLibSearch: TButton
+ Left = 613
+ Top = 179
+ Width = 24
+ Height = 23
+ Cursor = crHandPoint
+ Caption = '...'
+ TabOrder = 10
+ TabStop = False
+ OnClick = btnVendorLibSearchClick
+ end
+ object edtVendorLib: TEdit
+ Left = 31
+ Top = 180
+ Width = 581
+ Height = 21
+ TabOrder = 7
+ end
+ object btnDatabaseSearch: TButton
+ Left = 613
+ Top = 134
+ Width = 24
+ Height = 23
+ Cursor = crHandPoint
+ Caption = '...'
+ TabOrder = 11
+ TabStop = False
+ OnClick = btnDatabaseSearchClick
+ end
+ end
+end
diff --git a/Src/DB/Registers/DelphiAIDev.DB.Registers.AddEdit.View.pas b/Src/DB/Registers/DelphiAIDev.DB.Registers.AddEdit.View.pas
new file mode 100644
index 0000000..d3436a1
--- /dev/null
+++ b/Src/DB/Registers/DelphiAIDev.DB.Registers.AddEdit.View.pas
@@ -0,0 +1,220 @@
+unit DelphiAIDev.DB.Registers.AddEdit.View;
+
+interface
+
+uses
+ Winapi.Windows,
+ System.SysUtils,
+ System.Classes,
+ Vcl.Controls,
+ Vcl.Forms,
+ Vcl.StdCtrls,
+ Vcl.ExtCtrls,
+ Vcl.Menus,
+ Vcl.ComCtrls,
+ DelphiAIDev.Types,
+ DelphiAIDev.DB.Registers.Fields,
+ C4D.Conn;
+
+type
+ TDelphiAIDevDBRegistersAddEditView = class(TForm)
+ Panel1: TPanel;
+ btnConfirm: TButton;
+ btnClose: TButton;
+ Panel9: TPanel;
+ Bevel1: TBevel;
+ Bevel2: TBevel;
+ Label2: TLabel;
+ cBoxDriverID: TComboBox;
+ Label3: TLabel;
+ edtDescription: TEdit;
+ Label1: TLabel;
+ edtHost: TEdit;
+ Label5: TLabel;
+ edtUser: TEdit;
+ Label6: TLabel;
+ edtPassword: TEdit;
+ Label7: TLabel;
+ edtPort: TEdit;
+ Label4: TLabel;
+ edtDatabase: TEdit;
+ Label8: TLabel;
+ ckVisible: TCheckBox;
+ lbAddLocalDatabase: TLabel;
+ edtPasswordView: TButton;
+ btnTestConnection: TButton;
+ btnVendorLibSearch: TButton;
+ edtVendorLib: TEdit;
+ btnDatabaseSearch: TButton;
+ procedure btnCloseClick(Sender: TObject);
+ procedure btnConfirmClick(Sender: TObject);
+ procedure FormKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState);
+ procedure FormShow(Sender: TObject);
+ procedure FormCreate(Sender: TObject);
+ procedure lbAddLocalDatabaseClick(Sender: TObject);
+ procedure edtPasswordViewClick(Sender: TObject);
+ procedure btnTestConnectionClick(Sender: TObject);
+ procedure btnVendorLibSearchClick(Sender: TObject);
+ procedure btnDatabaseSearchClick(Sender: TObject);
+ private
+ FFields: TDelphiAIDevDBRegistersFields;
+ procedure FillcBoxDriverID;
+ procedure FillScreenFields;
+ procedure ValidateFillingFields;
+ public
+ property Fields: TDelphiAIDevDBRegistersFields read FFields write FFields;
+ end;
+
+implementation
+
+uses
+ DelphiAIDev.Consts,
+ DelphiAIDev.Utils,
+ DelphiAIDev.Utils.OTA,
+ DelphiAIDev.DB.Registers.Model;
+
+{$R *.dfm}
+
+procedure TDelphiAIDevDBRegistersAddEditView.FormCreate(Sender: TObject);
+begin
+ Self.ModalResult := mrCancel;
+ TUtilsOTA.IDEThemingAll(TDelphiAIDevDBRegistersAddEditView, Self);
+ Self.FillcBoxDriverID;
+end;
+
+procedure TDelphiAIDevDBRegistersAddEditView.FormShow(Sender: TObject);
+begin
+ Self.FillScreenFields;
+ edtDescription.SetFocus;
+end;
+
+procedure TDelphiAIDevDBRegistersAddEditView.FillcBoxDriverID;
+begin
+ cBoxDriverID.Items.Clear;
+ TUtils.DriverIDFillItemsTStrings(cBoxDriverID.Items);
+end;
+
+procedure TDelphiAIDevDBRegistersAddEditView.lbAddLocalDatabaseClick(Sender: TObject);
+begin
+ edtHost.Text := 'localhost';
+end;
+
+procedure TDelphiAIDevDBRegistersAddEditView.FillScreenFields;
+begin
+ cBoxDriverID.ItemIndex := cBoxDriverID.Items.IndexOf(FFields.DriverID.ToString);
+ edtDescription.Text := FFields.Description;
+ edtHost.Text := FFields.Host;
+ edtUser.Text := FFields.User;
+ edtPassword.Text := FFields.Password;
+ edtPort.Text := FFields.Port.ToString;
+ edtDatabase.Text := FFields.DatabaseName;
+ edtVendorLib.Text := FFields.VendorLib;
+ ckVisible.Checked := FFields.Visible;
+end;
+
+procedure TDelphiAIDevDBRegistersAddEditView.btnCloseClick(Sender: TObject);
+begin
+ Self.Close;
+ Self.ModalResult := mrCancel;
+end;
+
+procedure TDelphiAIDevDBRegistersAddEditView.btnConfirmClick(Sender: TObject);
+begin
+ Self.ValidateFillingFields;
+
+ FFields.DriverID := TUtils.StrToDriverID(cBoxDriverID.Text);
+ FFields.Description := edtDescription.Text;
+ FFields.Host := edtHost.Text;
+ FFields.User := edtUser.Text;
+ FFields.Password := edtPassword.Text;
+ FFields.Port := StrToIntDef(edtPort.Text, 0);
+ FFields.DatabaseName := edtDatabase.Text;
+ FFields.VendorLib := edtVendorLib.Text;
+ FFields.Visible := ckVisible.Checked;
+
+ TDelphiAIDevDBRegistersModel.New.SaveOrEditData(FFields);
+
+ Self.Close;
+ Self.ModalResult := mrOK;
+end;
+
+procedure TDelphiAIDevDBRegistersAddEditView.ValidateFillingFields;
+begin
+ if Trim(edtDescription.Text).IsEmpty then
+ TUtils.ShowMsgAndAbort('No informed Description', edtDescription);
+
+ if cBoxDriverID.ItemIndex < 0 then
+ TUtils.ShowMsgAndAbort('No informed Driver ID', cBoxDriverID);
+
+ if TUtils.StrToDriverID(cBoxDriverID.Text) = TC4DDriverID.None then
+ TUtils.ShowMsgAndAbort('Select a DriverID', cBoxDriverID);
+
+ if Trim(edtHost.Text).IsEmpty then
+ TUtils.ShowMsgAndAbort('No informed Host', edtHost);
+
+ if Trim(edtUser.Text).IsEmpty then
+ TUtils.ShowMsgAndAbort('No informed User', edtUser);
+
+ if Trim(edtDatabase.Text).IsEmpty then
+ TUtils.ShowMsgAndAbort('No informed Database', edtDatabase);
+end;
+
+procedure TDelphiAIDevDBRegistersAddEditView.edtPasswordViewClick(Sender: TObject);
+begin
+ if edtPassword.PasswordChar = '*' then
+ edtPassword.PasswordChar := #0
+ else
+ edtPassword.PasswordChar := '*';
+end;
+
+procedure TDelphiAIDevDBRegistersAddEditView.FormKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState);
+begin
+ case Key of
+ VK_F4:
+ if ssAlt in Shift then
+ Key := 0;
+ VK_ESCAPE:
+ if Shift = [] then
+ btnClose.Click;
+ end;
+end;
+
+procedure TDelphiAIDevDBRegistersAddEditView.btnTestConnectionClick(Sender: TObject);
+var
+ LConn: IC4DConn;
+begin
+ Screen.Cursor := crHourGlass;
+ try
+ LConn := TC4DConn.New;
+ LConn.Configs
+ .DriverID(TUtils.StrToDriverID(cBoxDriverID.Text))
+ .Host(edtHost.Text)
+ .UserName(edtUser.Text)
+ .Password(edtPassword.Text)
+ .Port(StrToIntDef(edtPort.Text, 0))
+ .Database(edtDatabase.Text)
+ .VendorLib(edtVendorLib.Text);
+
+ try
+ if LConn.Connection.TestConnection then
+ TUtils.ShowV('Connection Successful');
+ except
+ on E: exception do
+ TUtils.ShowError(E.Message);
+ end;
+ finally
+ Screen.Cursor := crDefault;
+ end;
+end;
+
+procedure TDelphiAIDevDBRegistersAddEditView.btnDatabaseSearchClick(Sender: TObject);
+begin
+ edtDatabase.Text := TUtils.SelectFile(edtDatabase.Text);
+end;
+
+procedure TDelphiAIDevDBRegistersAddEditView.btnVendorLibSearchClick(Sender: TObject);
+begin
+ edtVendorLib.Text := TUtils.SelectFile(edtVendorLib.Text);
+end;
+
+end.
diff --git a/Src/DB/Registers/DelphiAIDev.DB.Registers.Fields.pas b/Src/DB/Registers/DelphiAIDev.DB.Registers.Fields.pas
new file mode 100644
index 0000000..6e2af9c
--- /dev/null
+++ b/Src/DB/Registers/DelphiAIDev.DB.Registers.Fields.pas
@@ -0,0 +1,77 @@
+unit DelphiAIDev.DB.Registers.Fields;
+
+interface
+
+uses
+ DelphiAIDev.Types;
+
+type
+ TDelphiAIDevDBRegistersFields = class
+ private
+ FGuid: string;
+ FDriverID: TC4DDriverID;
+ FDescription: string;
+ FHost: string;
+ FUser: string;
+ FPassword: string;
+ FPort: Integer;
+ FDatabaseName: string;
+ FVisible: Boolean;
+ FVendorLib: string;
+ FLastReferences: TDateTime;
+ public
+ constructor Create;
+ procedure Clear;
+ procedure GetDataFromOtherObject(const AOtherObj: TDelphiAIDevDBRegistersFields);
+ property Guid: string read FGuid write FGuid;
+ property DriverID: TC4DDriverID read FDriverID write FDriverID;
+ property Description: string read FDescription write FDescription;
+ property Host: string read FHost write FHost;
+ property User: string read FUser write FUser;
+ property Password: string read FPassword write FPassword;
+ property Port: Integer read FPort write FPort;
+ property DatabaseName: string read FDatabaseName write FDatabaseName;
+ property Visible: Boolean read FVisible write FVisible;
+ property VendorLib: string read FVendorLib write FVendorLib;
+ property LastReferences: TDateTime read FLastReferences write FLastReferences;
+ end;
+
+implementation
+
+constructor TDelphiAIDevDBRegistersFields.Create;
+begin
+ Self.Clear;
+end;
+
+procedure TDelphiAIDevDBRegistersFields.Clear;
+begin
+ FGuid := '';
+ FDriverID := TC4DDriverID.None;
+ FDescription := '';
+ FHost := '';
+ FUser := '';
+ FPassword := '';
+ FPort := 0;
+ FDatabaseName := '';
+ FVisible := True;
+ FVendorLib := '';
+ FLastReferences := 0;
+end;
+
+procedure TDelphiAIDevDBRegistersFields.GetDataFromOtherObject(const AOtherObj: TDelphiAIDevDBRegistersFields);
+begin
+ FGuid := AOtherObj.Guid;
+ FDriverID := AOtherObj.DriverID;
+ FDescription := AOtherObj.Description;
+ FHost := AOtherObj.Host;
+ FUser := AOtherObj.User;
+ FPassword := AOtherObj.Password;
+ FPort := AOtherObj.Port;
+ FDatabaseName := AOtherObj.DatabaseName;
+ FVisible := AOtherObj.Visible;
+ FVendorLib := AOtherObj.VendorLib;
+ FLastReferences := AOtherObj.LastReferences;
+end;
+
+
+end.
diff --git a/Src/DB/Registers/DelphiAIDev.DB.Registers.Interfaces.pas b/Src/DB/Registers/DelphiAIDev.DB.Registers.Interfaces.pas
new file mode 100644
index 0000000..64ac8f0
--- /dev/null
+++ b/Src/DB/Registers/DelphiAIDev.DB.Registers.Interfaces.pas
@@ -0,0 +1,21 @@
+unit DelphiAIDev.DB.Registers.Interfaces;
+
+interface
+
+uses
+ System.SysUtils,
+ DelphiAIDev.Types,
+ DelphiAIDev.DB.Registers.Fields;
+
+type
+ IDelphiAIDevDatabasesModel = interface
+ ['{3399A776-4B23-4CFC-8992-568AE07FE065}']
+ function ReadGuid(const AGuid: string): TDelphiAIDevDBRegistersFields;
+ procedure ReadData(AProc: TProc; const AAutoFreeField: TAutoFreeField = TAutoFreeField.Yes);
+ procedure SaveOrEditData(AFields: TDelphiAIDevDBRegistersFields);
+ procedure RemoveData(const AGuid: string);
+ end;
+
+implementation
+
+end.
diff --git a/Src/DB/Registers/DelphiAIDev.DB.Registers.Model.pas b/Src/DB/Registers/DelphiAIDev.DB.Registers.Model.pas
new file mode 100644
index 0000000..8f61607
--- /dev/null
+++ b/Src/DB/Registers/DelphiAIDev.DB.Registers.Model.pas
@@ -0,0 +1,362 @@
+unit DelphiAIDev.DB.Registers.Model;
+
+interface
+
+uses
+ System.SysUtils,
+ System.Classes,
+ System.JSON,
+ Rest.JSON,
+ DelphiAIDev.Utils,
+ DelphiAIDev.Types,
+ DelphiAIDev.DB.Registers.Interfaces,
+ DelphiAIDev.DB.Registers.Fields,
+ DelphiAIDev.Utils.Crypt;
+
+type
+ TDelphiAIDevDBRegistersModel = class(TInterfacedObject, IDelphiAIDevDatabasesModel)
+ private
+ procedure SaveData(AFields: TDelphiAIDevDBRegistersFields);
+ procedure EditData(AFields: TDelphiAIDevDBRegistersFields);
+ procedure FillField(const AJSONObjItem: TJSONObject; var AField: TDelphiAIDevDBRegistersFields);
+ protected
+ function ReadGuid(const AGuid: string): TDelphiAIDevDBRegistersFields;
+ procedure ReadData(AProc: TProc; const AAutoFreeField: TAutoFreeField = TAutoFreeField.Yes);
+ procedure SaveOrEditData(AFields: TDelphiAIDevDBRegistersFields);
+ procedure RemoveData(const AGuid: string);
+ public
+ class function New: IDelphiAIDevDatabasesModel;
+ constructor Create;
+ end;
+
+implementation
+
+const
+ GUID = 'guid';
+ DRIVER_ID = 'driver_id';
+ DESCRIPTION = 'description';
+ HOST = 'host';
+ USER = 'user';
+ PASSWORD = 'password';
+ PORT = 'port';
+ DATABASE_NAME = 'database_name';
+ VENDOR_LIB = 'vendor_lib';
+ VISIBLE = 'visible';
+ LAST_REFERENCE = 'last_reference';
+
+class function TDelphiAIDevDBRegistersModel.New: IDelphiAIDevDatabasesModel;
+begin
+ Result := Self.Create;
+end;
+
+constructor TDelphiAIDevDBRegistersModel.Create;
+begin
+ //
+end;
+
+function TDelphiAIDevDBRegistersModel.ReadGuid(const AGuid: string): TDelphiAIDevDBRegistersFields;
+var
+ LStringList: TStringList;
+ LJSONObjItem: TJSONObject;
+ LJSONArray: TJsonArray;
+ i: Integer;
+begin
+ Result := TDelphiAIDevDBRegistersFields.Create;
+
+ if not FileExists(TUtils.GetPathFileJSONDatabases) then
+ Exit;
+
+ LStringList := TStringList.Create;
+ try
+ LStringList.LoadFromFile(TUtils.GetPathFileJSONDatabases);
+ LJSONArray := TJSONObject.ParseJSONValue(TEncoding.UTF8.GetBytes(LStringList.Text), 0) as TJSONArray;
+ finally
+ LStringList.Free;
+ end;
+
+ try
+ for i := 0 to Pred(LJSONArray.Count) do
+ begin
+ if not(LJSONArray.Items[i] is TJSONObject) then
+ Continue;
+
+ LJSONObjItem := LJSONArray.Items[i] as TJSONObject;
+
+ if LJSONObjItem.GetValue(GUID) = nil then
+ Continue;
+
+ if LJSONObjItem.GetValue(GUID) <> AGuid then
+ Continue;
+
+ Self.FillField(LJSONObjItem, Result);
+ Break;
+ end;
+ finally
+ LJSONArray.Free;
+ end;
+end;
+
+procedure TDelphiAIDevDBRegistersModel.FillField(const AJSONObjItem: TJSONObject;
+ var AField: TDelphiAIDevDBRegistersFields);
+begin
+ AField.Clear;
+ AField.Guid := AJSONObjItem.GetValue(GUID);
+
+ if AJSONObjItem.GetValue(DRIVER_ID) <> nil then
+ AField.DriverID := TC4DDriverID(AJSONObjItem.GetValue(DRIVER_ID));
+
+ if AJSONObjItem.GetValue(DESCRIPTION) <> nil then
+ AField.Description := AJSONObjItem.GetValue(DESCRIPTION);
+
+ if AJSONObjItem.GetValue(HOST) <> nil then
+ AField.Host := AJSONObjItem.GetValue(HOST);
+
+ if AJSONObjItem.GetValue(USER) <> nil then
+ AField.User := AJSONObjItem.GetValue(USER);
+
+ if AJSONObjItem.GetValue(PASSWORD) <> nil then
+ AField.Password := TUtilsCrypt.Decrypt(AJSONObjItem.GetValue(PASSWORD));
+
+ if AJSONObjItem.GetValue(PORT) <> nil then
+ AField.Port := AJSONObjItem.GetValue(PORT);
+
+ if AJSONObjItem.GetValue(DATABASE_NAME) <> nil then
+ AField.DatabaseName := AJSONObjItem.GetValue(DATABASE_NAME);
+
+ if AJSONObjItem.GetValue(VENDOR_LIB) <> nil then
+ AField.VendorLib := AJSONObjItem.GetValue(VENDOR_LIB);
+
+ if AJSONObjItem.GetValue(VISIBLE) <> nil then
+ AField.Visible := AJSONObjItem.GetValue(VISIBLE);
+
+ if AJSONObjItem.GetValue(LAST_REFERENCE) <> nil then
+ AField.LastReferences := StrToDateTimeDef(AJSONObjItem.GetValue(LAST_REFERENCE), 0);
+end;
+
+procedure TDelphiAIDevDBRegistersModel.ReadData(AProc: TProc;
+ const AAutoFreeField: TAutoFreeField = TAutoFreeField.Yes);
+var
+ LStringList: TStringList;
+ LJSONObjItem: TJSONObject;
+ LJSONArray: TJsonArray;
+ i: Integer;
+ LFields: TDelphiAIDevDBRegistersFields;
+begin
+ LFields := TDelphiAIDevDBRegistersFields.Create;
+ try
+ if not FileExists(TUtils.GetPathFileJSONDatabases) then
+ begin
+ AProc(LFields);
+ Exit;
+ end;
+
+ LStringList := TStringList.Create;
+ try
+ LStringList.LoadFromFile(TUtils.GetPathFileJSONDatabases);
+ LJSONArray := TJSONObject.ParseJSONValue(TEncoding.UTF8.GetBytes(LStringList.Text), 0) as TJSONArray;
+ finally
+ LStringList.Free;
+ end;
+
+ try
+ for i := 0 to Pred(LJSONArray.Count) do
+ begin
+ if not(LJSONArray.Items[i] is TJSONObject) then
+ Continue;
+
+ LJSONObjItem := LJSONArray.Items[i] as TJSONObject;
+
+ if LJSONObjItem.GetValue(GUID) = nil then
+ Continue;
+
+ Self.FillField(LJSONObjItem, LFields);
+
+ AProc(LFields);
+ end;
+ finally
+ LJSONArray.Free;
+ end;
+ finally
+ if AAutoFreeField = TAutoFreeField.Yes then
+ LFields.Free;
+ end;
+end;
+
+procedure TDelphiAIDevDBRegistersModel.SaveOrEditData(AFields: TDelphiAIDevDBRegistersFields);
+begin
+ if AFields.Guid.Trim.IsEmpty then
+ Self.SaveData(AFields)
+ else
+ Self.EditData(AFields);
+end;
+
+procedure TDelphiAIDevDBRegistersModel.SaveData(AFields: TDelphiAIDevDBRegistersFields);
+var
+ LStringList: TStringList;
+ LJSONArray: TJSONArray;
+ LJSONObject: TJSONObject;
+begin
+ LStringList := TStringList.Create;
+ try
+ if FileExists(TUtils.GetPathFileJSONDatabases) then
+ LStringList.LoadFromFile(TUtils.GetPathFileJSONDatabases);
+
+ LJSONArray := TJSONArray.Create;
+ try
+ if string(LStringList.Text).Trim.StartsWith('[') then
+ LJSONArray := TJSONObject.ParseJSONValue(TEncoding.UTF8.GetBytes(LStringList.Text), 0) as TJSONArray;
+
+ LJSONObject := TJSONObject.Create;
+ LJSONObject.AddPair(GUID, TUtils.GetGuidStr);
+ LJSONObject.AddPair(DRIVER_ID, TJSONNumber.Create(Integer(AFields.DriverID)));
+ LJSONObject.AddPair(DESCRIPTION, AFields.Description);
+ LJSONObject.AddPair(HOST, AFields.Host);
+ LJSONObject.AddPair(USER, AFields.User);
+ LJSONObject.AddPair(PASSWORD, TUtilsCrypt.Encrypt(AFields.Password));
+ LJSONObject.AddPair(PORT, TJSONNumber.Create(AFields.Port));
+ LJSONObject.AddPair(DATABASE_NAME, AFields.DatabaseName);
+ LJSONObject.AddPair(VENDOR_LIB, AFields.VendorLib);
+ LJSONObject.AddPair(VISIBLE, TJSONBool.Create(AFields.Visible));
+ LJSONObject.AddPair(LAST_REFERENCE, TJSONString.Create(TUtils.DateTimeToStrEmpty(AFields.LastReferences)));
+ LJSONArray.AddElement(LJSONObject);
+
+ {$IF CompilerVersion <= 32.0} //Tokyo
+ LStringList.Text := LJSONArray.ToJSON;
+ {$ELSE}
+ LStringList.Text := LJSONArray.Format(2);
+ {$ENDIF}
+ finally
+ LJSONArray.Free;
+ end;
+
+ LStringList.SaveToFile(TUtils.GetPathFileJSONDatabases);
+ finally
+ LStringList.Free;
+ end;
+end;
+
+procedure TDelphiAIDevDBRegistersModel.EditData(AFields: TDelphiAIDevDBRegistersFields);
+var
+ LStringList: TStringList;
+ LJSONArray: TJSONArray;
+ LJSONObjItem: TJSONObject;
+ i: Integer;
+begin
+ LStringList := TStringList.Create;
+ try
+ if FileExists(TUtils.GetPathFileJSONDatabases) then
+ LStringList.LoadFromFile(TUtils.GetPathFileJSONDatabases);
+
+ LJSONArray := TJSONArray.Create;
+ try
+ if string(LStringList.Text).Trim.StartsWith('[') then
+ LJSONArray := TJSONObject.ParseJSONValue(TEncoding.UTF8.GetBytes(LStringList.Text), 0) as TJSONArray;
+
+ for i := 0 to Pred(LJSONArray.Count) do
+ begin
+ if not(LJSONArray.Items[i] is TJSONObject) then
+ Continue;
+
+ LJSONObjItem := LJSONArray.Items[i] as TJSONObject;
+
+ if LJSONObjItem.GetValue(GUID) = AFields.Guid then
+ begin
+ LJSONObjItem.RemovePair(DRIVER_ID).Free;
+ LJSONObjItem.AddPair(DRIVER_ID, TJSONNumber.Create(Integer(AFields.DriverID)));
+
+ LJSONObjItem.RemovePair(DESCRIPTION).Free;
+ LJSONObjItem.AddPair(DESCRIPTION, AFields.Description);
+
+ LJSONObjItem.RemovePair(HOST).Free;
+ LJSONObjItem.AddPair(HOST, AFields.Host);
+
+ LJSONObjItem.RemovePair(USER).Free;
+ LJSONObjItem.AddPair(USER, AFields.User);
+
+ LJSONObjItem.RemovePair(PASSWORD).Free;
+ LJSONObjItem.AddPair(PASSWORD, TUtilsCrypt.Encrypt(AFields.Password));
+
+ LJSONObjItem.RemovePair(PORT).Free;
+ LJSONObjItem.AddPair(PORT, TJSONNumber.Create(AFields.Port));
+
+ LJSONObjItem.RemovePair(DATABASE_NAME).Free;
+ LJSONObjItem.AddPair(DATABASE_NAME, AFields.DatabaseName);
+
+ LJSONObjItem.RemovePair(VENDOR_LIB).Free;
+ LJSONObjItem.AddPair(VENDOR_LIB, AFields.VendorLib);
+
+ LJSONObjItem.RemovePair(VISIBLE).Free;
+ LJSONObjItem.AddPair(VISIBLE, TJSONBool.Create(AFields.Visible));
+
+ LJSONObjItem.RemovePair(LAST_REFERENCE).Free;
+ LJSONObjItem.AddPair(LAST_REFERENCE, TJSONString.Create(TUtils.DateTimeToStrEmpty(AFields.LastReferences)));
+
+ Break;
+ end;
+ end;
+
+ {$IF CompilerVersion <= 32.0} //Tokyo
+ LStringList.Text := LJSONArray.ToJSON;
+ {$ELSE}
+ LStringList.Text := LJSONArray.Format(2);
+ {$ENDIF}
+ finally
+ LJSONArray.Free;
+ end;
+
+ LStringList.SaveToFile(TUtils.GetPathFileJSONDatabases);
+ finally
+ LStringList.Free;
+ end;
+end;
+
+procedure TDelphiAIDevDBRegistersModel.RemoveData(const AGuid: string);
+var
+ LStringList: TStringList;
+ LJSONArray: TJSONArray;
+ LJSONObjItem: TJSONObject;
+ i: Integer;
+begin
+ if AGuid.Trim.IsEmpty then
+ Exit;
+
+ if not FileExists(TUtils.GetPathFileJSONDatabases) then
+ Exit;
+
+ LStringList := TStringList.Create;
+ try
+ LStringList.LoadFromFile(TUtils.GetPathFileJSONDatabases);
+ if not string(LStringList.Text).Trim.StartsWith('[') then
+ Exit;
+
+ LJSONArray := TJSONObject.ParseJSONValue(TEncoding.UTF8.GetBytes(LStringList.Text), 0) as TJSONArray;
+ try
+ for i := 0 to Pred(LJSONArray.Count) do
+ begin
+ if not(LJSONArray.Items[i] is TJSONObject) then
+ Continue;
+
+ LJSONObjItem := LJSONArray.Items[i] as TJSONObject;
+ if LJSONObjItem.GetValue(GUID) = AGuid then
+ begin
+ LJSONArray.Remove(i);
+ Break;
+ end;
+ end;
+
+ {$IF CompilerVersion <= 32.0} //Tokyo
+ LStringList.Text := LJSONArray.ToJSON;
+ {$ELSE}
+ LStringList.Text := LJSONArray.Format(2);
+ {$ENDIF}
+ finally
+ LJSONArray.Free;
+ end;
+
+ LStringList.SaveToFile(TUtils.GetPathFileJSONDatabases);
+ finally
+ LStringList.Free;
+ end;
+end;
+
+end.
diff --git a/Src/DB/Registers/DelphiAIDev.DB.Registers.View.dfm b/Src/DB/Registers/DelphiAIDev.DB.Registers.View.dfm
new file mode 100644
index 0000000..0f5b3e9
--- /dev/null
+++ b/Src/DB/Registers/DelphiAIDev.DB.Registers.View.dfm
@@ -0,0 +1,245 @@
+object DelphiAIDevDBRegistersView: TDelphiAIDevDBRegistersView
+ Left = 0
+ Top = 0
+ BorderIcons = [biSystemMenu]
+ Caption = 'IA Developer - Database registration'
+ ClientHeight = 561
+ ClientWidth = 1032
+ Color = clBtnFace
+ Font.Charset = DEFAULT_CHARSET
+ Font.Color = clWindowText
+ Font.Height = -11
+ Font.Name = 'Tahoma'
+ Font.Style = []
+ KeyPreview = True
+ OldCreateOrder = False
+ Position = poScreenCenter
+ OnCreate = FormCreate
+ OnKeyDown = FormKeyDown
+ OnShow = FormShow
+ PixelsPerInch = 96
+ TextHeight = 13
+ object Panel1: TPanel
+ Left = 0
+ Top = 507
+ Width = 1032
+ Height = 35
+ Align = alBottom
+ BevelEdges = [beLeft, beRight, beBottom]
+ BevelOuter = bvNone
+ Padding.Left = 2
+ Padding.Top = 2
+ Padding.Right = 2
+ Padding.Bottom = 2
+ ParentBackground = False
+ TabOrder = 0
+ object btnEdit: TButton
+ AlignWithMargins = True
+ Left = 124
+ Top = 2
+ Width = 120
+ Height = 31
+ Cursor = crHandPoint
+ Margins.Left = 0
+ Margins.Top = 0
+ Margins.Right = 2
+ Margins.Bottom = 0
+ Align = alLeft
+ Caption = 'Edit'
+ TabOrder = 0
+ OnClick = btnEditClick
+ end
+ object btnClose: TButton
+ AlignWithMargins = True
+ Left = 918
+ Top = 2
+ Width = 110
+ Height = 31
+ Cursor = crHandPoint
+ Margins.Left = 0
+ Margins.Top = 0
+ Margins.Right = 2
+ Margins.Bottom = 0
+ Align = alRight
+ Caption = 'Close'
+ TabOrder = 1
+ OnClick = btnCloseClick
+ end
+ object btnAdd: TButton
+ AlignWithMargins = True
+ Left = 2
+ Top = 2
+ Width = 120
+ Height = 31
+ Cursor = crHandPoint
+ Margins.Left = 0
+ Margins.Top = 0
+ Margins.Right = 2
+ Margins.Bottom = 0
+ Align = alLeft
+ Caption = 'Add new'
+ TabOrder = 2
+ OnClick = btnAddClick
+ end
+ object btnRemove: TButton
+ AlignWithMargins = True
+ Left = 246
+ Top = 2
+ Width = 120
+ Height = 31
+ Cursor = crHandPoint
+ Margins.Left = 0
+ Margins.Top = 0
+ Margins.Right = 2
+ Margins.Bottom = 0
+ Align = alLeft
+ Caption = 'Remove'
+ TabOrder = 3
+ OnClick = btnRemoveClick
+ end
+ object btnGenerateDatabaseReference: TButton
+ AlignWithMargins = True
+ Left = 368
+ Top = 2
+ Width = 165
+ Height = 31
+ Cursor = crHandPoint
+ Margins.Left = 0
+ Margins.Top = 0
+ Margins.Bottom = 0
+ Align = alLeft
+ Caption = 'Generate database reference'
+ TabOrder = 4
+ OnClick = btnGenerateDatabaseReferenceClick
+ end
+ end
+ object ListView: TListView
+ Left = 0
+ Top = 50
+ Width = 1032
+ Height = 457
+ Align = alClient
+ Columns = <
+ item
+ Caption = 'Description'
+ Width = 200
+ end
+ item
+ Caption = 'Driver ID'
+ Width = 70
+ end
+ item
+ Caption = 'Host'
+ Width = 100
+ end
+ item
+ Caption = 'User'
+ Width = 90
+ end
+ item
+ Alignment = taCenter
+ Caption = 'Port'
+ Width = 60
+ end
+ item
+ Caption = 'Database name'
+ Width = 200
+ end
+ item
+ Alignment = taCenter
+ Caption = 'Visible'
+ Width = 45
+ end
+ item
+ Caption = 'Last generation of reference'
+ Width = 180
+ end
+ item
+ Caption = 'Password'
+ MaxWidth = 1
+ Width = 1
+ end
+ item
+ Caption = 'VendorLib'
+ MaxWidth = 1
+ Width = 1
+ end
+ item
+ Caption = 'Guid'
+ MaxWidth = 1
+ Width = 1
+ end>
+ Font.Charset = DEFAULT_CHARSET
+ Font.Color = clWindowText
+ Font.Height = -12
+ Font.Name = 'Tahoma'
+ Font.Style = []
+ ReadOnly = True
+ RowSelect = True
+ ParentFont = False
+ SortType = stText
+ TabOrder = 1
+ ViewStyle = vsReport
+ OnColumnClick = ListViewColumnClick
+ OnDblClick = ListViewDblClick
+ OnKeyDown = ListViewKeyDown
+ OnSelectItem = ListViewSelectItem
+ end
+ object pnTop: TPanel
+ Left = 0
+ Top = 0
+ Width = 1032
+ Height = 50
+ Margins.Left = 0
+ Margins.Top = 0
+ Margins.Right = 0
+ Margins.Bottom = 0
+ Align = alTop
+ BevelOuter = bvNone
+ TabOrder = 2
+ object btnSearch: TButton
+ AlignWithMargins = True
+ Left = 947
+ Top = 14
+ Width = 75
+ Height = 27
+ Cursor = crHandPoint
+ Margins.Left = 2
+ Margins.Top = 14
+ Margins.Right = 10
+ Margins.Bottom = 9
+ Align = alRight
+ Caption = 'Search'
+ TabOrder = 0
+ OnClick = btnSearchClick
+ end
+ object edtSearch: TEdit
+ AlignWithMargins = True
+ Left = 10
+ Top = 15
+ Width = 935
+ Height = 25
+ Margins.Left = 10
+ Margins.Top = 15
+ Margins.Right = 0
+ Margins.Bottom = 10
+ Align = alClient
+ AutoSize = False
+ TabOrder = 1
+ OnKeyDown = edtSearchKeyDown
+ end
+ end
+ object StatusBar1: TStatusBar
+ Left = 0
+ Top = 542
+ Width = 1032
+ Height = 19
+ Panels = <
+ item
+ Width = 50
+ end
+ item
+ Width = 50
+ end>
+ end
+end
diff --git a/Src/DB/Registers/DelphiAIDev.DB.Registers.View.pas b/Src/DB/Registers/DelphiAIDev.DB.Registers.View.pas
new file mode 100644
index 0000000..56f68c9
--- /dev/null
+++ b/Src/DB/Registers/DelphiAIDev.DB.Registers.View.pas
@@ -0,0 +1,395 @@
+unit DelphiAIDev.DB.Registers.View;
+
+interface
+
+uses
+ Winapi.Windows,
+ System.SysUtils,
+ System.StrUtils,
+ System.Classes,
+ Vcl.Controls,
+ Vcl.Forms,
+ Vcl.StdCtrls,
+ Vcl.ExtCtrls,
+ Vcl.ComCtrls,
+ C4D.Conn,
+ DelphiAIDev.Utils.ListView,
+ DelphiAIDev.DB.Registers.Model,
+ DelphiAIDev.DB.Registers.Fields,
+ DelphiAIDev.DB.Registers.AddEdit.View,
+ DelphiAIDev.DB.References.View;
+
+type
+ TDelphiAIDevDBRegistersView = class(TForm)
+ Panel1: TPanel;
+ btnEdit: TButton;
+ btnClose: TButton;
+ ListView: TListView;
+ pnTop: TPanel;
+ btnSearch: TButton;
+ edtSearch: TEdit;
+ StatusBar1: TStatusBar;
+ btnAdd: TButton;
+ btnRemove: TButton;
+ btnGenerateDatabaseReference: TButton;
+ procedure FormCreate(Sender: TObject);
+ procedure FormShow(Sender: TObject);
+ procedure FormKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState);
+ procedure btnCloseClick(Sender: TObject);
+ procedure btnSearchClick(Sender: TObject);
+ procedure ListViewSelectItem(Sender: TObject; Item: TListItem; Selected: Boolean);
+ procedure ListViewDblClick(Sender: TObject);
+ procedure ListViewKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState);
+ procedure btnEditClick(Sender: TObject);
+ procedure btnAddClick(Sender: TObject);
+ procedure btnRemoveClick(Sender: TObject);
+ procedure edtSearchKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState);
+ procedure ListViewColumnClick(Sender: TObject; Column: TListColumn);
+ procedure btnGenerateDatabaseReferenceClick(Sender: TObject);
+ private
+ FUtilsListView: IDelphiAIDevUtilsListView;
+ FMadeChanges: Boolean;
+ procedure ReloadData;
+ procedure ReloadDataInternal;
+ procedure FillStatusBar(AItem: TListItem);
+ procedure FillFieldsWithSelectedItem(var AFields: TDelphiAIDevDBRegistersFields);
+ public
+ property MadeChanges: Boolean read FMadeChanges;
+ end;
+
+implementation
+
+uses
+ DelphiAIDev.Utils,
+ DelphiAIDev.Utils.OTA,
+ DelphiAIDev.Types;
+
+{$R *.dfm}
+
+const
+ C_INDEX_SUBITEM_DriverId = 0;
+ C_INDEX_SUBITEM_Host = 1;
+ C_INDEX_SUBITEM_User = 2;
+ C_INDEX_SUBITEM_Port = 3;
+ C_INDEX_SUBITEM_DatabaseName = 4;
+ C_INDEX_SUBITEM_Visible = 5;
+ C_INDEX_SUBITEM_LastReferences = 6;
+ C_INDEX_SUBITEM_Password = 7;
+ C_INDEX_SUBITEM_VendorLib = 8;
+ C_INDEX_SUBITEM_Guid = 9;
+
+procedure TDelphiAIDevDBRegistersView.FormCreate(Sender: TObject);
+begin
+ TUtilsOTA.IDEThemingAll(TDelphiAIDevDBRegistersView, Self);
+ FUtilsListView := TDelphiAIDevUtilsListView.New(ListView);
+end;
+
+procedure TDelphiAIDevDBRegistersView.FormShow(Sender: TObject);
+begin
+ Self.ReloadData;
+
+ if ListView.Items.Count > 0 then
+ ListView.Items.Item[0].Selected := True;
+ FMadeChanges := False;
+ edtSearch.SetFocus;
+
+ FUtilsListView
+ .InvertOrder(True)
+ .SortStyle(TDelphiAIDevUtilsListViewSortStyle.AlphaNum)
+ .ColumnIndex(C_INDEX_SUBITEM_DatabaseName + 1)
+ .CustomSort;
+end;
+
+procedure TDelphiAIDevDBRegistersView.FormKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState);
+begin
+ case Key of
+ VK_F4:
+ if ssAlt in Shift then
+ Key := 0;
+ VK_ESCAPE:
+ if Shift = [] then
+ btnClose.Click;
+ VK_DOWN, VK_UP:
+ begin
+ if ListView <> ActiveControl then
+ begin
+ case Key of
+ VK_DOWN:
+ if ListView.ItemIndex < Pred(ListView.Items.Count) then
+ ListView.ItemIndex := ListView.ItemIndex + 1;
+ VK_UP:
+ if ListView.ItemIndex > 0 then
+ ListView.ItemIndex := ListView.ItemIndex - 1;
+ end;
+ Key := 0;
+ end;
+ end;
+ end;
+end;
+
+procedure TDelphiAIDevDBRegistersView.btnCloseClick(Sender: TObject);
+begin
+ Self.Close;
+end;
+
+procedure TDelphiAIDevDBRegistersView.edtSearchKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState);
+begin
+ if Key = VK_RETURN then
+ Self.ReloadData;
+end;
+
+procedure TDelphiAIDevDBRegistersView.btnSearchClick(Sender: TObject);
+begin
+ Self.ReloadData;
+end;
+
+procedure TDelphiAIDevDBRegistersView.ReloadData;
+begin
+ Screen.Cursor := crHourGlass;
+ try
+ Self.ReloadDataInternal;
+ finally
+ Screen.Cursor := crDefault;
+ end;
+end;
+
+procedure TDelphiAIDevDBRegistersView.ReloadDataInternal;
+var
+ LStrSearch: string;
+ LListItem: TListItem;
+ LGuidSelected: string;
+begin
+ LStrSearch := LowerCase(edtSearch.Text);
+
+ if ListView.Selected <> nil then
+ LGuidSelected := ListView.Items[ListView.Selected.Index].SubItems[C_INDEX_SUBITEM_Guid];
+
+ ListView.Clear;
+
+ TDelphiAIDevDBRegistersModel.New.ReadData(
+ procedure(AFields: TDelphiAIDevDBRegistersFields)
+ begin
+ if AFields.Description.Trim.IsEmpty then
+ Exit;
+
+ //if (AFields.Kind = TC4DQuestionKind.ItemMenuNormal) and (AFields.Question.Trim.IsEmpty) then
+ // Exit;
+
+ if (LStrSearch.Trim.IsEmpty)
+ or(AFields.Description.ToLower.Contains(LStrSearch))
+ or(AFields.Host.ToLower.Contains(LStrSearch))
+ or(AFields.DatabaseName.ToLower.Contains(LStrSearch))
+ then
+ begin
+ LListItem := ListView.Items.Add;
+ LListItem.Caption := AFields.Description;
+ LListItem.ImageIndex := -1;
+ LListItem.SubItems.Add(AFields.DriverID.ToString);
+ LListItem.SubItems.Add(AFields.Host);
+ LListItem.SubItems.Add(AFields.User);
+ LListItem.SubItems.Add(AFields.Port.ToString);
+ LListItem.SubItems.Add(AFields.DatabaseName);
+ LListItem.SubItems.Add(TUtils.BoolToStrC4D(AFields.Visible));
+ LListItem.SubItems.Add(TUtils.DateTimeToStrEmpty(AFields.LastReferences));
+ LListItem.SubItems.Add(AFields.Password);
+ LListItem.SubItems.Add(AFields.VendorLib);
+ LListItem.SubItems.Add(AFields.Guid);
+ end;
+ end
+ );
+
+ FUtilsListView
+ .InvertOrder(False)
+ .CustomSort;
+
+ if not LGuidSelected.Trim.IsEmpty then
+ TUtils.FindListVewItem(ListView, C_INDEX_SUBITEM_Guid, LGuidSelected);
+
+ Self.FillStatusBar(ListView.Selected);
+end;
+
+procedure TDelphiAIDevDBRegistersView.ListViewSelectItem(Sender: TObject; Item: TListItem; Selected: Boolean);
+begin
+ Self.FillStatusBar(Item);
+end;
+
+procedure TDelphiAIDevDBRegistersView.FillFieldsWithSelectedItem(var AFields: TDelphiAIDevDBRegistersFields);
+var
+ LListItem: TListItem;
+begin
+ AFields.Clear;
+ if ListView.Selected = nil then
+ Exit;
+
+ LListItem := ListView.Items[ListView.Selected.Index];
+ AFields.Description := LListItem.Caption;
+ AFields.DriverID := TUtils.StrToDriverID(LListItem.SubItems[C_INDEX_SUBITEM_DriverId]);
+ AFields.Host := LListItem.SubItems[C_INDEX_SUBITEM_Host];
+ AFields.User := LListItem.SubItems[C_INDEX_SUBITEM_User];
+ AFields.Port := StrToIntDef(LListItem.SubItems[C_INDEX_SUBITEM_Port], 0);
+ AFields.DatabaseName := LListItem.SubItems[C_INDEX_SUBITEM_DatabaseName];
+ AFields.Visible := TUtils.StrToBoolC4D(LListItem.SubItems[C_INDEX_SUBITEM_Visible]);
+ AFields.LastReferences := StrToDateTimeDef(LListItem.SubItems[C_INDEX_SUBITEM_LastReferences], 0);
+ AFields.Password := LListItem.SubItems[C_INDEX_SUBITEM_Password];
+ AFields.VendorLib := LListItem.SubItems[C_INDEX_SUBITEM_VendorLib];
+ AFields.Guid := LListItem.SubItems[C_INDEX_SUBITEM_Guid];
+end;
+
+procedure TDelphiAIDevDBRegistersView.FillStatusBar(AItem: TListItem);
+var
+ LIndex: Integer;
+ LDatabaseName: string;
+begin
+ LIndex := -1;
+ LDatabaseName := '';
+ if AItem <> nil then
+ begin
+ LIndex := AItem.Index;
+ LDatabaseName := ListView.Items[LIndex].SubItems[C_INDEX_SUBITEM_DatabaseName];
+ end;
+
+ StatusBar1.Panels[0].Text := Format('%d of %d', [LIndex + 1, ListView.Items.Count]);
+ StatusBar1.Panels[1].Text := LDatabaseName;
+end;
+
+procedure TDelphiAIDevDBRegistersView.ListViewColumnClick(Sender: TObject; Column: TListColumn);
+var
+ LSortStyle: TDelphiAIDevUtilsListViewSortStyle;
+begin
+ LSortStyle := TDelphiAIDevUtilsListViewSortStyle.AlphaNum;
+ case Column.Index of
+ C_INDEX_SUBITEM_Port + 1:
+ LSortStyle := TDelphiAIDevUtilsListViewSortStyle.Numeric;
+ end;
+
+ FUtilsListView
+ .InvertOrder(True)
+ .SortStyle(LSortStyle)
+ .ColumnIndex(Column.Index)
+ .CustomSort;
+end;
+
+procedure TDelphiAIDevDBRegistersView.ListViewDblClick(Sender: TObject);
+begin
+ btnEdit.Click
+end;
+
+procedure TDelphiAIDevDBRegistersView.ListViewKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState);
+begin
+ if Key = VK_RETURN then
+ btnEdit.Click
+end;
+
+procedure TDelphiAIDevDBRegistersView.btnAddClick(Sender: TObject);
+var
+ LFields: TDelphiAIDevDBRegistersFields;
+ LView: TDelphiAIDevDBRegistersAddEditView;
+begin
+ LFields := TDelphiAIDevDBRegistersFields.Create;
+ try
+ LView := TDelphiAIDevDBRegistersAddEditView.Create(nil);
+ try
+ LView.Caption := string(LView.Caption).Replace('[action]', 'Adding', [rfReplaceAll, rfIgnoreCase]);
+ LView.Fields := LFields;
+
+ if LView.ShowModal <> mrOk then
+ Exit;
+
+ FMadeChanges := True;
+ finally
+ LView.Free;
+ end;
+ Self.ReloadData;
+ finally
+ LFields.Free;
+ end;
+end;
+
+procedure TDelphiAIDevDBRegistersView.btnEditClick(Sender: TObject);
+var
+ LFields: TDelphiAIDevDBRegistersFields;
+ LView: TDelphiAIDevDBRegistersAddEditView;
+begin
+ if ListView.Selected = nil then
+ Exit;
+
+ LFields := TDelphiAIDevDBRegistersFields.Create;
+ try
+ Self.FillFieldsWithSelectedItem(LFields);
+
+ if LFields.Description.Trim.IsEmpty then
+ TUtils.ShowMsgErrorAndAbort('Description not found');
+
+ LView := TDelphiAIDevDBRegistersAddEditView.Create(nil);
+ try
+ LView.Caption := string(LView.Caption).Replace('[action]', 'Editing', [rfReplaceAll, rfIgnoreCase]);
+ LView.Fields := LFields;
+ if LView.ShowModal <> mrOk then
+ Exit;
+
+ FMadeChanges := True;
+ finally
+ LView.Free;
+ end;
+ Self.ReloadData;
+ finally
+ LFields.Free;
+ end;
+end;
+
+procedure TDelphiAIDevDBRegistersView.btnRemoveClick(Sender: TObject);
+var
+ LGuid: string;
+begin
+ if ListView.Selected = nil then
+ Exit;
+
+ LGuid := ListView.Items[ListView.Selected.Index].SubItems[C_INDEX_SUBITEM_Guid];
+ if LGuid.Trim.IsEmpty then
+ TUtils.ShowMsgErrorAndAbort('Guid not found');
+
+// if TC4DWizardOpenExternalModel.New.ExistGuidInIniFile(LId) then
+// TUtils.ShowMsgAndAbort('This registration cannot be deleted, as it is linked to other registration(s)');
+
+ if not TUtils.ShowQuestion2('Confirm remove?') then
+ Exit;
+
+ Screen.Cursor := crHourGlass;
+ try
+ TDelphiAIDevDBRegistersModel.New.RemoveData(LGuid);
+ Self.ReloadData;
+ finally
+ FMadeChanges := True;
+ Screen.Cursor := crDefault;
+ end;
+end;
+
+procedure TDelphiAIDevDBRegistersView.btnGenerateDatabaseReferenceClick(Sender: TObject);
+var
+ LView: TDelphiAIDevDBReferencesView;
+ LFields: TDelphiAIDevDBRegistersFields;
+begin
+ if ListView.Selected = nil then
+ Exit;
+
+ LFields := TDelphiAIDevDBRegistersFields.Create;
+ try
+ Self.FillFieldsWithSelectedItem(LFields);
+
+ if LFields.Description.Trim.IsEmpty then
+ TUtils.ShowMsgErrorAndAbort('Description not found');
+
+ LView := TDelphiAIDevDBReferencesView.Create(nil);
+ try
+ LView.Fields := LFields;
+ if LView.ShowModal = mrOk then
+ Self.ReloadData;
+ finally
+ LView.Free;
+ end;
+ finally
+ LFields.Free;
+ end;
+end;
+
+end.
diff --git a/Src/DB/Utils/DelphiAIDev.DB.Utils.pas b/Src/DB/Utils/DelphiAIDev.DB.Utils.pas
new file mode 100644
index 0000000..649afbd
--- /dev/null
+++ b/Src/DB/Utils/DelphiAIDev.DB.Utils.pas
@@ -0,0 +1,73 @@
+unit DelphiAIDev.DB.Utils;
+
+interface
+
+uses
+ System.SysUtils,
+ Vcl.StdCtrls;
+
+type
+ TDelphiAIDevDBUtils = class
+ private
+ public
+ class procedure ClearComboBox(const AComboBox: TComboBox);
+ class procedure FillComboBoxDatabases(const AComboBox: TComboBox; const AGuidDatabaseDefault: string);
+ end;
+
+implementation
+
+uses
+ DelphiAIDev.DB.Registers.Fields,
+ DelphiAIDev.DB.Registers.Model;
+
+class procedure TDelphiAIDevDBUtils.ClearComboBox(const AComboBox: TComboBox);
+var
+ i: Integer;
+ LObj: TObject;
+begin
+ for i := 0 to Pred(AComboBox.Items.Count) do
+ begin
+ if not Assigned(AComboBox.Items.Objects[i]) then
+ Continue;
+
+ LObj := AComboBox.Items.Objects[i];
+
+ if LObj is TDelphiAIDevDBRegistersFields then
+ TDelphiAIDevDBRegistersFields(LObj).Free;
+ end;
+
+ AComboBox.Items.Clear;
+end;
+
+class procedure TDelphiAIDevDBUtils.FillComboBoxDatabases(const AComboBox: TComboBox; const AGuidDatabaseDefault: string);
+var
+ LField: TDelphiAIDevDBRegistersFields;
+ LFieldDefault: TDelphiAIDevDBRegistersFields;
+begin
+ Self.ClearComboBox(AComboBox);
+ LFieldDefault := nil;
+
+ TDelphiAIDevDBRegistersModel.New.ReadData(
+ procedure(AFields: TDelphiAIDevDBRegistersFields)
+ begin
+ if (not AFields.Visible) or (AFields.Description.Trim.IsEmpty) then
+ Exit;
+
+ if AFields.Visible then
+ begin
+ LField := TDelphiAIDevDBRegistersFields.Create;
+ LField.GetDataFromOtherObject(AFields);
+ AComboBox.Items.AddObject(LField.Description, LField);
+
+ if LField.Guid = AGuidDatabaseDefault then
+ LFieldDefault := LField;
+ end;
+ end
+ );
+
+ AComboBox.ItemIndex := 0;
+ if LFieldDefault <> nil then
+ AComboBox.ItemIndex := AComboBox.Items.IndexOfObject(LFieldDefault);
+end;
+
+end.
diff --git a/Src/DefaultsQuestions/DelphiAIDev.DefaultsQuestions.AddEdit.View.dfm b/Src/DefaultsQuestions/DelphiAIDev.DefaultsQuestions.AddEdit.View.dfm
index fd3cdd7..b659efd 100644
--- a/Src/DefaultsQuestions/DelphiAIDev.DefaultsQuestions.AddEdit.View.dfm
+++ b/Src/DefaultsQuestions/DelphiAIDev.DefaultsQuestions.AddEdit.View.dfm
@@ -89,7 +89,6 @@ object DelphiAIDevDefaultsQuestionsAddEditView: TDelphiAIDevDefaultsQuestionsAdd
BevelOuter = bvNone
ParentBackground = False
TabOrder = 0
- ExplicitTop = -2
DesignSize = (
674
350)
diff --git a/Src/DefaultsQuestions/DelphiAIDev.DefaultsQuestions.AddEdit.View.pas b/Src/DefaultsQuestions/DelphiAIDev.DefaultsQuestions.AddEdit.View.pas
index 8b41b12..b114e88 100644
--- a/Src/DefaultsQuestions/DelphiAIDev.DefaultsQuestions.AddEdit.View.pas
+++ b/Src/DefaultsQuestions/DelphiAIDev.DefaultsQuestions.AddEdit.View.pas
@@ -52,6 +52,7 @@ TDelphiAIDevDefaultsQuestionsAddEditView = class(TForm)
procedure MenuMasterLoad;
procedure MenuMasterClear;
procedure ConfFieldsKind;
+ procedure FillScreenFields;
public
property Fields: TDelphiAIDevDefaultsQuestionsFields read FFields write FFields;
end;
@@ -91,12 +92,7 @@ procedure TDelphiAIDevDefaultsQuestionsAddEditView.FormDestroy(Sender: TObject);
procedure TDelphiAIDevDefaultsQuestionsAddEditView.FormShow(Sender: TObject);
begin
- cBoxKind.ItemIndex := cBoxKind.Items.IndexOf(FFields.Kind.ToString);
- edtCaption.Text := FFields.Caption;
- mmQuestion.Lines.Text := FFields.Question;
- edtOrder.Text := FFields.Order.Tostring;
- ckVisible.Checked := FFields.Visible;
- ckCodeOnly.Checked := FFields.CodeOnly;
+ Self.FillScreenFields;
Self.ConfFieldsKind;
Self.MenuMasterLoad;
@@ -106,6 +102,16 @@ procedure TDelphiAIDevDefaultsQuestionsAddEditView.FormShow(Sender: TObject);
cBoxKind.SetFocus;
end;
+procedure TDelphiAIDevDefaultsQuestionsAddEditView.FillScreenFields;
+begin
+ cBoxKind.ItemIndex := cBoxKind.Items.IndexOf(FFields.Kind.ToString);
+ edtCaption.Text := FFields.Caption;
+ mmQuestion.Lines.Text := FFields.Question;
+ edtOrder.Text := FFields.Order.ToString;
+ ckVisible.Checked := FFields.Visible;
+ ckCodeOnly.Checked := FFields.CodeOnly;
+end;
+
procedure TDelphiAIDevDefaultsQuestionsAddEditView.MenuMasterClear;
var
I: Integer;
@@ -134,7 +140,7 @@ procedure TDelphiAIDevDefaultsQuestionsAddEditView.MenuMasterLoad;
LFields: TDelphiAIDevDefaultsQuestionsFields;
LItemIndex: Integer;
begin
- if(AFields.Kind <> TC4DQuestionKind.MenuMasterOnly)then
+ if AFields.Kind <> TC4DQuestionKind.MenuMasterOnly then
Exit;
LFields := TDelphiAIDevDefaultsQuestionsFields.Create;
@@ -145,7 +151,7 @@ procedure TDelphiAIDevDefaultsQuestionsAddEditView.MenuMasterLoad;
//if (FFields.IdParent > 0)and(FFields.IdParent = LFields.IdParent) then
// LItemIndexDefault := LItemIndex;
- if(FFields.GuidMenuMaster = LFields.Guid)then
+ if FFields.GuidMenuMaster = LFields.Guid then
LItemIndexDefault := LItemIndex;
end
);
@@ -161,13 +167,13 @@ procedure TDelphiAIDevDefaultsQuestionsAddEditView.btnCloseClick(Sender: TObject
procedure TDelphiAIDevDefaultsQuestionsAddEditView.btnConfirmClick(Sender: TObject);
begin
- if(cBoxKind.ItemIndex <= 0)then
+ if cBoxKind.ItemIndex <= 0 then
TUtils.ShowMsgAndAbort('No informed Kind', cBoxKind);
if Trim(edtCaption.Text).IsEmpty then
TUtils.ShowMsgAndAbort('No informed Caption', edtCaption);
- if (mmQuestion.Enabled) and (Trim(mmQuestion.Lines.Text).IsEmpty )then
+ if (mmQuestion.Enabled) and (Trim(mmQuestion.Lines.Text).IsEmpty)then
TUtils.ShowMsgAndAbort('No informed Question', mmQuestion);
FFields.Kind := TUtils.StrToDefaultsQuestionsKind(cBoxKind.Text);
@@ -178,8 +184,8 @@ procedure TDelphiAIDevDefaultsQuestionsAddEditView.btnConfirmClick(Sender: TObje
FFields.CodeOnly := ckCodeOnly.Checked;
FFields.GuidMenuMaster := '';
- if(cBoxMenuMaster.ItemIndex >= 0)then
- if(TDelphiAIDevDefaultsQuestionsFields(cBoxMenuMaster.Items.Objects[cBoxMenuMaster.ItemIndex]) <> nil)then
+ if cBoxMenuMaster.ItemIndex >= 0 then
+ if TDelphiAIDevDefaultsQuestionsFields(cBoxMenuMaster.Items.Objects[cBoxMenuMaster.ItemIndex]) <> nil then
FFields.GuidMenuMaster := TDelphiAIDevDefaultsQuestionsFields(cBoxMenuMaster.Items.Objects[cBoxMenuMaster.ItemIndex]).Guid;
TDelphiAIDevDefaultsQuestionsModel.New.SaveOrEditData(FFields);
@@ -199,7 +205,7 @@ procedure TDelphiAIDevDefaultsQuestionsAddEditView.ConfFieldsKind;
mmQuestion.Enabled := True;
cBoxMenuMaster.Enabled := True;
- if(cBoxKind.Text = TC4DQuestionKind.Separators.ToString)then
+ if cBoxKind.Text = TC4DQuestionKind.Separators.ToString then
begin
FLastCaption := edtCaption.Text;
edtCaption.Text := '-';
@@ -209,9 +215,9 @@ procedure TDelphiAIDevDefaultsQuestionsAddEditView.ConfFieldsKind;
mmQuestion.Lines.Clear;
mmQuestion.Enabled := False;
end
- else if(cBoxKind.Text = TC4DQuestionKind.MenuMasterOnly.ToString)then
+ else if cBoxKind.Text = TC4DQuestionKind.MenuMasterOnly.ToString then
begin
- if(edtCaption.Text = '-')and(not FLastCaption.Trim.IsEmpty)then
+ if (edtCaption.Text = '-') and (not FLastCaption.Trim.IsEmpty) then
edtCaption.Text := FLastCaption;
FLastQuestion := mmQuestion.Lines.Text;
@@ -224,29 +230,27 @@ procedure TDelphiAIDevDefaultsQuestionsAddEditView.ConfFieldsKind;
end
else
begin
- if(edtCaption.Text = '-')and(not FLastCaption.Trim.IsEmpty)then
+ if (edtCaption.Text = '-') and (not FLastCaption.Trim.IsEmpty) then
edtCaption.Text := FLastCaption;
- if(mmQuestion.Text = '')and(not FLastQuestion.Trim.IsEmpty)then
+ if (mmQuestion.Text = '') and (not FLastQuestion.Trim.IsEmpty) then
mmQuestion.Text := FLastQuestion;
end;
- if(cBoxKind.Text <> TC4DQuestionKind.MenuMasterOnly.ToString)then
- begin
- if(cBoxMenuMaster.ItemIndex <= 0)then
+ if cBoxKind.Text <> TC4DQuestionKind.MenuMasterOnly.ToString then
+ if cBoxMenuMaster.ItemIndex <= 0 then
cBoxMenuMaster.ItemIndex := FLastItemIndexMenuMaster;
- end;
end;
procedure TDelphiAIDevDefaultsQuestionsAddEditView.FormKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState);
begin
case Key of
VK_F4:
- if ssAlt in Shift then
- Key := 0;
+ if ssAlt in Shift then
+ Key := 0;
VK_ESCAPE:
- if Shift = [] then
- btnClose.Click;
+ if Shift = [] then
+ btnClose.Click;
end;
end;
diff --git a/Src/DefaultsQuestions/DelphiAIDev.DefaultsQuestions.PopupMenu.pas b/Src/DefaultsQuestions/DelphiAIDev.DefaultsQuestions.PopupMenu.pas
index 8d1c903..6614170 100644
--- a/Src/DefaultsQuestions/DelphiAIDev.DefaultsQuestions.PopupMenu.pas
+++ b/Src/DefaultsQuestions/DelphiAIDev.DefaultsQuestions.PopupMenu.pas
@@ -107,8 +107,8 @@ procedure TDelphiAIDevDefaultsQuestionsPopupMenu.CreateMenuItemsList;
for LOrder2 in LListOrder do
for LItem2 in FList do
begin
- if(LItem2.Order = LOrder2)then
- if(not LItem2.Created)and(LItem2.GuidMenuMaster.Trim = AFields.Guid.Trim)then
+ if LItem2.Order = LOrder2 then
+ if (not LItem2.Created) and (LItem2.GuidMenuMaster.Trim = AFields.Guid.Trim) then
begin
LMenuItem2 := Self.CreateSubMenu(AMenuItem, LItem2);
LItem2.Created := True;
@@ -129,10 +129,10 @@ procedure TDelphiAIDevDefaultsQuestionsPopupMenu.CreateMenuItemsList;
try
for LItem in FList do
begin
- if(LItem.Order <= 0)then
+ if LItem.Order <= 0 then
LItem.Order := 9999;
- if(not LListOrder.Contains(LItem.Order))then //(LItem.Order > 0)and
+ if not LListOrder.Contains(LItem.Order) then //(LItem.Order > 0)and
LListOrder.Add(LItem.Order);
end;
@@ -142,8 +142,8 @@ procedure TDelphiAIDevDefaultsQuestionsPopupMenu.CreateMenuItemsList;
for LOrder in LListOrder do
for LItem in FList do
begin
- if(LItem.Order = LOrder)then
- if(not LItem.Created)and(LITem.GuidMenuMaster.Trim.IsEmpty)then
+ if LItem.Order = LOrder then
+ if (not LItem.Created) and (LITem.GuidMenuMaster.Trim.IsEmpty) then
begin
LMenuItem := Self.CreateSubMenu(nil, LItem);
LItem.Created := True;
@@ -156,8 +156,8 @@ procedure TDelphiAIDevDefaultsQuestionsPopupMenu.CreateMenuItemsList;
for LOrder in LListOrder do
for LItem in FList do
begin
- if(LItem.Order = LOrder)then
- if(not LItem.Created)then
+ if LItem.Order = LOrder then
+ if not LItem.Created then
begin
LMenuItem := Self.CreateSubMenu(nil, LItem);
LItem.Created := True;
diff --git a/Src/DefaultsQuestions/DelphiAIDev.DefaultsQuestions.View.pas b/Src/DefaultsQuestions/DelphiAIDev.DefaultsQuestions.View.pas
index b69f5c9..296fcec 100644
--- a/Src/DefaultsQuestions/DelphiAIDev.DefaultsQuestions.View.pas
+++ b/Src/DefaultsQuestions/DelphiAIDev.DefaultsQuestions.View.pas
@@ -81,7 +81,7 @@ procedure TDelphiAIDevDefaultsQuestionsView.FormShow(Sender: TObject);
begin
Self.ReloadData;
- if(ListView.Items.Count > 0)then
+ if ListView.Items.Count > 0 then
ListView.Items.Item[0].Selected := True;
FMadeChanges := False;
edtSearch.SetFocus;
@@ -104,14 +104,14 @@ procedure TDelphiAIDevDefaultsQuestionsView.FormKeyDown(Sender: TObject; var Key
btnClose.Click;
VK_DOWN, VK_UP:
begin
- if(ListView <> ActiveControl)then
+ if ListView <> ActiveControl then
begin
case Key of
VK_DOWN:
- if(ListView.ItemIndex < Pred(ListView.Items.Count))then
+ if ListView.ItemIndex < Pred(ListView.Items.Count) then
ListView.ItemIndex := ListView.ItemIndex + 1;
VK_UP:
- if(ListView.ItemIndex > 0)then
+ if ListView.ItemIndex > 0 then
ListView.ItemIndex := ListView.ItemIndex - 1;
end;
Key := 0;
@@ -127,7 +127,7 @@ procedure TDelphiAIDevDefaultsQuestionsView.btnCloseClick(Sender: TObject);
procedure TDelphiAIDevDefaultsQuestionsView.edtSearchKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState);
begin
- if(Key = VK_RETURN)then
+ if Key = VK_RETURN then
Self.ReloadData;
end;
@@ -159,7 +159,7 @@ procedure TDelphiAIDevDefaultsQuestionsView.ReloadDataInternal;
begin
LStrSearch := LowerCase(edtSearch.Text);
- if(ListView.Selected <> nil)then
+ if ListView.Selected <> nil then
LGuid := ListView.Items[ListView.Selected.Index].SubItems[C_INDEX_SUBITEM_Guid];
ListView.Clear;
@@ -173,7 +173,7 @@ procedure TDelphiAIDevDefaultsQuestionsView.ReloadDataInternal;
if (AFields.Kind = TC4DQuestionKind.ItemMenuNormal) and (AFields.Question.Trim.IsEmpty) then
Exit;
- if(LStrSearch.Trim.IsEmpty)
+ if (LStrSearch.Trim.IsEmpty)
or(AFields.Caption.ToLower.Contains(LStrSearch))
or(AFields.Question.ToLower.Contains(LStrSearch))
then
@@ -196,7 +196,7 @@ procedure TDelphiAIDevDefaultsQuestionsView.ReloadDataInternal;
.InvertOrder(False)
.CustomSort;
- if(not LGuid.Trim.IsEmpty)then
+ if not LGuid.Trim.IsEmpty then
TUtils.FindListVewItem(ListView, C_INDEX_SUBITEM_Guid, LGuid);
Self.FillStatusBar(ListView.Selected);
@@ -212,7 +212,7 @@ procedure TDelphiAIDevDefaultsQuestionsView.FillFieldsWithSelectedItem(var AFiel
LListItem: TListItem;
begin
AFields.Clear;
- if(ListView.Selected = nil)then
+ if ListView.Selected = nil then
Exit;
LListItem := ListView.Items[ListView.Selected.Index];
@@ -233,7 +233,7 @@ procedure TDelphiAIDevDefaultsQuestionsView.FillStatusBar(AItem: TListItem);
begin
LIndex := -1;
LQuestion := '';
- if(AItem <> nil)then
+ if AItem <> nil then
begin
LIndex := AItem.Index;
LQuestion := ListView.Items[LIndex].SubItems[C_INDEX_SUBITEM_Question];
@@ -248,7 +248,7 @@ procedure TDelphiAIDevDefaultsQuestionsView.ListViewColumnClick(Sender: TObject;
LSortStyle: TDelphiAIDevUtilsListViewSortStyle;
begin
LSortStyle := TDelphiAIDevUtilsListViewSortStyle.AlphaNum;
- case(Column.Index)of
+ case Column.Index of
C_INDEX_SUBITEM_Order + 1:
LSortStyle := TDelphiAIDevUtilsListViewSortStyle.Numeric;
end;
@@ -267,7 +267,7 @@ procedure TDelphiAIDevDefaultsQuestionsView.ListViewDblClick(Sender: TObject);
procedure TDelphiAIDevDefaultsQuestionsView.ListViewKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState);
begin
- if(Key = VK_RETURN)then
+ if Key = VK_RETURN then
btnEdit.Click
end;
@@ -284,7 +284,7 @@ procedure TDelphiAIDevDefaultsQuestionsView.btnAddClick(Sender: TObject);
LView.Caption := string(LView.Caption).Replace('[action]', 'Adding', [rfReplaceAll, rfIgnoreCase]);
LView.Fields := LFields;
- if(LView.ShowModal <> mrOk)then
+ if LView.ShowModal <> mrOk then
Exit;
FMadeChanges := True;
@@ -302,21 +302,21 @@ procedure TDelphiAIDevDefaultsQuestionsView.btnEditClick(Sender: TObject);
LFields: TDelphiAIDevDefaultsQuestionsFields;
LView: TDelphiAIDevDefaultsQuestionsAddEditView;
begin
- if(ListView.Selected = nil)then
+ if ListView.Selected = nil then
Exit;
LFields := TDelphiAIDevDefaultsQuestionsFields.Create;
try
Self.FillFieldsWithSelectedItem(LFields);
- if(LFields.Caption.Trim.IsEmpty)then
+ if LFields.Caption.Trim.IsEmpty then
TUtils.ShowMsgErrorAndAbort('Caption not found');
LView := TDelphiAIDevDefaultsQuestionsAddEditView.Create(nil);
try
LView.Caption := string(LView.Caption).Replace('[action]', 'Editing', [rfReplaceAll, rfIgnoreCase]);
LView.Fields := LFields;
- if(LView.ShowModal <> mrOk)then
+ if LView.ShowModal <> mrOk then
Exit;
FMadeChanges := True;
@@ -333,17 +333,17 @@ procedure TDelphiAIDevDefaultsQuestionsView.btnRemoveClick(Sender: TObject);
var
LGuid: string;
begin
- if(ListView.Selected = nil)then
+ if ListView.Selected = nil then
Exit;
LGuid := ListView.Items[ListView.Selected.Index].SubItems[C_INDEX_SUBITEM_Guid];
- if(LGuid.Trim.IsEmpty)then
+ if LGuid.Trim.IsEmpty then
TUtils.ShowMsgErrorAndAbort('Guid not found');
-// if(TC4DWizardOpenExternalModel.New.ExistGuidInIniFile(LId))then
+// if TC4DWizardOpenExternalModel.New.ExistGuidInIniFile(LId) then
// TUtils.ShowMsgAndAbort('This registration cannot be deleted, as it is linked to other registration(s)');
- if(not TUtils.ShowQuestion2('Confirm remove?'))then
+ if not TUtils.ShowQuestion2('Confirm remove?') then
Exit;
Screen.Cursor := crHourGlass;
diff --git a/Src/DelphiAIDev.Register.pas b/Src/DelphiAIDev.Register.pas
index 709d890..6a38c15 100644
--- a/Src/DelphiAIDev.Register.pas
+++ b/Src/DelphiAIDev.Register.pas
@@ -4,8 +4,11 @@ interface
uses
DelphiAIDev.Chat.View,
+ DelphiAIDev.DB.Chat.View,
DelphiAIDev.MainMenu.Register,
- DelphiAIDev.IDE.Shortcuts;
+ DelphiAIDev.KeyboardBinding,
+ DelphiAIDev.PopupMenuProjects,
+ DelphiAIDev.IDE.OTAIDENotifier;
procedure Register;
@@ -14,8 +17,11 @@ implementation
procedure Register;
begin
DelphiAIDev.Chat.View.RegisterSelf;
+ DelphiAIDev.DB.Chat.View.RegisterSelf;
DelphiAIDev.MainMenu.Register.RegisterSelf;
- DelphiAIDev.IDE.Shortcuts.RefreshRegister;
+ DelphiAIDev.KeyboardBinding.RefreshRegister;
+ DelphiAIDev.PopupMenuProjects.RegisterSelf;
+ DelphiAIDev.IDE.OTAIDENotifier.RegisterSelf;
end;
end.
diff --git a/Src/IDE/ImageListMain/DelphiAIDev.IDE.ImageListMain.pas b/Src/IDE/ImageListMain/DelphiAIDev.IDE.ImageListMain.pas
index ca39d1f..efe47d8 100644
--- a/Src/IDE/ImageListMain/DelphiAIDev.IDE.ImageListMain.pas
+++ b/Src/IDE/ImageListMain/DelphiAIDev.IDE.ImageListMain.pas
@@ -13,6 +13,9 @@ TDelphiAIDevIDEImageListMain = class
FImgIndexGear: Integer;
FImgIndexMessage: Integer;
FImgQuestion: Integer;
+ FImgDatabase: Integer;
+ FImgDatabaseAdd: Integer;
+ FImgDatabaseExecute: Integer;
constructor Create;
public
class function GetInstance: TDelphiAIDevIDEImageListMain;
@@ -20,6 +23,9 @@ TDelphiAIDevIDEImageListMain = class
property ImgIndexGear: Integer read FImgIndexGear;
property ImgIndexMessage: Integer read FImgIndexMessage;
property ImgQuestion: Integer read FImgQuestion;
+ property ImgDatabase: Integer read FImgDatabase;
+ property ImgDatabaseAdd: Integer read FImgDatabaseAdd;
+ property ImgDatabaseExecute: Integer read FImgDatabaseExecute;
end;
implementation
@@ -32,7 +38,7 @@ implementation
class function TDelphiAIDevIDEImageListMain.GetInstance: TDelphiAIDevIDEImageListMain;
begin
- if(not Assigned(Instance))then
+ if not Assigned(Instance) then
Instance := Self.Create;
Result := Instance;
end;
@@ -43,13 +49,16 @@ constructor TDelphiAIDevIDEImageListMain.Create;
FImgIndexGear := TUtilsOTA.AddImgIDEResourceName('c4d_gear');
FImgIndexMessage := TUtilsOTA.AddImgIDEResourceName('c4d_message');
FImgQuestion := TUtilsOTA.AddImgIDEResourceName('c4d_question');
+ FImgDatabase := TUtilsOTA.AddImgIDEResourceName('c4d_database');
+ FImgDatabaseAdd := TUtilsOTA.AddImgIDEResourceName('c4d_database_add');
+ FImgDatabaseExecute := TUtilsOTA.AddImgIDEResourceName('c4d_database_execute');
end;
initialization
Instance := TDelphiAIDevIDEImageListMain.GetInstance;
finalization
- if(Assigned(Instance))then
+ if Assigned(Instance) then
Instance.Free;
end.
diff --git a/Src/IDE/NTAEditViewNotifier/DelphiAIDev.IDE.NTAEditViewNotifier.pas b/Src/IDE/NTAEditViewNotifier/DelphiAIDev.IDE.NTAEditViewNotifier.pas
new file mode 100644
index 0000000..82bbc5d
--- /dev/null
+++ b/Src/IDE/NTAEditViewNotifier/DelphiAIDev.IDE.NTAEditViewNotifier.pas
@@ -0,0 +1,210 @@
+unit DelphiAIDev.IDE.NTAEditViewNotifier;
+
+interface
+
+uses
+ System.SysUtils,
+ System.Classes,
+ System.Generics.Collections,
+ System.Types,
+ System.SyncObjs,
+ System.RegularExpressions,
+ Vcl.Dialogs,
+ Vcl.Graphics,
+ Vcl.Imaging.pngimage,
+ DelphiAIDev.Utils,
+ DelphiAIDev.Utils.OTA,
+ DelphiAIDev.Consts,
+ DelphiAIDev.CodeCompletion.Vars,
+ DelphiAIDev.Settings,
+ ToolsAPI;
+
+type
+ TDelphiAIDevIDENTAEditViewNotifier = class(TInterfacedObject, IOTANotifier, INTAEditViewNotifier)
+ private
+ LVars: TDelphiAIDevCodeCompletionVars;
+ protected
+ FIOTAEditView: IOTAEditView;
+ FIndex: Integer;
+ procedure RemoveNotifier;
+ public
+ constructor Create(FileName: string; AEditView: IOTAEditView);
+ destructor Destroy; override;
+
+ { INTAEditViewNotifier }
+ ///EditorIdle chamado aps alguma ao ter ocorrido na visualizao
+ ///(edio, movimento do cursor, etc.) e um perodo de tempo ter passado sem que outra
+ ///ao acontecesse. Isso aproximadamente equivalente ao momento em que o Code
+ ///Insight acionado (e est vinculado configurao de atraso do Code Insight)
+ procedure EditorIdle(const View: IOTAEditView);
+ procedure BeginPaint(const View: IOTAEditView; var FullRepaint: Boolean);
+ procedure PaintLine(const View: IOTAEditView; LineNumber: Integer;
+ const LineText: PAnsiChar; const TextWidth: Word; const LineAttributes: TOTAAttributeArray;
+ const Canvas: TCanvas; const TextRect: TRect; const LineRect: TRect; const CellSize: TSize);
+ ///EndPaint chamado depois que todas as linhas foram repintadas.
+ ///Use isso para limpar quaisquer estruturas de dados que foram mantidas
+ ///ao longo da pintura das linhas
+ procedure EndPaint(const View: IOTAEditView);
+
+ //IOTANotifier
+ procedure AfterSave;
+ procedure BeforeSave;
+ procedure Modified;
+ procedure Destroyed;
+
+ //TDelphiAIDevIDENTAEditViewNotifier
+ procedure ClearLinesNotUsed;
+ end;
+
+implementation
+
+constructor TDelphiAIDevIDENTAEditViewNotifier.Create(FileName: string; AEditView: IOTAEditView);
+begin
+ inherited Create;
+ FIOTAEditView := AEditView;
+ FIndex := FIOTAEditView.AddNotifier(Self);
+ LVars := TDelphiAIDevCodeCompletionVars.GetInstance;
+end;
+
+destructor TDelphiAIDevIDENTAEditViewNotifier.Destroy;
+begin
+ Self.RemoveNotifier;
+ inherited;
+end;
+
+procedure TDelphiAIDevIDENTAEditViewNotifier.Destroyed;
+begin
+ Self.RemoveNotifier;
+end;
+
+procedure TDelphiAIDevIDENTAEditViewNotifier.AfterSave;
+begin
+
+end;
+
+procedure TDelphiAIDevIDENTAEditViewNotifier.BeforeSave;
+begin
+
+end;
+
+procedure TDelphiAIDevIDENTAEditViewNotifier.ClearLinesNotUsed;
+var
+ LView: IOTAEditView;
+ LColCurrent: Integer;
+ LLineCurrent: Integer;
+begin
+ ////LVars.Release := False;
+ if LVars.Module = nil then
+ Exit;
+
+ //**
+ if LVars.Contents.Count <= 1 then
+ Exit;
+ //**
+
+ LView := TUtilsOTA.GetIOTAEditView(LVars.Module);
+ LColCurrent := LView.CursorPos.Col;
+ LLineCurrent := LView.CursorPos.Line;
+ try
+ LView.Buffer.EditPosition.Move(LVars.LineIni, 2);
+ LView.Buffer.EditPosition.Delete(Pred(LVars.Contents.Count));
+ finally
+ LView.Buffer.EditPosition.Move(LLineCurrent, LColCurrent);
+ end;
+end;
+
+procedure TDelphiAIDevIDENTAEditViewNotifier.BeginPaint(const View: IOTAEditView; var FullRepaint: Boolean);
+begin
+ FullRepaint := True;
+end;
+
+procedure TDelphiAIDevIDENTAEditViewNotifier.EditorIdle(const View: IOTAEditView);
+var
+ LRow: Integer;
+ LColumn: Integer;
+begin
+ if LVars.LineIni <= 0 then
+ Exit;
+
+ TUtilsOTA.GetCursorPosition(LRow, LColumn);
+
+ if (LRow <> LVars.Row) or (LColumn <> LVars.Column) then
+ begin
+ TUtils.AddLog('EditorIdle');
+
+ ////LVars.Release := True;
+ try
+ Self.ClearLinesNotUsed;
+ finally
+ LVars.Clear;
+ end;
+ end;
+end;
+
+procedure TDelphiAIDevIDENTAEditViewNotifier.EndPaint(const View: IOTAEditView);
+begin
+
+end;
+
+procedure TDelphiAIDevIDENTAEditViewNotifier.Modified;
+begin
+
+end;
+
+procedure TDelphiAIDevIDENTAEditViewNotifier.PaintLine(const View: IOTAEditView; LineNumber: Integer;
+ const LineText: PAnsiChar; const TextWidth: Word; const LineAttributes: TOTAAttributeArray;
+ const Canvas: TCanvas; const TextRect: TRect; const LineRect: TRect; const CellSize: TSize);
+var
+ LLineText: string;
+begin
+ if LineNumber < 1 then
+ Exit;
+
+ LLineText := string(LineText);
+
+ //AQUI VERIFICA SE A LINHA NAO FOR VAZIA NAO ADICIONA O TEXTO DA SUGESTAO
+ //if not LLineText.Trim.IsEmpty then Exit;
+
+ //if LineNumber <> View.CursorPos.Line then Exit;
+
+// if LVars.Release then
+// begin
+// try
+// Self.ClearLinesNotUsed;
+// finally
+// LVars.Clear;
+// end;
+// end;
+
+ if (LineNumber >= LVars.LineIni) and (LineNumber < LVars.LineEnd) then
+ begin
+ Canvas.Brush.Style := bsClear;
+ Canvas.Font.Color := $777777;
+ if TDelphiAIDevSettings.GetInstance.CodeCompletionSuggestionColorUse then
+ Canvas.Font.Color := TDelphiAIDevSettings.GetInstance.CodeCompletionSuggestionColor;
+
+ try
+ LLineText := LVars.Contents[LineNumber - LVars.LineIni];
+ Canvas.TextOut(TextRect.Left, TextRect.Top, LLineText.TrimRight);
+ except on E: Exception do
+ if TUtils.DebugMyIsOn then
+ TUtils.AddLog('Exception in TDelphiAIDevIDENTAEditViewNotifier.PaintLine: ' + sLineBreak +
+ 'LineNumber: ' + LineNumber.ToString + sLineBreak +
+ 'LineIni: ' + LVars.LineIni.ToString + sLineBreak +
+ 'LineEnd: ' + LVars.LineEnd.ToString + sLineBreak +
+ E.Message);
+ end;
+ end;
+end;
+
+procedure TDelphiAIDevIDENTAEditViewNotifier.RemoveNotifier;
+begin
+ if Assigned(FIOTAEditView) and (FIndex >= 0) then
+ begin
+ FIOTAEditView.RemoveNotifier(FIndex);
+ FIndex := -1;
+ FIOTAEditView := nil;
+ end;
+end;
+
+end.
diff --git a/Src/IDE/OTAEditorNotifier/DelphiAIDev.IDE.OTAEditorNotifier.pas b/Src/IDE/OTAEditorNotifier/DelphiAIDev.IDE.OTAEditorNotifier.pas
new file mode 100644
index 0000000..f1a7998
--- /dev/null
+++ b/Src/IDE/OTAEditorNotifier/DelphiAIDev.IDE.OTAEditorNotifier.pas
@@ -0,0 +1,92 @@
+unit DelphiAIDev.IDE.OTAEditorNotifier;
+
+interface
+
+uses
+ System.SysUtils,
+ System.Classes,
+ System.Generics.Collections,
+ System.Types,
+ System.SyncObjs,
+ System.RegularExpressions,
+ Vcl.Dialogs,
+ Vcl.Graphics,
+ Vcl.Imaging.pngimage,
+ ToolsAPI,
+ DelphiAIDev.Utils,
+ DelphiAIDev.Consts,
+ DelphiAIDev.CodeCompletion.Vars,
+ DelphiAIDev.IDE.NTAEditViewNotifier;
+
+type
+ TDelphiAIDevIDEOTAEditorNotifier = class(TNotifierObject, IOTANotifier, IOTAEditorNotifier)
+ private
+ FIOTASourceEditor: IOTASourceEditor;
+ FINTAEditViewNotifierList: TList;
+ FIndex: Integer;
+ procedure RemoveNotifiers;
+ public
+ constructor Create(ASourceEditor: IOTASourceEditor);
+ destructor Destroy; override;
+ { IOTANotifier }
+ procedure Destroyed;
+ { IOTAEditorNotifier }
+ procedure ViewNotification(const View: IOTAEditView; Operation: TOperation);
+ procedure ViewActivated(const View: IOTAEditView);
+ end;
+
+implementation
+
+constructor TDelphiAIDevIDEOTAEditorNotifier.Create(ASourceEditor: IOTASourceEditor);
+var
+ i: Integer;
+begin
+ inherited Create;
+ FINTAEditViewNotifierList := TList.Create;
+ FIOTASourceEditor := ASourceEditor;
+
+ FIndex := FIOTASourceEditor.AddNotifier(Self);
+ for i := 0 to Pred(FIOTASourceEditor.EditViewCount) do
+ FINTAEditViewNotifierList.Add(TDelphiAIDevIDENTAEditViewNotifier.Create(FIOTASourceEditor.FileName, FIOTASourceEditor.EditViews[i]));
+end;
+
+destructor TDelphiAIDevIDEOTAEditorNotifier.Destroy;
+begin
+ RemoveNotifiers;
+ FINTAEditViewNotifierList.Free;
+ inherited;
+end;
+
+procedure TDelphiAIDevIDEOTAEditorNotifier.Destroyed;
+begin
+ RemoveNotifiers;
+end;
+
+procedure TDelphiAIDevIDEOTAEditorNotifier.RemoveNotifiers;
+var
+ i: Integer;
+begin
+ for i := 0 to Pred(FINTAEditViewNotifierList.Count) do
+ FINTAEditViewNotifierList[i].Destroyed;
+ FINTAEditViewNotifierList.Clear;
+
+ if Assigned(FIOTASourceEditor) and (FIndex >= 0) then
+ begin
+ FIOTASourceEditor.RemoveNotifier(FIndex);
+ FIndex := -1;
+ FIOTASourceEditor := nil;
+ end;
+end;
+
+procedure TDelphiAIDevIDEOTAEditorNotifier.ViewActivated(const View: IOTAEditView);
+begin
+
+end;
+
+procedure TDelphiAIDevIDEOTAEditorNotifier.ViewNotification(const View: IOTAEditView; Operation: TOperation);
+begin
+ if Operation = opInsert then
+ FINTAEditViewNotifierList.Add(TDelphiAIDevIDENTAEditViewNotifier.Create(FIOTASourceEditor.FileName, View));
+end;
+
+end.
diff --git a/Src/IDE/OTAIDENotifier/DelphiAIDev.IDE.OTAIDENotifier.pas b/Src/IDE/OTAIDENotifier/DelphiAIDev.IDE.OTAIDENotifier.pas
new file mode 100644
index 0000000..d31ed98
--- /dev/null
+++ b/Src/IDE/OTAIDENotifier/DelphiAIDev.IDE.OTAIDENotifier.pas
@@ -0,0 +1,134 @@
+unit DelphiAIDev.IDE.OTAIDENotifier;
+
+interface
+
+uses
+ System.SysUtils,
+ System.Classes,
+ System.Generics.Collections,
+ System.Types,
+ System.SyncObjs,
+ System.RegularExpressions,
+ Vcl.Dialogs,
+ Vcl.Graphics,
+ Vcl.Imaging.pngimage,
+ ToolsAPI,
+ DelphiAIDev.Utils,
+ DelphiAIDev.Consts,
+ DelphiAIDev.Types,
+ DelphiAIDev.CodeCompletion.Vars,
+ DelphiAIDev.IDE.OTAEditorNotifier;
+
+type
+ TDelphiAIDevIDEOTAIDENotifier = class(TNotifierObject, IOTANotifier, IOTAIDENotifier)
+ private
+ FEditorNotifiers: TList;
+ protected
+ procedure FileNotification(NotifyCode: TOTAFileNotification;const FileName: string; var Cancel: Boolean);
+ procedure BeforeCompile(const Project: IOTAProject; var Cancel: Boolean); overload;
+ procedure AfterCompile(Succeeded: Boolean); overload;
+ public
+ constructor Create;
+ destructor Destroy; override;
+ end;
+
+ procedure RegisterSelf;
+
+implementation
+
+var
+ Index: Integer;
+
+procedure RegisterSelf;
+begin
+ Index := (BorlandIDEServices as IOTAServices).AddNotifier(TDelphiAIDevIDEOTAIDENotifier.Create);
+end;
+
+procedure TDelphiAIDevIDEOTAIDENotifier.AfterCompile(Succeeded: Boolean);
+begin
+ //
+end;
+
+procedure TDelphiAIDevIDEOTAIDENotifier.BeforeCompile(const Project: IOTAProject; var Cancel: Boolean);
+begin
+ Cancel := False;
+end;
+
+constructor TDelphiAIDevIDEOTAIDENotifier.Create;
+var
+ LIOTAModuleServices: IOTAModuleServices;
+ i: Integer;
+ j: Integer;
+ LIOTAModule: IOTAModule;
+ LIOTASourceEditor: IOTASourceEditor;
+ LExt: string;
+begin
+ FEditorNotifiers := TList.Create;
+ LIOTAModuleServices := BorlandIDEServices as IOTAModuleServices;
+ for i := 0 to Pred(LIOTAModuleServices.ModuleCount) do
+ begin
+ LIOTAModule := LIOTAModuleServices.Modules[i];
+
+ for j := 0 to Pred(LIOTAModule.ModuleFileCount) do
+ if Supports(LIOTAModule.ModuleFileEditors[j], IOTASourceEditor, LIOTASourceEditor) then
+ begin
+ LExt := ExtractFileExt(LIOTASourceEditor.FileName).ToLower;
+ if LExt.Equals(TC4DExtensionsFiles.PAS.ToStringWithPoint) then
+ FEditorNotifiers.Add(TDelphiAIDevIDEOTAEditorNotifier.Create(LIOTASourceEditor));
+ end;
+ end;
+
+ inherited;
+end;
+
+destructor TDelphiAIDevIDEOTAIDENotifier.Destroy;
+var
+ i: Integer;
+begin
+ for i := 0 to Pred(FEditorNotifiers.Count) do
+ FEditorNotifiers[i].Destroyed;
+ FEditorNotifiers.Free;
+ inherited;
+end;
+
+procedure TDelphiAIDevIDEOTAIDENotifier.FileNotification(NotifyCode: TOTAFileNotification; const FileName: string; var Cancel: Boolean);
+var
+ LIOTAModule: IOTAModule;
+ LExtension: string;
+ i: Integer;
+ LIOTASourceEditor: IOTASourceEditor;
+begin
+ Cancel := False;
+
+ if NotifyCode = ofnFileOpened then
+ begin
+ LIOTAModule := (BorlandIDEServices as IOTAModuleServices).FindModule(FileName);
+
+ if not Assigned(LIOTAModule) then
+ Exit;
+
+ for i := 0 to Pred(LIOTAModule.ModuleFileCount) do
+ if Supports(LIOTAModule.ModuleFileEditors[i], IOTASourceEditor, LIOTASourceEditor) then
+ begin
+ LExtension := ExtractFileExt(LIOTASourceEditor.FileName).ToLower;
+ if LExtension.Equals(TC4DExtensionsFiles.PAS.ToStringWithPoint) then
+ FEditorNotifiers.Add(TDelphiAIDevIDEOTAEditorNotifier.Create(LIOTASourceEditor));
+ end;
+ end;
+
+ if (NotifyCode <> ofnFileOpened) and (NotifyCode <> ofnFileClosing) then
+ Exit;
+
+ LExtension := ExtractFileExt(FileName).ToLower;
+ if (LExtension <> TC4DExtensionsFiles.DPROJ.ToStringWithPoint)
+ and (LExtension <> TC4DExtensionsFiles.GROUPPROJ.ToStringWithPoint)
+ then
+ Exit;
+end;
+
+initialization
+
+finalization
+ if Index >= 0 then
+ (BorlandIDEServices as IOTAServices).RemoveNotifier(Index);
+end.
diff --git a/Src/IDE/Shortcuts/DelphiAIDev.IDE.Shortcuts.pas b/Src/IDE/Shortcuts/DelphiAIDev.IDE.Shortcuts.pas
deleted file mode 100644
index 6ca9253..0000000
--- a/Src/IDE/Shortcuts/DelphiAIDev.IDE.Shortcuts.pas
+++ /dev/null
@@ -1,124 +0,0 @@
-unit DelphiAIDev.IDE.Shortcuts;
-
-interface
-
-uses
- System.SysUtils,
- System.Classes,
- Winapi.Windows,
- Vcl.Menus,
- ToolsAPI,
- DelphiAIDev.Utils.CnWizard,
- DelphiAIDev.Chat.View;
-
-type
- TDelphiAIDevIDEShortcuts = class(TNotifierObject, IOTAKeyboardBinding)
- private
- //procedure KeyProcBlockReturn(const Context: IOTAKeyContext; KeyCode: TShortcut; var BindingResult: TKeyBindingResult);
- procedure KeyProcBlockReturnAndAlt(const Context: IOTAKeyContext; KeyCode: TShortcut; var BindingResult: TKeyBindingResult);
- protected
- function GetBindingType: TBindingType;
- function GetDisplayName: string;
- function GetName: string;
- procedure BindKeyboard(const BindingServices: IOTAKeyBindingServices);
- public
- class function New: IOTAKeyboardBinding;
- end;
-
-procedure RefreshRegister;
-
-implementation
-
-uses
- DelphiAIDev.Utils,
- DelphiAIDev.Utils.OTA;
-
-var
- Index: Integer = -1;
-
-procedure RegisterSelf;
-begin
- if Index < 0 then
- Index := TUtilsOTA.GetIOTAKeyboardServices.AddKeyboardBinding(TDelphiAIDevIDEShortcuts.New);
-end;
-
-procedure UnRegisterSelf;
-begin
- if Index >= 0 then
- begin
- TUtilsOTA.GetIOTAKeyboardServices.RemoveKeyboardBinding(Index);
- Index := -1;
- end;
-end;
-
-procedure RefreshRegister;
-begin
- UnRegisterSelf;
- RegisterSelf;
-end;
-
-class function TDelphiAIDevIDEShortcuts.New: IOTAKeyboardBinding;
-begin
- Result := Self.Create;
-end;
-
-function TDelphiAIDevIDEShortcuts.GetBindingType: TBindingType;
-begin
- Result := btPartial;
-end;
-
-function TDelphiAIDevIDEShortcuts.GetDisplayName: string;
-begin
- Result := Self.ClassName;
-end;
-
-function TDelphiAIDevIDEShortcuts.GetName: string;
-begin
- Result := Self.ClassName;
-end;
-
-procedure TDelphiAIDevIDEShortcuts.BindKeyboard(const BindingServices: IOTAKeyBindingServices);
-begin
-// if TUtilsOTA.CurrentProjectIsDelphiAIDeveloperDPROJ then
-// Exit;
-
- //BindingServices.AddKeyBinding([Shortcut(VK_RETURN, [])], Self.KeyProcBlockReturn, nil);
- BindingServices.AddKeyBinding([Shortcut(VK_RETURN, [ssAlt])], Self.KeyProcBlockReturnAndAlt, nil);
-end;
-
-//procedure TDelphiAIDevIDEShortcuts.KeyProcBlockReturn(const Context: IOTAKeyContext; KeyCode: TShortcut; var BindingResult: TKeyBindingResult);
-//begin
-// if KeyCode <> Shortcut(VK_RETURN, []) then
-// Exit;
-//
-// TUtils.AddLog(GetCurrentLineOrBlock(CnOtaGetTopMostEditView));
-// BindingResult := TKeyBindingResult.krNextProc; //krUnhandled;
-//end;
-
-procedure TDelphiAIDevIDEShortcuts.KeyProcBlockReturnAndAlt(const Context: IOTAKeyContext; KeyCode: TShortcut; var BindingResult: TKeyBindingResult);
-var
- LTextCurrentLineOrBlock: string;
-begin
- if KeyCode <> Shortcut(VK_RETURN, [ssAlt]) then
- Exit;
-
- //LTextCurrentLineOrBlock := Context.EditBuffer.EditBlock.Text;
- LTextCurrentLineOrBlock := GetCurrentLineOrBlock(CnOtaGetTopMostEditView).Trim;
- if LTextCurrentLineOrBlock.Trim.IsEmpty then
- Exit;
-
- if copy(LTextCurrentLineOrBlock, 1, 2) = '//' then
- LTextCurrentLineOrBlock := copy(LTextCurrentLineOrBlock, 3, LTextCurrentLineOrBlock.Length);
-
- DelphiAIDev.Chat.View.DelphiAIDevChatView.QuestionOnShow := LTextCurrentLineOrBlock;
- DelphiAIDev.Chat.View.DelphiAIDevChatViewShowDockableForm;
-
- BindingResult := TKeyBindingResult.krUnhandled; //krNextProc;
-end;
-
-initialization
-
-finalization
- UnRegisterSelf;
-
-end.
diff --git a/Src/KeyboardBinding/DelphiAIDev.KeyboardBinding.pas b/Src/KeyboardBinding/DelphiAIDev.KeyboardBinding.pas
new file mode 100644
index 0000000..ffa28da
--- /dev/null
+++ b/Src/KeyboardBinding/DelphiAIDev.KeyboardBinding.pas
@@ -0,0 +1,167 @@
+unit DelphiAIDev.KeyboardBinding;
+
+interface
+
+uses
+ System.SysUtils,
+ System.Classes,
+ Winapi.Windows,
+ Vcl.Menus,
+ ToolsAPI,
+ DelphiAIDev.Consts,
+ DelphiAIDev.Utils.CnWizard,
+ DelphiAIDev.Chat.View,
+ DelphiAIDev.CodeCompletion.Search,
+ DelphiAIDev.CodeCompletion.KeyTab,
+ DelphiAIDev.Settings;
+
+type
+ TDelphiAIDevKeyboardBinding = class(TNotifierObject, IOTAKeyboardBinding)
+ private
+ procedure KeyAltHome(const Context: IOTAKeyContext; KeyCode: TShortcut; var BindingResult: TKeyBindingResult);
+ procedure KeyTab(const Context: IOTAKeyContext; KeyCode: TShortcut; var BindingResult: TKeyBindingResult);
+ procedure CodeCompletionSearch(const Context: IOTAKeyContext; KeyCode: TShortcut; var BindingResult: TKeyBindingResult);
+ //procedure HandleKeyBinding(const Context: IOTAKeyContext; KeyCode: TShortcut; var BindingResult: TKeyBindingResult);
+ protected
+ function GetBindingType: TBindingType;
+ function GetDisplayName: string;
+ function GetName: string;
+ procedure BindKeyboard(const BindingServices: IOTAKeyBindingServices);
+ public
+ class function New: IOTAKeyboardBinding;
+ end;
+
+procedure RefreshRegister;
+
+implementation
+
+uses
+ DelphiAIDev.Utils,
+ DelphiAIDev.Utils.OTA,
+ DelphiAIDev.CodeCompletion.Vars;
+
+var
+ Index: Integer = -1;
+
+procedure RegisterSelf;
+begin
+ if Index < 0 then
+ Index := TUtilsOTA.GetIOTAKeyboardServices.AddKeyboardBinding(TDelphiAIDevKeyboardBinding.New);
+end;
+
+procedure UnRegisterSelf;
+begin
+ if Index >= 0 then
+ begin
+ TUtilsOTA.GetIOTAKeyboardServices.RemoveKeyboardBinding(Index);
+ Index := -1;
+ end;
+end;
+
+procedure RefreshRegister;
+begin
+ UnRegisterSelf;
+ RegisterSelf;
+end;
+
+class function TDelphiAIDevKeyboardBinding.New: IOTAKeyboardBinding;
+begin
+ Result := Self.Create;
+end;
+
+function TDelphiAIDevKeyboardBinding.GetBindingType: TBindingType;
+begin
+ Result := btPartial;
+end;
+
+function TDelphiAIDevKeyboardBinding.GetDisplayName: string;
+begin
+ Result := Self.ClassName;
+end;
+
+function TDelphiAIDevKeyboardBinding.GetName: string;
+begin
+ Result := Self.ClassName;
+end;
+
+procedure TDelphiAIDevKeyboardBinding.BindKeyboard(const BindingServices: IOTAKeyBindingServices);
+var
+ LShortcut: string;
+begin
+ //if TUtilsOTA.CurrentProjectIsDelphiAIDeveloperDPROJ then
+ // Exit;
+
+ LShortcut := TConsts.CODE_COMPLETION_SHORTCUT_INVOKE;
+ if not Trim(TDelphiAIDevSettings.GetInstance.CodeCompletionShortcutInvoke).IsEmpty then
+ LShortcut := TDelphiAIDevSettings.GetInstance.CodeCompletionShortcutInvoke;
+
+ BindingServices.AddKeyBinding([TextToShortCut(LShortcut)], Self.CodeCompletionSearch, nil);
+
+ BindingServices.AddKeyBinding([Shortcut(VK_TAB, [])], Self.KeyTab, nil);
+ BindingServices.AddKeyBinding([Shortcut(VK_HOME, [ssAlt])], Self.KeyAltHome, nil);
+
+// //**
+// BindingServices.AddKeyBinding([], HandleKeyBinding, nil);
+// //**
+end;
+
+////**
+//procedure TDelphiAIDevKeyboardBinding.HandleKeyBinding(const Context: IOTAKeyContext; KeyCode: TShortcut; var BindingResult: TKeyBindingResult);
+//var
+// Key: Word;
+//begin
+// //Key := Word(KeyCode and $FF); // Extrai o cdigo da tecla
+// //TUtils.AddLog('Tecla pressionada: ' + IntToStr(Key));
+// TUtils.ShowMsg('Aqui');
+// BindingResult := TKeyBindingResult.krNextProc
+//end;
+////**
+
+procedure TDelphiAIDevKeyboardBinding.CodeCompletionSearch(const Context: IOTAKeyContext; KeyCode: TShortcut; var BindingResult: TKeyBindingResult);
+begin
+ try
+ if TDelphiAIDevSettings.GetInstance.CodeCompletionUse then
+ TDelphiAIDevCodeCompletionSearch.New.Process(Context);
+ finally
+ //BindingResult := TKeyBindingResult.krUnhandled;
+ BindingResult := TKeyBindingResult.krNextProc; //krHandled;
+ end;
+end;
+
+procedure TDelphiAIDevKeyboardBinding.KeyTab(const Context: IOTAKeyContext; KeyCode: TShortcut; var BindingResult: TKeyBindingResult);
+begin
+// if KeyCode <> Shortcut(VK_TAB, []) then
+// Exit;
+
+ BindingResult := TKeyBindingResult.krUnhandled;
+
+ if TDelphiAIDevCodeCompletionVars.GetInstance.LineIni > 0 then
+ begin
+ TDelphiAIDevCodeCompletionKeyTab.New.Process(Context);
+ BindingResult := TKeyBindingResult.krNextProc; //krHandled;
+ end;
+end;
+
+procedure TDelphiAIDevKeyboardBinding.KeyAltHome(const Context: IOTAKeyContext; KeyCode: TShortcut; var BindingResult: TKeyBindingResult);
+var
+ LTextCurrentLineOrBlock: string;
+begin
+ LTextCurrentLineOrBlock := GetCurrentLineOrBlock(CnOtaGetTopMostEditView).Trim;
+ if LTextCurrentLineOrBlock.Trim.IsEmpty then
+ Exit;
+
+ if copy(LTextCurrentLineOrBlock, 1, 2) = '//' then
+ LTextCurrentLineOrBlock := copy(LTextCurrentLineOrBlock, 3, LTextCurrentLineOrBlock.Length);
+
+ DelphiAIDev.Chat.View.DelphiAIDevChatView.QuestionOnShow := LTextCurrentLineOrBlock;
+ DelphiAIDev.Chat.View.DelphiAIDevChatViewShowDockableForm;
+
+ BindingResult := TKeyBindingResult.krUnhandled;
+end;
+
+initialization
+
+finalization
+ UnRegisterSelf;
+
+end.
diff --git a/Src/MainMenu/DelphiAIDev.MainMenu.Clicks.pas b/Src/MainMenu/DelphiAIDev.MainMenu.Clicks.pas
index f07deb0..5dd7993 100644
--- a/Src/MainMenu/DelphiAIDev.MainMenu.Clicks.pas
+++ b/Src/MainMenu/DelphiAIDev.MainMenu.Clicks.pas
@@ -10,10 +10,11 @@ interface
type
TDelphiAIDevIDEMainMenuClicks = class
- private
public
class procedure ChatClick(Sender: TObject);
class procedure DefaultsQuestionsClick(Sender: TObject);
+ class procedure DatabasesAddClick(Sender: TObject);
+ class procedure DatabasesChatClick(Sender: TObject);
class procedure SettingsClick(Sender: TObject);
class procedure AboutClick(Sender: TObject);
end;
@@ -25,10 +26,11 @@ implementation
DelphiAIDev.Utils.OTA,
DelphiAIDev.Chat.View,
DelphiAIDev.DefaultsQuestions.View,
+ DelphiAIDev.DB.Registers.View,
+ DelphiAIDev.DB.Chat.View,
DelphiAIDev.Settings.View,
DelphiAIDev.View.About;
-
class procedure TDelphiAIDevIDEMainMenuClicks.ChatClick(Sender: TObject);
begin
DelphiAIDev.Chat.View.DelphiAIDevChatViewShowDockableForm;
@@ -46,6 +48,23 @@ class procedure TDelphiAIDevIDEMainMenuClicks.DefaultsQuestionsClick(Sender: TOb
end;
end;
+class procedure TDelphiAIDevIDEMainMenuClicks.DatabasesAddClick(Sender: TObject);
+var
+ LView: TDelphiAIDevDBRegistersView;
+begin
+ LView := TDelphiAIDevDBRegistersView.Create(nil);
+ try
+ LView.ShowModal;
+ finally
+ FreeAndNil(LView);
+ end;
+end;
+
+class procedure TDelphiAIDevIDEMainMenuClicks.DatabasesChatClick(Sender: TObject);
+begin
+ DelphiAIDev.DB.Chat.View.DelphiAIDevDBChatViewShowDockableForm;
+end;
+
class procedure TDelphiAIDevIDEMainMenuClicks.SettingsClick(Sender: TObject);
begin
DelphiAIDevSettingsView := TDelphiAIDevSettingsView.Create(nil);
diff --git a/Src/MainMenu/DelphiAIDev.MainMenu.Register.pas b/Src/MainMenu/DelphiAIDev.MainMenu.Register.pas
index aa7c6f0..d5e88c7 100644
--- a/Src/MainMenu/DelphiAIDev.MainMenu.Register.pas
+++ b/Src/MainMenu/DelphiAIDev.MainMenu.Register.pas
@@ -39,7 +39,7 @@ procedure RegisterSelf;
begin
DelphiAIDevIDEMainMenuRegister := TDelphiAIDevIDEMainMenuRegister.Create;
- if(Supports(TObject(DelphiAIDevIDEMainMenuRegister), IOTAWizard, LIOTAWizard))then
+ if Supports(TObject(DelphiAIDevIDEMainMenuRegister), IOTAWizard, LIOTAWizard) then
IndexPlugin := TUtilsOTA.GetIOTAWizardServices.AddWizard(LIOTAWizard);
end;
diff --git a/Src/MainMenu/DelphiAIDev.MainMenu.pas b/Src/MainMenu/DelphiAIDev.MainMenu.pas
index 65d8dac..2c25baf 100644
--- a/Src/MainMenu/DelphiAIDev.MainMenu.pas
+++ b/Src/MainMenu/DelphiAIDev.MainMenu.pas
@@ -39,7 +39,7 @@ implementation
class function TDelphiAIDevIDEMainMenu.GetInstance: IDelphiAIDevIDEMainMenu;
begin
- if(not Assigned(Instance))then
+ if not Assigned(Instance) then
Instance := Self.Create;
Result := Instance;
end;
@@ -51,45 +51,56 @@ constructor TDelphiAIDevIDEMainMenu.Create;
destructor TDelphiAIDevIDEMainMenu.Destroy;
begin
- if(Assigned(FMenuItemC4D))then
+ if Assigned(FMenuItemC4D) then
FreeAndNil(FMenuItemC4D);
inherited;
end;
procedure TDelphiAIDevIDEMainMenu.CreateMenus;
+var
+ LImgList: TDelphiAIDevIDEImageListMain;
begin
+ LImgList := TDelphiAIDevIDEImageListMain.GetInstance;
+
Self.CreateMenuDelphiAIDeveloperInIDEMenu;
Self.CreateSubMenu(TConsts.MENU_IDE_CHAT_NAME,
TConsts.MENU_IDE_CHAT_CAPTION,
TDelphiAIDevIDEMainMenuClicks.ChatClick,
- TDelphiAIDevIDEImageListMain.GetInstance.ImgIndexMessage,
- Self.GetShortCutStrChat
- );
+ LImgList.ImgIndexMessage,
+ Self.GetShortCutStrChat);
- Self.CreateSubMenu('C4DSeparator40', '-', nil);
+ Self.CreateSubMenu(TConsts.PREFIX_NAME_SEPARATOR + '10', '-', nil);
Self.CreateSubMenu(TConsts.MENU_IDE_DEFAULTS_QUESTIONS_NAME,
TConsts.MENU_IDE_DEFAULTS_QUESTIONS_CAPTION,
TDelphiAIDevIDEMainMenuClicks.DefaultsQuestionsClick,
- TDelphiAIDevIDEImageListMain.GetInstance.ImgQuestion
- );
+ LImgList.ImgQuestion);
+
+ Self.CreateSubMenu(TConsts.PREFIX_NAME_SEPARATOR + '20', '-', nil);
- Self.CreateSubMenu('C4DSeparator50', '-', nil);
+ Self.CreateSubMenu(TConsts.MENU_IDE_DEFAULTS_DATABASES_ADD_NAME,
+ TConsts.MENU_IDE_DEFAULTS_DATABASES_ADD_Caption,
+ TDelphiAIDevIDEMainMenuClicks.DatabasesAddClick,
+ LImgList.ImgDatabaseAdd);
+
+ Self.CreateSubMenu(TConsts.MENU_IDE_DEFAULTS_DATABASES_CHAT_NAME,
+ TConsts.MENU_IDE_DEFAULTS_DATABASES_CHAT_CAPTION,
+ TDelphiAIDevIDEMainMenuClicks.DatabasesChatClick,
+ LImgList.ImgDatabaseExecute);
+
+ Self.CreateSubMenu(TConsts.PREFIX_NAME_SEPARATOR + '30', '-', nil);
Self.CreateSubMenu(TConsts.MENU_IDE_SETTINGS_NAME,
TConsts.MENU_IDE_SETTINGS_CAPTION,
TDelphiAIDevIDEMainMenuClicks.SettingsClick,
- TDelphiAIDevIDEImageListMain.GetInstance.ImgIndexGear
- );
-
+ LImgList.ImgIndexGear);
- Self.CreateSubMenu('C4DSeparator90', '-', nil);
+ Self.CreateSubMenu(TConsts.PREFIX_NAME_SEPARATOR + '40', '-', nil);
Self.CreateSubMenu(TConsts.MENU_IDE_ABOUT_NAME,
TConsts.MENU_IDE_ABOUT_CAPTION,
TDelphiAIDevIDEMainMenuClicks.AboutClick,
- TDelphiAIDevIDEImageListMain.GetInstance.ImgIndexC4D_Logo
- );
+ LImgList.ImgIndexC4D_Logo);
end;
procedure TDelphiAIDevIDEMainMenu.CreateMenuDelphiAIDeveloperInIDEMenu;
@@ -98,7 +109,7 @@ procedure TDelphiAIDevIDEMainMenu.CreateMenuDelphiAIDeveloperInIDEMenu;
LMenuItemTools: TMenuItem;
begin
FMenuItemC4D := TMenuItem(FMainMenuIDE.FindComponent(TConsts.ITEM_MENU_C4DDelphiAIDev_NAME));
- if(Assigned(FMenuItemC4D))then
+ if Assigned(FMenuItemC4D) then
FreeAndNil(FMenuItemC4D);
FMenuItemC4D := TMenuItem.Create(FMainMenuIDE);
@@ -106,14 +117,14 @@ procedure TDelphiAIDevIDEMainMenu.CreateMenuDelphiAIDeveloperInIDEMenu;
FMenuItemC4D.Caption := TConsts.ITEM_MENU_C4DDelphiAIDev_CAPTION;
LMenuItemTabs := FMainMenuIDE.Items.Find('Tabs');
- if(Assigned(LMenuItemTabs))then
+ if Assigned(LMenuItemTabs) then
begin
FMainMenuIDE.Items.Insert(FMainMenuIDE.Items.IndexOf(LMenuItemTabs), FMenuItemC4D);
Exit;
end;
LMenuItemTools := FMainMenuIDE.Items.Find('Tools');
- if(Assigned(LMenuItemTools))then
+ if Assigned(LMenuItemTools) then
begin
FMainMenuIDE.Items.Insert(FMainMenuIDE.Items.IndexOf(LMenuItemTools) + 1, FMenuItemC4D);
Exit;
@@ -138,13 +149,13 @@ function TDelphiAIDevIDEMainMenu.CreateSubMenu(AName: string; ACaption: string;
function TDelphiAIDevIDEMainMenu.GetShortCutStrChat: string;
begin
- Result := 'Ctrl+Shift+Alt+A';
+ Result := TConsts.SHORTCUT_CHAT_DEFAULT;
end;
initialization
finalization
- if(Assigned(Instance))then
+ if Assigned(Instance) then
Instance := nil;
end.
diff --git a/Src/MetaInfo/DelphiAIDev.MetaInfo.pas b/Src/MetaInfo/DelphiAIDev.MetaInfo.pas
new file mode 100644
index 0000000..e12b6dc
--- /dev/null
+++ b/Src/MetaInfo/DelphiAIDev.MetaInfo.pas
@@ -0,0 +1,219 @@
+unit DelphiAIDev.MetaInfo;
+
+interface
+
+uses
+ System.SysUtils,
+ System.Classes,
+ System.Json,
+ FireDAC.Stan.Intf,
+ FireDAC.Stan.Option,
+ FireDAC.Stan.Param,
+ FireDAC.Stan.Error,
+ FireDAC.DatS,
+ FireDAC.Phys.Intf,
+ FireDAC.DApt.Intf,
+ FireDAC.Stan.Async,
+ FireDAC.DApt,
+ Data.DB,
+ FireDAC.Comp.DataSet,
+ FireDAC.Comp.Client,
+ C4D.Conn,
+ DelphiAIDev.Utils,
+ DelphiAIDev.Types,
+ DelphiAIDev.DB.Registers.Fields,
+ DelphiAIDev.DB.Registers.Model;
+
+type
+ TDelphiAIDevMetaInfo = class
+ private
+ FField: TDelphiAIDevDBRegistersFields;
+ FC4DConn: IC4DConn;
+ FMetaInfoTables: TFDMetaInfoQuery;
+ FMetaInfoFields: TFDMetaInfoQuery;
+ FAddFieldLength: Boolean;
+ FCompressData: Boolean;
+
+ FKeyName: string;
+ FKeyTYPE: string;
+ FKeyLength: string;
+ FKeyColumns: string;
+
+ procedure ConfigConn;
+ procedure SaveJsonInFolder(const AJSONObject: TJSONObject);
+ procedure SaveGenerationDataToField;
+ function GetInstructionsNamesKeysCompress: string;
+ procedure ProcessNamesKeys;
+ public
+ constructor Create(const AField: TDelphiAIDevDBRegistersFields);
+ destructor Destroy; override;
+ procedure Process;
+
+ property AddFieldLength: Boolean read FAddFieldLength write FAddFieldLength;
+ property CompressData: Boolean read FCompressData write FCompressData;
+ end;
+
+implementation
+
+const
+ KEY_NAME = 'name';
+ KEY_TYPE = 'type';
+ KEY_LENGTH = 'length';
+ KEY_COLUMNS = 'columns';
+
+ KEY_NAME_SHORT = 'n';
+ KEY_TYPE_SHORT = 't';
+ KEY_LENGTH_SHORT = 'l';
+ KEY_COLUMNS_SHORT = 'c';
+
+constructor TDelphiAIDevMetaInfo.Create(const AField: TDelphiAIDevDBRegistersFields);
+begin
+ FAddFieldLength := False;
+ FCompressData := False;
+
+ FField := AField;
+ FC4DConn := TC4DConn.New;
+ Self.ConfigConn;
+
+ FMetaInfoTables := TFDMetaInfoQuery.Create(nil);
+ FMetaInfoTables.Connection := TFDConnection(FC4DConn.Connection.Component);
+ FMetaInfoTables.MetaInfoKind := mkTables;
+
+ FMetaInfoFields := TFDMetaInfoQuery.Create(nil);
+ FMetaInfoFields.Connection := TFDConnection(FC4DConn.Connection.Component);
+ FMetaInfoFields.MetaInfoKind := mkTableFields;
+end;
+
+destructor TDelphiAIDevMetaInfo.Destroy;
+begin
+ FMetaInfoFields.Free;
+ FMetaInfoTables.Free;
+ inherited;
+end;
+
+procedure TDelphiAIDevMetaInfo.ConfigConn;
+begin
+ FC4DConn.Configs
+ .DriverID(FField.DriverID)
+ .Host(FField.Host)
+ .UserName(FField.User)
+ .Password(FField.Password)
+ .Port(FField.Port)
+ .Database(FField.DatabaseName)
+ .VendorLib(FField.VendorLib);
+end;
+
+procedure TDelphiAIDevMetaInfo.ProcessNamesKeys;
+begin
+ FKeyName := KEY_NAME;
+ FKeyTYPE := KEY_TYPE;
+ FKeyLength := KEY_LENGTH;
+ FKeyColumns := KEY_COLUMNS;
+
+ if FCompressData then
+ begin
+ FKeyName := KEY_NAME_SHORT;
+ FKeyTYPE := KEY_TYPE_SHORT;
+ FKeyLength := KEY_LENGTH_SHORT;
+ FKeyColumns := KEY_COLUMNS_SHORT;
+ end;
+end;
+
+function TDelphiAIDevMetaInfo.GetInstructionsNamesKeysCompress: string;
+begin
+ Result := 'Some JSON keys have been abbreviated, here is the legend for the abbreviations: ' +
+ Format('%s = %s; ', [KEY_NAME_SHORT, KEY_NAME]) +
+ Format('%s = %s; ', [KEY_TYPE_SHORT, KEY_TYPE]) +
+ Format('%s = %s; ', [KEY_LENGTH_SHORT, KEY_LENGTH]) +
+ Format('%s = %s. ', [KEY_COLUMNS_SHORT, KEY_COLUMNS]);
+end;
+
+procedure TDelphiAIDevMetaInfo.Process;
+var
+ LJSONObjAll: TJSONObject;
+ LJSONArrayTables: TJSONArray;
+ LJSONObjTable: TJSONObject;
+ LJSONArrayColumns: TJSONArray;
+ LJSONObjColumn: TJSONObject;
+begin
+ Self.ProcessNamesKeys;
+ FC4DConn.Connection.Open;
+
+ FMetaInfoTables.Open;
+ if FMetaInfoTables.IsEmpty then
+ TUtils.ShowMsgAndAbort('No tables could be found in the current connection');
+
+ LJSONObjAll := TJSONObject.Create;
+ try
+ if FCompressData then
+ LJSONObjAll.AddPair('instructions', Self.GetInstructionsNamesKeysCompress);
+
+ LJSONObjAll.AddPair('SGBD (database)', FField.DriverID.ToString);
+ LJSONObjAll.AddPair('database name', FField.DatabaseName);
+
+ LJSONArrayTables := TJSONArray.Create;
+
+ FMetaInfoTables.First;
+ while not FMetaInfoTables.Eof do
+ begin
+ FMetaInfoFields.Close;
+ FMetaInfoFields.ObjectName := FMetaInfoTables.FieldByName('TABLE_NAME').AsString;
+ FMetaInfoFields.Open;
+
+ LJSONArrayColumns := TJSONArray.Create;
+ FMetaInfoFields.First;
+ while not FMetaInfoFields.Eof do
+ begin
+ LJSONObjColumn := TJSONObject.Create;
+ LJSONObjColumn.AddPair(FKeyName, TJSONString.Create(FMetaInfoFields.FieldByName('COLUMN_NAME').AsString));
+ LJSONObjColumn.AddPair(FKeyType, TJSONString.Create(FMetaInfoFields.FieldByName('COLUMN_TYPENAME').AsString));
+ if FAddFieldLength then
+ LJSONObjColumn.AddPair(FKeyLength, TJSONNumber.Create(FMetaInfoFields.FieldByName('COLUMN_LENGTH').AsInteger));
+
+ LJSONArrayColumns.AddElement(LJSONObjColumn);
+ FMetaInfoFields.Next;
+ end;
+
+ LJSONObjTable := TJSONObject.Create;
+ LJSONObjTable.AddPair(FKeyName, TJSONString.Create(FMetaInfoTables.FieldByName('TABLE_NAME').AsString));
+ LJSONObjTable.AddPair(FKeyColumns, LJSONArrayColumns);
+ LJSONArrayTables.AddElement(LJSONObjTable);
+
+ FMetaInfoTables.Next;
+ end;
+
+ LJSONObjAll.AddPair('tables', LJSONArrayTables);
+ Self.SaveJsonInFolder(LJSONObjAll);
+ Self.SaveGenerationDataToField;
+
+ TUtils.ShowV('Process completed');
+ finally
+ LJSONObjAll.Free;
+ end;
+end;
+
+procedure TDelphiAIDevMetaInfo.SaveGenerationDataToField;
+begin
+ FField.LastReferences := Now;
+ TDelphiAIDevDBRegistersModel.New.SaveOrEditData(FField);
+end;
+
+procedure TDelphiAIDevMetaInfo.SaveJsonInFolder(const AJSONObject: TJSONObject);
+var
+ LStringList: TStringList;
+begin
+ LStringList := TStringList.Create;
+ try
+// {$IF CompilerVersion <= 32.0} //Tokyo
+// LStringList.Text := AJSONObject.ToJSON;
+// {$ELSE}
+// LStringList.Text := AJSONObject.Format(2);
+// {$ENDIF}
+ LStringList.Text := AJSONObject.ToString;
+ LStringList.SaveToFile(TUtils.GetPathFolderMetaInfo + FField.Guid + '.json');
+ finally
+ LStringList.Free;
+ end;
+end;
+
+end.
diff --git a/Src/PopupMenuProjects/DelphiAIDev.PopupMenuProjects.Item.pas b/Src/PopupMenuProjects/DelphiAIDev.PopupMenuProjects.Item.pas
new file mode 100644
index 0000000..2e3857b
--- /dev/null
+++ b/Src/PopupMenuProjects/DelphiAIDev.PopupMenuProjects.Item.pas
@@ -0,0 +1,173 @@
+unit DelphiAIDev.PopupMenuProjects.Item;
+
+interface
+
+uses
+ System.SysUtils,
+ System.Classes,
+ ToolsAPI,
+ DelphiAIDev.Types;
+
+type
+ TDelphiAIDevPopupMenuProjectsItem = class(TNotifierObject, IOTALocalMenu, IOTAProjectManagerMenu)
+ private
+ FCaption: string;
+ FIsMultiSelectable: Boolean;
+ FChecked: Boolean;
+ FEnabled: Boolean;
+ FHelpContext: Integer;
+ FName: string;
+ FParent: string;
+ FPosition: Integer;
+ FVerb: string;
+ protected
+ FProject: IOTAProject;
+ FOnExecute: TC4DWizardMenuContextList;
+ function GetCaption: string;
+ function GetChecked: Boolean;
+ function GetEnabled: Boolean;
+ function GetHelpContext: Integer;
+ function GetName: string;
+ function GetParent: string;
+ function GetPosition: Integer;
+ function GetVerb: string;
+ procedure SetCaption(const Value: string);
+ procedure SetChecked(Value: Boolean);
+ procedure SetEnabled(Value: Boolean);
+ procedure SetHelpContext(Value: Integer);
+ procedure SetName(const Value: string);
+ procedure SetParent(const Value: string);
+ procedure SetPosition(Value: Integer);
+ procedure SetVerb(const Value: string);
+ function GetIsMultiSelectable: Boolean;
+ procedure SetIsMultiSelectable(Value: Boolean);
+ procedure Execute(const MenuContextList: IInterfaceList); virtual;
+ function PreExecute(const MenuContextList: IInterfaceList): Boolean;
+ function PostExecute(const MenuContextList: IInterfaceList): Boolean;
+ public
+ class function New(OnExecute: TC4DWizardMenuContextList): IOTAProjectManagerMenu; overload;
+ constructor Create(OnExecute: TC4DWizardMenuContextList); overload;
+ end;
+
+implementation
+
+class function TDelphiAIDevPopupMenuProjectsItem.New(OnExecute: TC4DWizardMenuContextList): IOTAProjectManagerMenu;
+begin
+ Result := Self.Create(OnExecute);
+end;
+
+constructor TDelphiAIDevPopupMenuProjectsItem.Create(OnExecute: TC4DWizardMenuContextList);
+begin
+ FOnExecute := OnExecute;
+ FEnabled := True;
+ FChecked := False;
+ FIsMultiSelectable := False;
+end;
+
+procedure TDelphiAIDevPopupMenuProjectsItem.Execute(const MenuContextList: IInterfaceList);
+begin
+ if Assigned(FOnExecute) then
+ FOnExecute(MenuContextList);
+end;
+
+function TDelphiAIDevPopupMenuProjectsItem.GetCaption: string;
+begin
+ Result := FCaption;
+end;
+
+function TDelphiAIDevPopupMenuProjectsItem.GetChecked: Boolean;
+begin
+ Result := FChecked;
+end;
+
+function TDelphiAIDevPopupMenuProjectsItem.GetEnabled: Boolean;
+begin
+ Result := FEnabled;
+end;
+
+function TDelphiAIDevPopupMenuProjectsItem.GetHelpContext: Integer;
+begin
+ Result := FHelpContext;
+end;
+
+function TDelphiAIDevPopupMenuProjectsItem.GetIsMultiSelectable: Boolean;
+begin
+ Result := FIsMultiSelectable;
+end;
+
+function TDelphiAIDevPopupMenuProjectsItem.GetName: string;
+begin
+ Result := FName;
+end;
+
+function TDelphiAIDevPopupMenuProjectsItem.GetParent: string;
+begin
+ Result := FParent;
+end;
+
+function TDelphiAIDevPopupMenuProjectsItem.GetPosition: Integer;
+begin
+ Result := FPosition;
+end;
+
+function TDelphiAIDevPopupMenuProjectsItem.GetVerb: string;
+begin
+ Result := FVerb;
+end;
+
+function TDelphiAIDevPopupMenuProjectsItem.PostExecute(const MenuContextList: IInterfaceList): Boolean;
+begin
+ Result := True;
+end;
+
+function TDelphiAIDevPopupMenuProjectsItem.PreExecute(const MenuContextList: IInterfaceList): Boolean;
+begin
+ Result := True;
+end;
+
+procedure TDelphiAIDevPopupMenuProjectsItem.SetCaption(const Value: string);
+begin
+ FCaption := Value;
+end;
+
+procedure TDelphiAIDevPopupMenuProjectsItem.SetChecked(Value: Boolean);
+begin
+ FChecked := Value;
+end;
+
+procedure TDelphiAIDevPopupMenuProjectsItem.SetEnabled(Value: Boolean);
+begin
+ FEnabled := Value;
+end;
+
+procedure TDelphiAIDevPopupMenuProjectsItem.SetHelpContext(Value: Integer);
+begin
+ FHelpContext := Value;
+end;
+
+procedure TDelphiAIDevPopupMenuProjectsItem.SetIsMultiSelectable(Value: Boolean);
+begin
+ FIsMultiSelectable := Value;
+end;
+
+procedure TDelphiAIDevPopupMenuProjectsItem.SetName(const Value: string);
+begin
+ FName := Value;
+end;
+
+procedure TDelphiAIDevPopupMenuProjectsItem.SetParent(const Value: string);
+begin
+ FParent := Value;
+end;
+
+procedure TDelphiAIDevPopupMenuProjectsItem.SetPosition(Value: Integer);
+begin
+ FPosition := Value;
+end;
+
+procedure TDelphiAIDevPopupMenuProjectsItem.SetVerb(const Value: string);
+begin
+ FVerb := Value;
+end;
+
+end.
diff --git a/Src/PopupMenuProjects/DelphiAIDev.PopupMenuProjects.OnExecute.pas b/Src/PopupMenuProjects/DelphiAIDev.PopupMenuProjects.OnExecute.pas
new file mode 100644
index 0000000..74cba54
--- /dev/null
+++ b/Src/PopupMenuProjects/DelphiAIDev.PopupMenuProjects.OnExecute.pas
@@ -0,0 +1,50 @@
+unit DelphiAIDev.PopupMenuProjects.OnExecute;
+
+interface
+
+uses
+ System.SysUtils,
+ System.Classes,
+ ToolsAPI;
+
+type
+ TDelphiAIDevPopupMenuProjectsOnExecute = class
+ private
+ FIOTAProject: IOTAProject;
+ procedure CheckFileNameProject;
+ public
+ procedure EditInformation(const MenuContextList: IInterfaceList);
+ property OTAProject: IOTAProject write FIOTAProject;
+ end;
+
+implementation
+
+uses
+ DelphiAIDev.Utils,
+ DelphiAIDev.Projects.AddEdit.View;
+
+procedure TDelphiAIDevPopupMenuProjectsOnExecute.CheckFileNameProject;
+begin
+ if FIOTAProject.FileName.Trim.IsEmpty then
+ TUtils.ShowMsgAndAbort('Project file name is empty');
+
+// if not System.SysUtils.FileExists(FIOTAProject.FileName) then
+// TUtils.ShowMsgAndAbort('Project file not found');
+end;
+
+procedure TDelphiAIDevPopupMenuProjectsOnExecute.EditInformation(const MenuContextList: IInterfaceList);
+var
+ LView: TDelphiAIDevProjectsAddEditView;
+begin
+ Self.CheckFileNameProject;
+
+ LView := TDelphiAIDevProjectsAddEditView.Create(nil);
+ try
+ LView.OTAProject := FIOTAProject;
+ LView.ShowModal;
+ finally
+ LView.Free;
+ end;
+end;
+
+end.
diff --git a/Src/PopupMenuProjects/DelphiAIDev.PopupMenuProjects.pas b/Src/PopupMenuProjects/DelphiAIDev.PopupMenuProjects.pas
new file mode 100644
index 0000000..8fb874a
--- /dev/null
+++ b/Src/PopupMenuProjects/DelphiAIDev.PopupMenuProjects.pas
@@ -0,0 +1,119 @@
+unit DelphiAIDev.PopupMenuProjects;
+
+interface
+
+uses
+ System.SysUtils,
+ System.Classes,
+ ToolsAPI,
+ DelphiAIDev.Types,
+ DelphiAIDev.PopupMenuProjects.Item,
+ DelphiAIDev.PopupMenuProjects.OnExecute;
+
+type
+ TC4DWizardIDEPopupMenuNotifier = class(TNotifierObject, IOTAProjectMenuItemCreatorNotifier)
+ private
+ FOnExecute: TDelphiAIDevPopupMenuProjectsOnExecute;
+ FIOTAProject: IOTAProject;
+ FPosition: Integer;
+ function AddItemInMenu(const ACaption: string): IOTAProjectManagerMenu;
+ function AddSubItemInMenu(const ACaption: string; const AOnExecute: TC4DWizardMenuContextList = nil;
+ const AChecked: Boolean = False): IOTAProjectManagerMenu;
+ protected
+ procedure AddMenu(const Project: IOTAProject; const IdentList: TStrings;
+ const ProjectManagerMenuList: IInterfaceList; IsMultiSelect: Boolean);
+ public
+ class function New: IOTAProjectMenuItemCreatorNotifier;
+ constructor Create;
+ destructor Destroy; override;
+ end;
+
+procedure RegisterSelf;
+
+implementation
+
+uses
+ DelphiAIDev.Consts,
+ DelphiAIDev.Utils,
+ DelphiAIDev.Utils.OTA;
+
+var
+ Index: Integer = -1;
+
+procedure RegisterSelf;
+begin
+ Index := TUtilsOTA
+ .GetIOTAProjectManager
+ .AddMenuItemCreatorNotifier(TC4DWizardIDEPopupMenuNotifier.New);
+end;
+
+class function TC4DWizardIDEPopupMenuNotifier.New: IOTAProjectMenuItemCreatorNotifier;
+begin
+ Result := Self.Create;
+end;
+
+constructor TC4DWizardIDEPopupMenuNotifier.Create;
+begin
+ FOnExecute := TDelphiAIDevPopupMenuProjectsOnExecute.Create;
+end;
+
+destructor TC4DWizardIDEPopupMenuNotifier.Destroy;
+begin
+ FOnExecute.Free;
+ inherited;
+end;
+
+procedure TC4DWizardIDEPopupMenuNotifier.AddMenu(const Project: IOTAProject; const IdentList: TStrings;
+ const ProjectManagerMenuList: IInterfaceList; IsMultiSelect: Boolean);
+begin
+ if not Assigned(ProjectManagerMenuList) then
+ Exit;
+
+ if IdentList.IndexOf(sProjectContainer) >= 0 then
+ FPosition := pmmpUninstall
+ else if IdentList.IndexOf(sProjectGroupContainer) >= 0 then
+ FPosition := pmmpRename
+ else
+ Exit;
+
+ FIOTAProject := Project;
+ FOnExecute.OTAProject := FIOTAProject;
+
+ FPosition := FPosition + 201;
+ ProjectManagerMenuList.Add(Self.AddItemInMenu('-'));
+ ProjectManagerMenuList.Add(Self.AddItemInMenu(TConsts.ITEM_POPUP_MENU_PROJ_CAPTION));
+
+ ProjectManagerMenuList.Add(Self.AddSubItemInMenu(TConsts.ITEM_POPUP_MENU_PROJ_EditInformation_CAPTION,
+ FOnExecute.EditInformation));
+end;
+
+function TC4DWizardIDEPopupMenuNotifier.AddItemInMenu(const ACaption: string): IOTAProjectManagerMenu;
+begin
+ Result := TDelphiAIDevPopupMenuProjectsItem.New({$IF CompilerVersion = 30.0} TC4DWizardMenuContextList(nil) {$ELSE} nil {$ENDIF});
+ Result.Caption := ACaption;
+ Result.Verb := ACaption;
+ Result.Parent := '';
+ Result.Position := TUtils.IncInt(FPosition);
+ Result.Checked := False;
+ Result.IsMultiSelectable := False;
+end;
+
+function TC4DWizardIDEPopupMenuNotifier.AddSubItemInMenu(const ACaption: string;
+ const AOnExecute: TC4DWizardMenuContextList = nil; const AChecked: Boolean = False): IOTAProjectManagerMenu;
+begin
+ Result := TDelphiAIDevPopupMenuProjectsItem.New(AOnExecute);
+ Result.Caption := ACaption;
+ Result.Verb := ACaption;
+ Result.Parent := TConsts.ITEM_POPUP_MENU_PROJ_CAPTION;
+ Result.Position := TUtils.IncInt(FPosition);
+ Result.Checked := AChecked;
+ Result.IsMultiSelectable := False;
+end;
+
+initialization
+
+finalization
+ if Index >= 0 then
+ TUtilsOTA.GetIOTAProjectManager.RemoveMenuItemCreatorNotifier(Index);
+
+end.
diff --git a/Src/Projects/DelphiAIDev.Projects.AddEdit.View.dfm b/Src/Projects/DelphiAIDev.Projects.AddEdit.View.dfm
new file mode 100644
index 0000000..bc09ff6
--- /dev/null
+++ b/Src/Projects/DelphiAIDev.Projects.AddEdit.View.dfm
@@ -0,0 +1,158 @@
+object DelphiAIDevProjectsAddEditView: TDelphiAIDevProjectsAddEditView
+ Left = 0
+ Top = 0
+ BorderIcons = [biSystemMenu]
+ Caption = 'IA Developer - Project Config'
+ ClientHeight = 230
+ ClientWidth = 629
+ Color = clBtnFace
+ Font.Charset = DEFAULT_CHARSET
+ Font.Color = clWindowText
+ Font.Height = -11
+ Font.Name = 'Tahoma'
+ Font.Style = []
+ KeyPreview = True
+ OldCreateOrder = False
+ Position = poScreenCenter
+ OnClose = FormClose
+ OnCreate = FormCreate
+ OnDestroy = FormDestroy
+ OnKeyDown = FormKeyDown
+ OnShow = FormShow
+ PixelsPerInch = 96
+ TextHeight = 13
+ object Bevel2: TBevel
+ AlignWithMargins = True
+ Left = 0
+ Top = 191
+ Width = 629
+ Height = 1
+ Margins.Left = 0
+ Margins.Top = 0
+ Margins.Right = 0
+ Align = alBottom
+ Shape = bsTopLine
+ ExplicitLeft = -87
+ ExplicitTop = 264
+ ExplicitWidth = 665
+ end
+ object pnBody: TPanel
+ Left = 0
+ Top = 0
+ Width = 629
+ Height = 191
+ Align = alClient
+ BevelOuter = bvNone
+ ParentBackground = False
+ TabOrder = 0
+ object Bevel1: TBevel
+ AlignWithMargins = True
+ Left = 0
+ Top = 187
+ Width = 629
+ Height = 1
+ Margins.Left = 0
+ Margins.Top = 0
+ Margins.Right = 0
+ Align = alBottom
+ Shape = bsTopLine
+ ExplicitTop = 444
+ ExplicitWidth = 676
+ end
+ object Label1: TLabel
+ Left = 24
+ Top = 135
+ Width = 79
+ Height = 13
+ Caption = 'Last generation:'
+ end
+ object lbLastGeneration: TLabel
+ Left = 109
+ Top = 135
+ Width = 81
+ Height = 13
+ Caption = 'lbLastGeneration'
+ end
+ object Label2: TLabel
+ Left = 24
+ Top = 43
+ Width = 55
+ Height = 13
+ Caption = 'Nickname'
+ Font.Charset = DEFAULT_CHARSET
+ Font.Color = clWindowText
+ Font.Height = -11
+ Font.Name = 'Tahoma'
+ Font.Style = [fsBold]
+ ParentFont = False
+ end
+ object Label3: TLabel
+ Left = 24
+ Top = 95
+ Width = 84
+ Height = 13
+ Caption = 'Database Default'
+ end
+ object cBoxDatabaseDefault: TComboBox
+ Left = 24
+ Top = 111
+ Width = 577
+ Height = 21
+ Style = csDropDownList
+ TabOrder = 1
+ OnClick = cBoxDatabaseDefaultClick
+ end
+ object edtNickname: TEdit
+ Left = 24
+ Top = 59
+ Width = 577
+ Height = 21
+ TabOrder = 0
+ end
+ end
+ object pnButtons: TPanel
+ Left = 0
+ Top = 195
+ Width = 629
+ Height = 35
+ Align = alBottom
+ BevelEdges = [beLeft, beRight, beBottom]
+ BevelOuter = bvNone
+ Padding.Left = 2
+ Padding.Top = 2
+ Padding.Right = 2
+ Padding.Bottom = 2
+ ParentBackground = False
+ TabOrder = 1
+ object btnConfirm: TButton
+ AlignWithMargins = True
+ Left = 401
+ Top = 2
+ Width = 110
+ Height = 31
+ Cursor = crHandPoint
+ Margins.Left = 0
+ Margins.Top = 0
+ Margins.Bottom = 0
+ Align = alRight
+ Caption = 'Confirm'
+ TabOrder = 0
+ OnClick = btnConfirmClick
+ end
+ object btnClose: TButton
+ AlignWithMargins = True
+ Left = 514
+ Top = 2
+ Width = 110
+ Height = 31
+ Cursor = crHandPoint
+ Margins.Left = 0
+ Margins.Top = 0
+ Margins.Bottom = 0
+ Align = alRight
+ Caption = 'Close'
+ TabOrder = 1
+ OnClick = btnCloseClick
+ end
+ end
+end
diff --git a/Src/Projects/DelphiAIDev.Projects.AddEdit.View.pas b/Src/Projects/DelphiAIDev.Projects.AddEdit.View.pas
new file mode 100644
index 0000000..a619608
--- /dev/null
+++ b/Src/Projects/DelphiAIDev.Projects.AddEdit.View.pas
@@ -0,0 +1,173 @@
+unit DelphiAIDev.Projects.AddEdit.View;
+
+interface
+
+uses
+ Winapi.Windows,
+ Winapi.Messages,
+ System.SysUtils,
+ System.Variants,
+ System.Classes,
+ Vcl.Graphics,
+ Vcl.Controls,
+ Vcl.Forms,
+ Vcl.Dialogs,
+ Vcl.StdCtrls,
+ Vcl.ExtCtrls,
+ ToolsAPI,
+ DelphiAIDev.DB.Registers.Model,
+ DelphiAIDev.DB.Registers.Fields,
+ DelphiAIDev.Projects.Model,
+ DelphiAIDev.Projects.Fields;
+
+type
+ TDelphiAIDevProjectsAddEditView = class(TForm)
+ Bevel2: TBevel;
+ pnBody: TPanel;
+ Bevel1: TBevel;
+ Label1: TLabel;
+ lbLastGeneration: TLabel;
+ pnButtons: TPanel;
+ btnConfirm: TButton;
+ btnClose: TButton;
+ cBoxDatabaseDefault: TComboBox;
+ Label2: TLabel;
+ edtNickname: TEdit;
+ Label3: TLabel;
+ procedure FormCreate(Sender: TObject);
+ procedure FormShow(Sender: TObject);
+ procedure FormKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState);
+ procedure btnCloseClick(Sender: TObject);
+ procedure btnConfirmClick(Sender: TObject);
+ procedure cBoxDatabaseDefaultClick(Sender: TObject);
+ procedure FormDestroy(Sender: TObject);
+ procedure FormClose(Sender: TObject; var Action: TCloseAction);
+ private
+ FOTAProject: IOTAProject;
+ FProjectsFields: TDelphiAIDevProjectsFields;
+ procedure FillScreenFields;
+ procedure FillcBoxDatabases;
+ procedure FillDateLastReferences;
+ function GetFieldDBSelected: TDelphiAIDevDBRegistersFields;
+ procedure ValidateFillingFields;
+ public
+ property OTAProject: IOTAProject write FOTAProject;
+ end;
+
+implementation
+
+uses
+ DelphiAIDev.Consts,
+ DelphiAIDev.Utils,
+ DelphiAIDev.Utils.OTA,
+ DelphiAIDev.DB.Utils;
+
+{$R *.dfm}
+
+procedure TDelphiAIDevProjectsAddEditView.FormCreate(Sender: TObject);
+begin
+ Self.ModalResult := mrCancel;
+ TUtilsOTA.IDEThemingAll(TDelphiAIDevProjectsAddEditView, Self);
+end;
+
+procedure TDelphiAIDevProjectsAddEditView.FormDestroy(Sender: TObject);
+begin
+ //
+end;
+
+procedure TDelphiAIDevProjectsAddEditView.FormShow(Sender: TObject);
+begin
+ FProjectsFields := TDelphiAIDevProjectsModel.New.ReadFilePath(FOTAProject.FileName);
+ Self.FillScreenFields;
+end;
+
+procedure TDelphiAIDevProjectsAddEditView.FormClose(Sender: TObject; var Action: TCloseAction);
+begin
+ if Assigned(FProjectsFields)then
+ FProjectsFields.Free;
+end;
+
+procedure TDelphiAIDevProjectsAddEditView.FillScreenFields;
+begin
+ Screen.Cursor := crHourGlass;
+ try
+ edtNickname.Text := FProjectsFields.Nickname;
+ Self.FillcBoxDatabases;
+ finally
+ Screen.Cursor := crDefault;
+ end;
+end;
+
+procedure TDelphiAIDevProjectsAddEditView.FillcBoxDatabases;
+begin
+ TDelphiAIDevDBUtils.FillComboBoxDataBases(cBoxDatabaseDefault, FProjectsFields.GuidDatabaseDefault);
+ Self.FillDateLastReferences;
+end;
+
+procedure TDelphiAIDevProjectsAddEditView.FormKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState);
+begin
+ case Key of
+ VK_F4:
+ if ssAlt in Shift then
+ Key := 0;
+ VK_ESCAPE:
+ if Shift = [] then
+ btnClose.Click;
+ end;
+end;
+
+procedure TDelphiAIDevProjectsAddEditView.cBoxDatabaseDefaultClick(Sender: TObject);
+begin
+ Self.FillDateLastReferences;
+end;
+
+procedure TDelphiAIDevProjectsAddEditView.FillDateLastReferences;
+begin
+ lbLastGeneration.Caption := '';
+
+ if cBoxDatabaseDefault.Items.Count < 0 then
+ Exit;
+
+ lbLastGeneration.Caption := TUtils.DateTimeToStrEmpty(Self.GetFieldDBSelected.LastReferences);
+end;
+
+function TDelphiAIDevProjectsAddEditView.GetFieldDBSelected: TDelphiAIDevDBRegistersFields;
+begin
+ Result := TDelphiAIDevDBRegistersFields(cBoxDatabaseDefault.Items.Objects[cBoxDatabaseDefault.ItemIndex]);
+end;
+
+procedure TDelphiAIDevProjectsAddEditView.btnCloseClick(Sender: TObject);
+begin
+ Self.Close;
+ Self.ModalResult := mrCancel;
+end;
+
+procedure TDelphiAIDevProjectsAddEditView.btnConfirmClick(Sender: TObject);
+begin
+ Self.ValidateFillingFields;
+
+ Screen.Cursor := crHourGlass;
+ try
+ FProjectsFields.FilePath := FOTAProject.FileName;
+ FProjectsFields.Nickname := edtNickname.Text;
+ FProjectsFields.GuidDatabaseDefault := Self.GetFieldDBSelected.Guid;
+
+ TDelphiAIDevProjectsModel.New.SaveOrEditData(FProjectsFields);
+ finally
+ Screen.Cursor := crDefault;
+ end;
+
+ Self.Close;
+ Self.ModalResult := mrOk;
+end;
+
+procedure TDelphiAIDevProjectsAddEditView.ValidateFillingFields;
+begin
+ if Trim(edtNickname.Text).IsEmpty then
+ TUtils.ShowMsgAndAbort('No informed Nickname', edtNickname);
+
+// if cBoxDatabaseDefault.ItemIndex < 0 then
+// TUtils.ShowMsgAndAbort('No informed Database', cBoxDatabaseDefault);
+end;
+
+end.
diff --git a/Src/Projects/DelphiAIDev.Projects.Fields.pas b/Src/Projects/DelphiAIDev.Projects.Fields.pas
new file mode 100644
index 0000000..2b6ac26
--- /dev/null
+++ b/Src/Projects/DelphiAIDev.Projects.Fields.pas
@@ -0,0 +1,48 @@
+unit DelphiAIDev.Projects.Fields;
+
+interface
+
+uses
+ DelphiAIDev.Types;
+
+type
+ TDelphiAIDevProjectsFields = class
+ private
+ FGuid: string;
+ FFilePath: string;
+ FNickname: string;
+ FGuidDatabaseDefault: string;
+ public
+ constructor Create;
+ procedure Clear;
+ procedure GetDataFromOtherObject(const AOtherObj: TDelphiAIDevProjectsFields);
+ property Guid: string read FGuid write FGuid;
+ property FilePath: string read FFilePath write FFilePath;
+ property Nickname: string read FNickname write FNickname;
+ property GuidDatabaseDefault: string read FGuidDatabaseDefault write FGuidDatabaseDefault;
+ end;
+
+implementation
+
+constructor TDelphiAIDevProjectsFields.Create;
+begin
+ Self.Clear;
+end;
+
+procedure TDelphiAIDevProjectsFields.Clear;
+begin
+ FGuid := '';
+ FFilePath := '';
+ FNickname := '';
+ FGuidDatabaseDefault := '';
+end;
+
+procedure TDelphiAIDevProjectsFields.GetDataFromOtherObject(const AOtherObj: TDelphiAIDevProjectsFields);
+begin
+ FGuid := AOtherObj.Guid;
+ FNickname := AOtherObj.Nickname;
+ FFilePath := AOtherObj.FilePath;
+ FGuidDatabaseDefault := AOtherObj.GuidDatabaseDefault;
+end;
+
+end.
diff --git a/Src/Projects/DelphiAIDev.Projects.Interfaces.pas b/Src/Projects/DelphiAIDev.Projects.Interfaces.pas
new file mode 100644
index 0000000..36caa95
--- /dev/null
+++ b/Src/Projects/DelphiAIDev.Projects.Interfaces.pas
@@ -0,0 +1,23 @@
+unit DelphiAIDev.Projects.Interfaces;
+
+interface
+
+uses
+ System.SysUtils,
+ DelphiAIDev.Types,
+ DelphiAIDev.Projects.Fields;
+
+type
+ IDelphiAIDevProjectsModel = interface
+ ['{D919A407-4301-447F-A267-6965153DC01A}']
+ function ReadGuid(const AGuid: string): TDelphiAIDevProjectsFields;
+ function ReadFilePathCurrentProject: TDelphiAIDevProjectsFields;
+ function ReadFilePath(const AFilePath: string): TDelphiAIDevProjectsFields;
+ procedure ReadData(AProc: TProc; const AAutoFreeField: TAutoFreeField = TAutoFreeField.Yes);
+ procedure SaveOrEditData(AFields: TDelphiAIDevProjectsFields);
+ procedure RemoveData(const AGuid: string);
+ end;
+
+implementation
+
+end.
diff --git a/Src/Projects/DelphiAIDev.Projects.Model.pas b/Src/Projects/DelphiAIDev.Projects.Model.pas
new file mode 100644
index 0000000..1a9469e
--- /dev/null
+++ b/Src/Projects/DelphiAIDev.Projects.Model.pas
@@ -0,0 +1,358 @@
+unit DelphiAIDev.Projects.Model;
+
+interface
+
+uses
+ System.SysUtils,
+ System.Classes,
+ System.JSON,
+ Rest.JSON,
+ DelphiAIDev.Utils,
+ DelphiAIDev.Utils.OTA,
+ DelphiAIDev.Types,
+ DelphiAIDev.Projects.Interfaces,
+ DelphiAIDev.Projects.Fields;
+
+type
+ TDelphiAIDevProjectsModel = class(TInterfacedObject, IDelphiAIDevProjectsModel)
+ private
+ procedure SaveData(AFields: TDelphiAIDevProjectsFields);
+ procedure EditData(AFields: TDelphiAIDevProjectsFields);
+ procedure FillField(const AJSONObjItem: TJSONObject; var AField: TDelphiAIDevProjectsFields);
+ protected
+ function ReadGuid(const AGuid: string): TDelphiAIDevProjectsFields;
+ function ReadFilePathCurrentProject: TDelphiAIDevProjectsFields;
+ function ReadFilePath(const AFilePath: string): TDelphiAIDevProjectsFields;
+ procedure ReadData(AProc: TProc; const AAutoFreeField: TAutoFreeField = TAutoFreeField.Yes);
+ procedure SaveOrEditData(AFields: TDelphiAIDevProjectsFields);
+ procedure RemoveData(const AGuid: string);
+ public
+ class function New: IDelphiAIDevProjectsModel;
+ constructor Create;
+ end;
+
+implementation
+
+const
+ GUID = 'guid';
+ FILE_PATH = 'file_path';
+ NICKNAME = 'Nickname';
+ GUID_DATABASE_DEFAULT = 'guid_database_default';
+
+class function TDelphiAIDevProjectsModel.New: IDelphiAIDevProjectsModel;
+begin
+ Result := Self.Create;
+end;
+
+constructor TDelphiAIDevProjectsModel.Create;
+begin
+ //
+end;
+
+function TDelphiAIDevProjectsModel.ReadGuid(const AGuid: string): TDelphiAIDevProjectsFields;
+var
+ LStringList: TStringList;
+ LJSONObjItem: TJSONObject;
+ LJSONArray: TJsonArray;
+ i: Integer;
+begin
+ Result := TDelphiAIDevProjectsFields.Create;
+
+ if not FileExists(TUtils.GetPathFileJSONProjects) then
+ Exit;
+
+ LStringList := TStringList.Create;
+ try
+ LStringList.LoadFromFile(TUtils.GetPathFileJSONProjects);
+ LJSONArray := TJSONObject.ParseJSONValue(TEncoding.UTF8.GetBytes(LStringList.Text), 0) as TJSONArray;
+ finally
+ LStringList.Free;
+ end;
+
+ try
+ for i := 0 to Pred(LJSONArray.Count) do
+ begin
+ if not(LJSONArray.Items[i] is TJSONObject) then
+ Continue;
+
+ LJSONObjItem := LJSONArray.Items[i] as TJSONObject;
+
+ if LJSONObjItem.GetValue(GUID) = nil then
+ Continue;
+
+ if LJSONObjItem.GetValue(GUID) <> AGuid then
+ Continue;
+
+ Self.FillField(LJSONObjItem, Result);
+ Break;
+ end;
+ finally
+ LJSONArray.Free;
+ end;
+end;
+
+function TDelphiAIDevProjectsModel.ReadFilePathCurrentProject: TDelphiAIDevProjectsFields;
+begin
+ Result := Self.ReadFilePath(TUtilsOTA.GetCurrentProjectFileName);
+end;
+
+function TDelphiAIDevProjectsModel.ReadFilePath(const AFilePath: string): TDelphiAIDevProjectsFields;
+var
+ LStringList: TStringList;
+ LJSONObjItem: TJSONObject;
+ LJSONArray: TJsonArray;
+ i: Integer;
+begin
+ Result := TDelphiAIDevProjectsFields.Create;
+
+ if AFilePath.Trim.IsEmpty then
+ Exit;
+
+ if not FileExists(TUtils.GetPathFileJSONProjects) then
+ Exit;
+
+ LStringList := TStringList.Create;
+ try
+ LStringList.LoadFromFile(TUtils.GetPathFileJSONProjects);
+ LJSONArray := TJSONObject.ParseJSONValue(TEncoding.UTF8.GetBytes(LStringList.Text), 0) as TJSONArray;
+ finally
+ LStringList.Free;
+ end;
+
+ try
+ for i := 0 to Pred(LJSONArray.Count) do
+ begin
+ if not(LJSONArray.Items[i] is TJSONObject) then
+ Continue;
+
+ LJSONObjItem := LJSONArray.Items[i] as TJSONObject;
+
+ if LJSONObjItem.GetValue(FILE_PATH) = nil then
+ Continue;
+
+ if LJSONObjItem.GetValue(FILE_PATH) <> AFilePath then
+ Continue;
+
+ Self.FillField(LJSONObjItem, Result);
+ Break;
+ end;
+ finally
+ LJSONArray.Free;
+ end;
+end;
+
+procedure TDelphiAIDevProjectsModel.FillField(const AJSONObjItem: TJSONObject;
+ var AField: TDelphiAIDevProjectsFields);
+begin
+ AField.Clear;
+ AField.Guid := AJSONObjItem.GetValue(GUID);
+
+ if AJSONObjItem.GetValue(FILE_PATH) <> nil then
+ AField.FilePath := AJSONObjItem.GetValue(FILE_PATH);
+
+ if AJSONObjItem.GetValue(NICKNAME) <> nil then
+ AField.Nickname := AJSONObjItem.GetValue(NICKNAME);
+
+ if AJSONObjItem.GetValue(GUID_DATABASE_DEFAULT) <> nil then
+ AField.GuidDatabaseDefault := AJSONObjItem.GetValue(GUID_DATABASE_DEFAULT);
+end;
+
+procedure TDelphiAIDevProjectsModel.ReadData(AProc: TProc;
+ const AAutoFreeField: TAutoFreeField = TAutoFreeField.Yes);
+var
+ LStringList: TStringList;
+ LJSONObjItem: TJSONObject;
+ LJSONArray: TJsonArray;
+ i: Integer;
+ LFields: TDelphiAIDevProjectsFields;
+begin
+ LFields := TDelphiAIDevProjectsFields.Create;
+ try
+ if not FileExists(TUtils.GetPathFileJSONProjects) then
+ begin
+ AProc(LFields);
+ Exit;
+ end;
+
+ LStringList := TStringList.Create;
+ try
+ LStringList.LoadFromFile(TUtils.GetPathFileJSONProjects);
+ LJSONArray := TJSONObject.ParseJSONValue(TEncoding.UTF8.GetBytes(LStringList.Text), 0) as TJSONArray;
+ finally
+ LStringList.Free;
+ end;
+
+ try
+ for i := 0 to Pred(LJSONArray.Count) do
+ begin
+ if not(LJSONArray.Items[i] is TJSONObject) then
+ Continue;
+
+ LJSONObjItem := LJSONArray.Items[i] as TJSONObject;
+
+ if LJSONObjItem.GetValue(GUID) = nil then
+ Continue;
+
+ Self.FillField(LJSONObjItem, LFields);
+
+ AProc(LFields);
+ end;
+ finally
+ LJSONArray.Free;
+ end;
+ finally
+ if AAutoFreeField = TAutoFreeField.Yes then
+ LFields.Free;
+ end;
+end;
+
+procedure TDelphiAIDevProjectsModel.SaveOrEditData(AFields: TDelphiAIDevProjectsFields);
+begin
+ if AFields.Guid.Trim.IsEmpty then
+ Self.SaveData(AFields)
+ else
+ Self.EditData(AFields);
+end;
+
+procedure TDelphiAIDevProjectsModel.SaveData(AFields: TDelphiAIDevProjectsFields);
+var
+ LStringList: TStringList;
+ LJSONArray: TJSONArray;
+ LJSONObject: TJSONObject;
+begin
+ LStringList := TStringList.Create;
+ try
+ if FileExists(TUtils.GetPathFileJSONProjects) then
+ LStringList.LoadFromFile(TUtils.GetPathFileJSONProjects);
+
+ LJSONArray := TJSONArray.Create;
+ try
+ if string(LStringList.Text).Trim.StartsWith('[') then
+ LJSONArray := TJSONObject.ParseJSONValue(TEncoding.UTF8.GetBytes(LStringList.Text), 0) as TJSONArray;
+
+ LJSONObject := TJSONObject.Create;
+ LJSONObject.AddPair(GUID, TUtils.GetGuidStr);
+ LJSONObject.AddPair(FILE_PATH, AFields.FilePath);
+ LJSONObject.AddPair(NICKNAME, AFields.Nickname);
+ LJSONObject.AddPair(GUID_DATABASE_DEFAULT, AFields.GuidDatabaseDefault);
+ LJSONArray.AddElement(LJSONObject);
+
+ {$IF CompilerVersion <= 32.0} //Tokyo
+ LStringList.Text := LJSONArray.ToJSON;
+ {$ELSE}
+ LStringList.Text := LJSONArray.Format(2);
+ {$ENDIF}
+ finally
+ LJSONArray.Free;
+ end;
+
+ LStringList.SaveToFile(TUtils.GetPathFileJSONProjects);
+ finally
+ LStringList.Free;
+ end;
+end;
+
+procedure TDelphiAIDevProjectsModel.EditData(AFields: TDelphiAIDevProjectsFields);
+var
+ LStringList: TStringList;
+ LJSONArray: TJSONArray;
+ LJSONObjItem: TJSONObject;
+ i: Integer;
+begin
+ LStringList := TStringList.Create;
+ try
+ if FileExists(TUtils.GetPathFileJSONProjects) then
+ LStringList.LoadFromFile(TUtils.GetPathFileJSONProjects);
+
+ LJSONArray := TJSONArray.Create;
+ try
+ if string(LStringList.Text).Trim.StartsWith('[') then
+ LJSONArray := TJSONObject.ParseJSONValue(TEncoding.UTF8.GetBytes(LStringList.Text), 0) as TJSONArray;
+
+ for i := 0 to Pred(LJSONArray.Count) do
+ begin
+ if not(LJSONArray.Items[i] is TJSONObject) then
+ Continue;
+
+ LJSONObjItem := LJSONArray.Items[i] as TJSONObject;
+
+ if LJSONObjItem.GetValue(GUID) = AFields.Guid then
+ begin
+ LJSONObjItem.RemovePair(FILE_PATH).Free;
+ LJSONObjItem.AddPair(FILE_PATH, AFields.FilePath);
+
+ LJSONObjItem.RemovePair(NICKNAME).Free;
+ LJSONObjItem.AddPair(NICKNAME, AFields.Nickname);
+
+ LJSONObjItem.RemovePair(GUID_DATABASE_DEFAULT).Free;
+ LJSONObjItem.AddPair(GUID_DATABASE_DEFAULT, AFields.GuidDatabaseDefault);
+
+ Break;
+ end;
+ end;
+
+ {$IF CompilerVersion <= 32.0} //Tokyo
+ LStringList.Text := LJSONArray.ToJSON;
+ {$ELSE}
+ LStringList.Text := LJSONArray.Format(2);
+ {$ENDIF}
+ finally
+ LJSONArray.Free;
+ end;
+
+ LStringList.SaveToFile(TUtils.GetPathFileJSONProjects);
+ finally
+ LStringList.Free;
+ end;
+end;
+
+procedure TDelphiAIDevProjectsModel.RemoveData(const AGuid: string);
+var
+ LStringList: TStringList;
+ LJSONArray: TJSONArray;
+ LJSONObjItem: TJSONObject;
+ i: Integer;
+begin
+ if AGuid.Trim.IsEmpty then
+ Exit;
+
+ if not FileExists(TUtils.GetPathFileJSONProjects) then
+ Exit;
+
+ LStringList := TStringList.Create;
+ try
+ LStringList.LoadFromFile(TUtils.GetPathFileJSONProjects);
+ if not string(LStringList.Text).Trim.StartsWith('[') then
+ Exit;
+
+ LJSONArray := TJSONObject.ParseJSONValue(TEncoding.UTF8.GetBytes(LStringList.Text), 0) as TJSONArray;
+ try
+ for i := 0 to Pred(LJSONArray.Count) do
+ begin
+ if not(LJSONArray.Items[i] is TJSONObject) then
+ Continue;
+
+ LJSONObjItem := LJSONArray.Items[i] as TJSONObject;
+ if LJSONObjItem.GetValue(GUID) = AGuid then
+ begin
+ LJSONArray.Remove(i);
+ Break;
+ end;
+ end;
+
+ {$IF CompilerVersion <= 32.0} //Tokyo
+ LStringList.Text := LJSONArray.ToJSON;
+ {$ELSE}
+ LStringList.Text := LJSONArray.Format(2);
+ {$ENDIF}
+ finally
+ LJSONArray.Free;
+ end;
+
+ LStringList.SaveToFile(TUtils.GetPathFileJSONProjects);
+ finally
+ LStringList.Free;
+ end;
+end;
+
+end.
diff --git a/Src/Settings/DelphiAIDev.Settings.View.dfm b/Src/Settings/DelphiAIDev.Settings.View.dfm
index 3be8253..b023496 100644
--- a/Src/Settings/DelphiAIDev.Settings.View.dfm
+++ b/Src/Settings/DelphiAIDev.Settings.View.dfm
@@ -2,601 +2,33 @@ object DelphiAIDevSettingsView: TDelphiAIDevSettingsView
Left = 0
Top = 0
Caption = 'Delphi AI Developer - Settings'
- ClientHeight = 578
- ClientWidth = 632
+ ClientHeight = 676
+ ClientWidth = 670
Color = clBtnFace
Font.Charset = DEFAULT_CHARSET
Font.Color = clWindowText
Font.Height = -11
Font.Name = 'Tahoma'
Font.Style = []
- OldCreateOrder = False
+ KeyPreview = True
Position = poScreenCenter
OnClose = FormClose
OnCreate = FormCreate
OnKeyDown = FormKeyDown
OnShow = FormShow
- PixelsPerInch = 96
TextHeight = 13
object pnBackAll: TPanel
Left = 0
Top = 0
- Width = 632
- Height = 578
+ Width = 670
+ Height = 676
Align = alClient
BevelOuter = bvNone
TabOrder = 0
- object pnBody: TPanel
- Left = 0
- Top = 0
- Width = 632
- Height = 543
- Align = alClient
- BevelOuter = bvNone
- ParentBackground = False
- TabOrder = 0
- object gBoxGemini: TGroupBox
- Left = 0
- Top = 97
- Width = 632
- Height = 133
- Align = alTop
- Caption = ' Gemini (Google) '
- ParentBackground = False
- TabOrder = 1
- object pnGeminiBack: TPanel
- AlignWithMargins = True
- Left = 5
- Top = 18
- Width = 622
- Height = 110
- Align = alClient
- BevelOuter = bvNone
- ParentBackground = False
- TabOrder = 0
- object Label5: TLabel
- Left = 16
- Top = 5
- Width = 45
- Height = 13
- Caption = 'Base URL'
- end
- object Label6: TLabel
- Left = 16
- Top = 48
- Width = 37
- Height = 13
- Caption = 'API key'
- end
- object Label7: TLabel
- Left = 267
- Top = 5
- Width = 28
- Height = 13
- Caption = 'Model'
- end
- object lbLinkGemini01: TLabel
- Left = 16
- Top = 89
- Width = 86
- Height = 13
- Cursor = crHandPoint
- Hint = 'https://aistudio.google.com/app/apikey'
- Caption = 'Generate API Key'
- Font.Charset = DEFAULT_CHARSET
- Font.Color = clBlue
- Font.Height = -11
- Font.Name = 'Tahoma'
- Font.Style = []
- ParentFont = False
- ParentShowHint = False
- ShowHint = True
- OnClick = lbLinkGpt01Click
- end
- object lbLinkGemini02: TLabel
- Left = 128
- Top = 89
- Width = 72
- Height = 13
- Cursor = crHandPoint
- Hint = 'https://ai.google.dev/gemini-api/docs/api-overview#curl_1'
- Caption = 'Documentation'
- Font.Charset = DEFAULT_CHARSET
- Font.Color = clBlue
- Font.Height = -11
- Font.Name = 'Tahoma'
- Font.Style = []
- ParentFont = False
- ParentShowHint = False
- ShowHint = True
- OnClick = lbLinkGpt01Click
- end
- object btnApiKeyGeminiView: TSpeedButton
- Left = 582
- Top = 63
- Width = 23
- Height = 22
- Cursor = crHandPoint
- Hint = 'Show/Hide API Key'
- Flat = True
- Glyph.Data = {
- 36030000424D3603000000000000360000002800000010000000100000000100
- 18000000000000030000120B0000120B00000000000000000000FF00FF4A667C
- BE9596FF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00
- FFFF00FFFF00FFFF00FF6B9CC31E89E84B7AA3C89693FF00FFFF00FFFF00FFFF
- 00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FF4BB4FE51B5FF
- 2089E94B7AA2C69592FF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00
- FFFF00FFFF00FFFF00FFFF00FF51B7FE51B3FF1D87E64E7AA0CA9792FF00FFFF
- 00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FF
- 51B7FE4EB2FF1F89E64E7BA2B99497FF00FFFF00FFFF00FFFF00FFFF00FFFF00
- FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FF52B8FE4BB1FF2787D95F6A76FF
- 00FFB0857FC09F94C09F96BC988EFF00FFFF00FFFF00FFFF00FFFF00FFFF00FF
- FF00FFFF00FF55BDFFB5D6EDBF9D92BB9B8CE7DAC2FFFFE3FFFFE5FDFADAD8C3
- B3B58D85FF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFCEA795FD
- EEBEFFFFD8FFFFDAFFFFDBFFFFE6FFFFFBEADDDCAE837FFF00FFFF00FFFF00FF
- FF00FFFF00FFFF00FFFF00FFC1A091FBDCA8FEF7D0FFFFDBFFFFE3FFFFF8FFFF
- FDFFFFFDC6A99CFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFC1A091FEE3ACF1
- C491FCF2CAFFFFDDFFFFE4FFFFF7FFFFF7FFFFE9EEE5CBB9948CFF00FFFF00FF
- FF00FFFF00FFFF00FFC2A191FFE6AEEEB581F7DCAEFEFDD8FFFFDFFFFFE3FFFF
- E4FFFFE0F3ECD2BB968EFF00FFFF00FFFF00FFFF00FFFF00FFBC978CFBE7B7F4
- C791F2C994F8E5B9FEFCD8FFFFDDFFFFDCFFFFE0E2D2BAB68E86FF00FFFF00FF
- FF00FFFF00FFFF00FFFF00FFD9C3A9FFFEE5F7DCB8F2C994F5D4A5FAE8BDFDF4
- C9FDFBD6B69089FF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFB58D85E8
- DEDDFFFEF2F9D8A3F4C48CF9D49FFDEAB8D0B49FB89086FF00FFFF00FFFF00FF
- FF00FFFF00FFFF00FFFF00FFFF00FFAD827FC9AA9EEFE0B7EFDFB2E7CEACB890
- 86B89086FF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF
- 00FFFF00FFBA968ABB988CB79188FF00FFFF00FFFF00FFFF00FF}
- ParentShowHint = False
- ShowHint = True
- OnClick = btnApiKeyGeminiViewClick
- end
- object lbLinkGemini03: TLabel
- Left = 232
- Top = 89
- Width = 67
- Height = 13
- Cursor = crHandPoint
- Hint = 'https://ai.google.dev/gemini-api/docs/models/gemini?hl=pt-br'
- Caption = 'Gemini Models'
- Font.Charset = DEFAULT_CHARSET
- Font.Color = clBlue
- Font.Height = -11
- Font.Name = 'Tahoma'
- Font.Style = []
- ParentFont = False
- ParentShowHint = False
- ShowHint = True
- OnClick = lbLinkGpt01Click
- end
- object edtBaseUrlGemini: TEdit
- Left = 16
- Top = 20
- Width = 249
- Height = 21
- TabOrder = 0
- end
- object edtApiKeyGemini: TEdit
- Left = 16
- Top = 64
- Width = 563
- Height = 21
- PasswordChar = '*'
- TabOrder = 2
- end
- object cBoxModelGemini: TComboBox
- Left = 267
- Top = 20
- Width = 333
- Height = 21
- TabOrder = 1
- Items.Strings = (
- 'v1/models/gemini-1.5-flash:generateContent'
- 'v1beta/models/gemini-pro:generateContent'
- 'v1beta/models/gemini-1.5-flash:generateContent')
- end
- end
- end
- object GroupBox2: TGroupBox
- Left = 0
- Top = 0
- Width = 632
- Height = 97
- Align = alTop
- Caption = ' Preferences '
- ParentBackground = False
- TabOrder = 0
- object Label11: TLabel
- Left = 272
- Top = 23
- Width = 48
- Height = 13
- Caption = 'AI default'
- end
- object Label4: TLabel
- Left = 21
- Top = 23
- Width = 133
- Height = 13
- Caption = 'Language used in questions'
- end
- object cBoxAIDefault: TComboBox
- Left = 272
- Top = 38
- Width = 333
- Height = 21
- Style = csDropDownList
- TabOrder = 1
- Items.Strings = (
- '')
- end
- object ColorBoxColorHighlightCodeDelphi: TColorBox
- Left = 218
- Top = 66
- Width = 133
- Height = 22
- TabOrder = 3
- end
- object ckColorHighlightCodeDelphiUse: TCheckBox
- Left = 21
- Top = 68
- Width = 194
- Height = 17
- Caption = 'Color to highlight Delphi/Pascal code'
- TabOrder = 2
- OnClick = ckColorHighlightCodeDelphiUseClick
- end
- object cBoxLanguageQuestions: TComboBox
- Left = 21
- Top = 38
- Width = 249
- Height = 21
- Hint = 'What is the standard language for questions?'
- Style = csDropDownList
- ParentShowHint = False
- ShowHint = True
- TabOrder = 0
- end
- end
- object gBoxOpenAI: TGroupBox
- Left = 0
- Top = 230
- Width = 632
- Height = 133
- Align = alTop
- Caption = ' ChatGPT (OpenAI)'
- ParentBackground = False
- TabOrder = 2
- object pnOpenAIBack: TPanel
- AlignWithMargins = True
- Left = 5
- Top = 18
- Width = 622
- Height = 110
- Align = alClient
- BevelOuter = bvNone
- ParentBackground = False
- TabOrder = 0
- object Label1: TLabel
- Left = 16
- Top = 5
- Width = 45
- Height = 13
- Caption = 'Base URL'
- end
- object Label3: TLabel
- Left = 16
- Top = 48
- Width = 37
- Height = 13
- Caption = 'API key'
- end
- object Label2: TLabel
- Left = 478
- Top = 5
- Width = 28
- Height = 13
- Caption = 'Model'
- end
- object lbLinkGpt01: TLabel
- Left = 16
- Top = 90
- Width = 86
- Height = 13
- Cursor = crHandPoint
- Hint = 'https://platform.openai.com/api-keys'
- Caption = 'Generate API Key'
- Font.Charset = DEFAULT_CHARSET
- Font.Color = clBlue
- Font.Height = -11
- Font.Name = 'Tahoma'
- Font.Style = []
- ParentFont = False
- ParentShowHint = False
- ShowHint = True
- OnClick = lbLinkGpt01Click
- end
- object btnApiKeyOpenAIView: TSpeedButton
- Left = 582
- Top = 63
- Width = 23
- Height = 22
- Cursor = crHandPoint
- Hint = 'Show/Hide API Key'
- Flat = True
- Glyph.Data = {
- 36030000424D3603000000000000360000002800000010000000100000000100
- 18000000000000030000120B0000120B00000000000000000000FF00FF4A667C
- BE9596FF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00
- FFFF00FFFF00FFFF00FF6B9CC31E89E84B7AA3C89693FF00FFFF00FFFF00FFFF
- 00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FF4BB4FE51B5FF
- 2089E94B7AA2C69592FF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00
- FFFF00FFFF00FFFF00FFFF00FF51B7FE51B3FF1D87E64E7AA0CA9792FF00FFFF
- 00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FF
- 51B7FE4EB2FF1F89E64E7BA2B99497FF00FFFF00FFFF00FFFF00FFFF00FFFF00
- FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FF52B8FE4BB1FF2787D95F6A76FF
- 00FFB0857FC09F94C09F96BC988EFF00FFFF00FFFF00FFFF00FFFF00FFFF00FF
- FF00FFFF00FF55BDFFB5D6EDBF9D92BB9B8CE7DAC2FFFFE3FFFFE5FDFADAD8C3
- B3B58D85FF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFCEA795FD
- EEBEFFFFD8FFFFDAFFFFDBFFFFE6FFFFFBEADDDCAE837FFF00FFFF00FFFF00FF
- FF00FFFF00FFFF00FFFF00FFC1A091FBDCA8FEF7D0FFFFDBFFFFE3FFFFF8FFFF
- FDFFFFFDC6A99CFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFC1A091FEE3ACF1
- C491FCF2CAFFFFDDFFFFE4FFFFF7FFFFF7FFFFE9EEE5CBB9948CFF00FFFF00FF
- FF00FFFF00FFFF00FFC2A191FFE6AEEEB581F7DCAEFEFDD8FFFFDFFFFFE3FFFF
- E4FFFFE0F3ECD2BB968EFF00FFFF00FFFF00FFFF00FFFF00FFBC978CFBE7B7F4
- C791F2C994F8E5B9FEFCD8FFFFDDFFFFDCFFFFE0E2D2BAB68E86FF00FFFF00FF
- FF00FFFF00FFFF00FFFF00FFD9C3A9FFFEE5F7DCB8F2C994F5D4A5FAE8BDFDF4
- C9FDFBD6B69089FF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFB58D85E8
- DEDDFFFEF2F9D8A3F4C48CF9D49FFDEAB8D0B49FB89086FF00FFFF00FFFF00FF
- FF00FFFF00FFFF00FFFF00FFFF00FFAD827FC9AA9EEFE0B7EFDFB2E7CEACB890
- 86B89086FF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF
- 00FFFF00FFBA968ABB988CB79188FF00FFFF00FFFF00FFFF00FF}
- ParentShowHint = False
- ShowHint = True
- OnClick = btnApiKeyOpenAIViewClick
- end
- object lbLinkGpt02: TLabel
- Left = 128
- Top = 90
- Width = 72
- Height = 13
- Cursor = crHandPoint
- Hint = 'https://platform.openai.com/docs/api-reference/making-requests'
- Caption = 'Documentation'
- Font.Charset = DEFAULT_CHARSET
- Font.Color = clBlue
- Font.Height = -11
- Font.Name = 'Tahoma'
- Font.Style = []
- ParentFont = False
- ParentShowHint = False
- ShowHint = True
- OnClick = lbLinkGpt01Click
- end
- object edtBaseUrlOpenAI: TEdit
- Left = 16
- Top = 21
- Width = 460
- Height = 21
- TabOrder = 0
- end
- object edtApiKeyOpenAI: TEdit
- Left = 16
- Top = 64
- Width = 563
- Height = 21
- PasswordChar = '*'
- TabOrder = 2
- end
- object cBoxModelOpenAI: TComboBox
- Left = 478
- Top = 21
- Width = 122
- Height = 21
- Style = csDropDownList
- TabOrder = 1
- Items.Strings = (
- 'gpt-3.5-turbo'
- 'gpt-3.5-turbo-16k'
- 'gpt-4'
- 'gpt-4-32k')
- end
- end
- end
- object gboxData: TGroupBox
- Left = 0
- Top = 498
- Width = 632
- Height = 45
- Align = alBottom
- Caption = ' Data '
- Padding.Left = 2
- Padding.Top = 5
- Padding.Bottom = 3
- TabOrder = 3
- object btnOpenDataFolder: TButton
- Left = 4
- Top = 20
- Width = 122
- Height = 20
- Cursor = crHandPoint
- Align = alLeft
- Caption = 'Open Data Folder'
- TabOrder = 0
- OnClick = btnOpenDataFolderClick
- end
- end
- object gBoxGroq: TGroupBox
- Left = 0
- Top = 363
- Width = 632
- Height = 135
- Align = alClient
- Caption = ' Groq '
- ParentBackground = False
- TabOrder = 4
- object pnGroqBack: TPanel
- AlignWithMargins = True
- Left = 5
- Top = 18
- Width = 622
- Height = 112
- Align = alClient
- BevelOuter = bvNone
- ParentBackground = False
- TabOrder = 0
- object Label8: TLabel
- Left = 16
- Top = 5
- Width = 45
- Height = 13
- Caption = 'Base URL'
- end
- object Label9: TLabel
- Left = 16
- Top = 48
- Width = 37
- Height = 13
- Caption = 'API key'
- end
- object Label10: TLabel
- Left = 478
- Top = 5
- Width = 28
- Height = 13
- Caption = 'Model'
- end
- object lbLinkGroq01: TLabel
- Left = 16
- Top = 90
- Width = 86
- Height = 13
- Cursor = crHandPoint
- Hint = 'https://console.groq.com/keys'
- Caption = 'Generate API Key'
- Font.Charset = DEFAULT_CHARSET
- Font.Color = clBlue
- Font.Height = -11
- Font.Name = 'Tahoma'
- Font.Style = []
- ParentFont = False
- ParentShowHint = False
- ShowHint = True
- OnClick = lbLinkGpt01Click
- end
- object btnApiKeyGroqView: TSpeedButton
- Left = 582
- Top = 63
- Width = 23
- Height = 22
- Cursor = crHandPoint
- Hint = 'Show/Hide API Key'
- Flat = True
- Glyph.Data = {
- 36030000424D3603000000000000360000002800000010000000100000000100
- 18000000000000030000120B0000120B00000000000000000000FF00FF4A667C
- BE9596FF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00
- FFFF00FFFF00FFFF00FF6B9CC31E89E84B7AA3C89693FF00FFFF00FFFF00FFFF
- 00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FF4BB4FE51B5FF
- 2089E94B7AA2C69592FF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00
- FFFF00FFFF00FFFF00FFFF00FF51B7FE51B3FF1D87E64E7AA0CA9792FF00FFFF
- 00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FF
- 51B7FE4EB2FF1F89E64E7BA2B99497FF00FFFF00FFFF00FFFF00FFFF00FFFF00
- FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FF52B8FE4BB1FF2787D95F6A76FF
- 00FFB0857FC09F94C09F96BC988EFF00FFFF00FFFF00FFFF00FFFF00FFFF00FF
- FF00FFFF00FF55BDFFB5D6EDBF9D92BB9B8CE7DAC2FFFFE3FFFFE5FDFADAD8C3
- B3B58D85FF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFCEA795FD
- EEBEFFFFD8FFFFDAFFFFDBFFFFE6FFFFFBEADDDCAE837FFF00FFFF00FFFF00FF
- FF00FFFF00FFFF00FFFF00FFC1A091FBDCA8FEF7D0FFFFDBFFFFE3FFFFF8FFFF
- FDFFFFFDC6A99CFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFC1A091FEE3ACF1
- C491FCF2CAFFFFDDFFFFE4FFFFF7FFFFF7FFFFE9EEE5CBB9948CFF00FFFF00FF
- FF00FFFF00FFFF00FFC2A191FFE6AEEEB581F7DCAEFEFDD8FFFFDFFFFFE3FFFF
- E4FFFFE0F3ECD2BB968EFF00FFFF00FFFF00FFFF00FFFF00FFBC978CFBE7B7F4
- C791F2C994F8E5B9FEFCD8FFFFDDFFFFDCFFFFE0E2D2BAB68E86FF00FFFF00FF
- FF00FFFF00FFFF00FFFF00FFD9C3A9FFFEE5F7DCB8F2C994F5D4A5FAE8BDFDF4
- C9FDFBD6B69089FF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFB58D85E8
- DEDDFFFEF2F9D8A3F4C48CF9D49FFDEAB8D0B49FB89086FF00FFFF00FFFF00FF
- FF00FFFF00FFFF00FFFF00FFFF00FFAD827FC9AA9EEFE0B7EFDFB2E7CEACB890
- 86B89086FF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF
- 00FFFF00FFBA968ABB988CB79188FF00FFFF00FFFF00FFFF00FF}
- ParentShowHint = False
- ShowHint = True
- OnClick = btnApiKeyGroqViewClick
- end
- object lbLinkGroq02: TLabel
- Left = 128
- Top = 90
- Width = 72
- Height = 13
- Cursor = crHandPoint
- Hint = 'https://console.groq.com/docs/quickstart'
- Caption = 'Documentation'
- Font.Charset = DEFAULT_CHARSET
- Font.Color = clBlue
- Font.Height = -11
- Font.Name = 'Tahoma'
- Font.Style = []
- ParentFont = False
- ParentShowHint = False
- ShowHint = True
- OnClick = lbLinkGpt01Click
- end
- object lbLinkGroq03: TLabel
- Left = 232
- Top = 89
- Width = 59
- Height = 13
- Cursor = crHandPoint
- Hint = 'https://console.groq.com/docs/models'
- Caption = 'Groq Models'
- Font.Charset = DEFAULT_CHARSET
- Font.Color = clBlue
- Font.Height = -11
- Font.Name = 'Tahoma'
- Font.Style = []
- ParentFont = False
- ParentShowHint = False
- ShowHint = True
- OnClick = lbLinkGpt01Click
- end
- object edtBaseUrlGroq: TEdit
- Left = 16
- Top = 21
- Width = 460
- Height = 21
- TabOrder = 0
- end
- object edtApiKeyGroq: TEdit
- Left = 16
- Top = 64
- Width = 563
- Height = 21
- PasswordChar = '*'
- TabOrder = 2
- end
- object cBoxModelGroq: TComboBox
- Left = 478
- Top = 21
- Width = 122
- Height = 21
- Style = csDropDownList
- TabOrder = 1
- Items.Strings = (
- 'llama3-8b-8192'
- 'llama3-70b-8192'
- 'llama3-groq-8b-8192-tool-use-preview'
- 'llama3-groq-70b-8192-tool-use-preview'
- 'mixtral-8x7b-32768'
- 'gemma-7b-it'
- 'gemma2-9b-it'
- 'whisper-large-v3')
- end
- end
- end
- end
object pnBottom: TPanel
Left = 0
- Top = 543
- Width = 632
+ Top = 641
+ Width = 670
Height = 35
Margins.Left = 0
Margins.Top = 0
@@ -609,16 +41,17 @@ object DelphiAIDevSettingsView: TDelphiAIDevSettingsView
Padding.Right = 2
Padding.Bottom = 2
ParentBackground = False
- TabOrder = 1
+ TabOrder = 0
object lbRestoreDefaults: TLabel
AlignWithMargins = True
Left = 16
- Top = 12
+ Top = 7
Width = 80
- Height = 18
+ Height = 21
Cursor = crHandPoint
Margins.Left = 16
- Margins.Top = 10
+ Margins.Top = 5
+ Margins.Bottom = 5
Align = alLeft
Caption = 'Restore defaults'
Font.Charset = DEFAULT_CHARSET
@@ -635,7 +68,7 @@ object DelphiAIDevSettingsView: TDelphiAIDevSettingsView
end
object btnConfirm: TButton
AlignWithMargins = True
- Left = 404
+ Left = 442
Top = 2
Width = 110
Height = 31
@@ -650,7 +83,7 @@ object DelphiAIDevSettingsView: TDelphiAIDevSettingsView
end
object btnClose: TButton
AlignWithMargins = True
- Left = 517
+ Left = 555
Top = 2
Width = 110
Height = 31
@@ -664,5 +97,1232 @@ object DelphiAIDevSettingsView: TDelphiAIDevSettingsView
OnClick = btnCloseClick
end
end
+ object pnMyControl: TPanel
+ Left = 0
+ Top = 0
+ Width = 670
+ Height = 641
+ Align = alClient
+ BevelOuter = bvNone
+ TabOrder = 1
+ object pnMyControlButtons: TPanel
+ Left = 0
+ Top = 0
+ Width = 670
+ Height = 30
+ Align = alTop
+ BevelEdges = [beBottom]
+ BevelOuter = bvNone
+ TabOrder = 0
+ object Bevel5: TBevel
+ AlignWithMargins = True
+ Left = 0
+ Top = 26
+ Width = 670
+ Height = 1
+ Margins.Left = 0
+ Margins.Top = 0
+ Margins.Right = 0
+ Align = alBottom
+ Shape = bsTopLine
+ ExplicitTop = 218
+ ExplicitWidth = 632
+ end
+ object btnPreferences: TButton
+ AlignWithMargins = True
+ Left = 3
+ Top = 2
+ Width = 95
+ Height = 23
+ Cursor = crHandPoint
+ Margins.Top = 2
+ Margins.Right = 0
+ Margins.Bottom = 1
+ Align = alLeft
+ Caption = 'Preferences'
+ TabOrder = 0
+ OnClick = btnPreferencesClick
+ end
+ object btnIAsOnline: TButton
+ AlignWithMargins = True
+ Left = 101
+ Top = 2
+ Width = 95
+ Height = 23
+ Cursor = crHandPoint
+ Margins.Top = 2
+ Margins.Right = 0
+ Margins.Bottom = 1
+ Align = alLeft
+ Caption = 'AI on-line'
+ TabOrder = 1
+ OnClick = btnIAsOnlineClick
+ end
+ object btnIAsOffline: TButton
+ AlignWithMargins = True
+ Left = 199
+ Top = 2
+ Width = 95
+ Height = 23
+ Cursor = crHandPoint
+ Margins.Top = 2
+ Margins.Right = 0
+ Margins.Bottom = 1
+ Align = alLeft
+ Caption = 'AI off-Line'
+ TabOrder = 2
+ OnClick = btnIAsOfflineClick
+ end
+ object btnCodeCompletion: TButton
+ AlignWithMargins = True
+ Left = 297
+ Top = 2
+ Width = 95
+ Height = 23
+ Cursor = crHandPoint
+ Margins.Top = 2
+ Margins.Right = 0
+ Margins.Bottom = 1
+ Align = alLeft
+ Caption = 'Code Completion'
+ TabOrder = 3
+ OnClick = btnCodeCompletionClick
+ end
+ end
+ object pnBody: TPanel
+ Left = 0
+ Top = 30
+ Width = 670
+ Height = 611
+ Align = alClient
+ BevelOuter = bvNone
+ TabOrder = 1
+ end
+ end
+ end
+ object PageControl1: TPageControl
+ Left = 0
+ Top = 33
+ Width = 667
+ Height = 521
+ ActivePage = TabSheet2
+ TabOrder = 1
+ object TabSheet1: TTabSheet
+ Caption = 'Preferences'
+ object pnPreferencesBack: TPanel
+ Left = 0
+ Top = 0
+ Width = 659
+ Height = 493
+ Align = alClient
+ BevelOuter = bvNone
+ ParentBackground = False
+ TabOrder = 0
+ object GroupBox2: TGroupBox
+ Left = 0
+ Top = 0
+ Width = 659
+ Height = 493
+ Align = alClient
+ Caption = ' Preferences '
+ ParentBackground = False
+ TabOrder = 0
+ object Label11: TLabel
+ Left = 272
+ Top = 23
+ Width = 186
+ Height = 13
+ Caption = 'AI default (Chat and Databases Chat) '
+ end
+ object Label4: TLabel
+ Left = 21
+ Top = 23
+ Width = 133
+ Height = 13
+ Caption = 'Language used in questions'
+ end
+ object Label19: TLabel
+ Left = 21
+ Top = 122
+ Width = 72
+ Height = 13
+ Caption = 'Default Prompt'
+ end
+ object cBoxAIDefault: TComboBox
+ Left = 272
+ Top = 38
+ Width = 333
+ Height = 21
+ Style = csDropDownList
+ TabOrder = 1
+ Items.Strings = (
+ '')
+ end
+ object ColorBoxColorHighlightCodeDelphi: TColorBox
+ Left = 21
+ Top = 87
+ Width = 194
+ Height = 22
+ TabOrder = 3
+ end
+ object ckColorHighlightCodeDelphiUse: TCheckBox
+ Left = 21
+ Top = 67
+ Width = 194
+ Height = 17
+ Caption = 'Color to highlight Delphi/Pascal code'
+ TabOrder = 2
+ OnClick = ckColorHighlightCodeDelphiUseClick
+ end
+ object cBoxLanguageQuestions: TComboBox
+ Left = 21
+ Top = 38
+ Width = 249
+ Height = 21
+ Hint = 'What is the standard language for questions?'
+ Style = csDropDownList
+ ParentShowHint = False
+ ShowHint = True
+ TabOrder = 0
+ end
+ object gboxData: TGroupBox
+ Left = 2
+ Top = 433
+ Width = 655
+ Height = 58
+ Align = alBottom
+ Caption = ' Data '
+ Padding.Left = 2
+ Padding.Top = 5
+ Padding.Bottom = 3
+ TabOrder = 4
+ object btnOpenDataFolder: TButton
+ Left = 4
+ Top = 20
+ Width = 122
+ Height = 33
+ Cursor = crHandPoint
+ Align = alLeft
+ Caption = 'Open Data Folder'
+ TabOrder = 0
+ OnClick = btnOpenDataFolderClick
+ end
+ end
+ object mmDefaultPrompt: TMemo
+ Left = 21
+ Top = 139
+ Width = 617
+ Height = 201
+ ScrollBars = ssVertical
+ TabOrder = 5
+ end
+ end
+ end
+ end
+ object TabSheet2: TTabSheet
+ Caption = 'AI on-line'
+ ImageIndex = 1
+ object pnIAsOnLineBack: TPanel
+ Left = 0
+ Top = 0
+ Width = 659
+ Height = 493
+ Align = alClient
+ BevelOuter = bvNone
+ ParentBackground = False
+ TabOrder = 0
+ object Bevel1: TBevel
+ AlignWithMargins = True
+ Left = 0
+ Top = 489
+ Width = 659
+ Height = 1
+ Margins.Left = 0
+ Margins.Top = 0
+ Margins.Right = 0
+ Align = alBottom
+ Shape = bsTopLine
+ ExplicitTop = 158
+ ExplicitWidth = 441
+ end
+ object Bevel2: TBevel
+ AlignWithMargins = True
+ Left = 0
+ Top = 505
+ Width = 659
+ Height = 1
+ Margins.Left = 0
+ Margins.Top = 0
+ Margins.Right = 0
+ Align = alTop
+ Shape = bsTopLine
+ ExplicitTop = 475
+ ExplicitWidth = 632
+ end
+ object Bevel3: TBevel
+ AlignWithMargins = True
+ Left = 0
+ Top = 253
+ Width = 659
+ Height = 1
+ Margins.Left = 0
+ Margins.Top = 0
+ Margins.Right = 0
+ Align = alTop
+ Shape = bsTopLine
+ ExplicitTop = 347
+ ExplicitWidth = 632
+ end
+ object Bevel4: TBevel
+ AlignWithMargins = True
+ Left = 0
+ Top = 124
+ Width = 659
+ Height = 1
+ Margins.Left = 0
+ Margins.Top = 0
+ Margins.Right = 0
+ Align = alTop
+ Shape = bsTopLine
+ ExplicitTop = 218
+ ExplicitWidth = 632
+ end
+ object gBoxGemini: TGroupBox
+ Left = 0
+ Top = 0
+ Width = 659
+ Height = 124
+ Align = alTop
+ Caption = ' Gemini (Google) '
+ ParentBackground = False
+ TabOrder = 0
+ object pnGeminiBack: TPanel
+ AlignWithMargins = True
+ Left = 5
+ Top = 18
+ Width = 649
+ Height = 101
+ Align = alClient
+ BevelOuter = bvNone
+ ParentBackground = False
+ TabOrder = 0
+ object Label5: TLabel
+ Left = 16
+ Top = 5
+ Width = 45
+ Height = 13
+ Caption = 'Base URL'
+ end
+ object Label6: TLabel
+ Left = 16
+ Top = 44
+ Width = 37
+ Height = 13
+ Caption = 'API key'
+ end
+ object Label7: TLabel
+ Left = 267
+ Top = 5
+ Width = 28
+ Height = 13
+ Caption = 'Model'
+ end
+ object lbLinkGemini01: TLabel
+ Left = 16
+ Top = 83
+ Width = 86
+ Height = 13
+ Cursor = crHandPoint
+ Hint = 'https://aistudio.google.com/app/apikey'
+ Caption = 'Generate API Key'
+ Font.Charset = DEFAULT_CHARSET
+ Font.Color = clBlue
+ Font.Height = -11
+ Font.Name = 'Tahoma'
+ Font.Style = []
+ ParentFont = False
+ ParentShowHint = False
+ ShowHint = True
+ OnClick = lbLinkGpt01Click
+ end
+ object lbLinkGemini02: TLabel
+ Left = 128
+ Top = 83
+ Width = 72
+ Height = 13
+ Cursor = crHandPoint
+ Hint = 'https://ai.google.dev/gemini-api/docs/api-overview#curl_1'
+ Caption = 'Documentation'
+ Font.Charset = DEFAULT_CHARSET
+ Font.Color = clBlue
+ Font.Height = -11
+ Font.Name = 'Tahoma'
+ Font.Style = []
+ ParentFont = False
+ ParentShowHint = False
+ ShowHint = True
+ OnClick = lbLinkGpt01Click
+ end
+ object btnApiKeyGeminiView: TSpeedButton
+ Left = 582
+ Top = 59
+ Width = 23
+ Height = 22
+ Cursor = crHandPoint
+ Hint = 'Show/Hide API Key'
+ Flat = True
+ Glyph.Data = {
+ 36030000424D3603000000000000360000002800000010000000100000000100
+ 18000000000000030000120B0000120B00000000000000000000FF00FF4A667C
+ BE9596FF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00
+ FFFF00FFFF00FFFF00FF6B9CC31E89E84B7AA3C89693FF00FFFF00FFFF00FFFF
+ 00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FF4BB4FE51B5FF
+ 2089E94B7AA2C69592FF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00
+ FFFF00FFFF00FFFF00FFFF00FF51B7FE51B3FF1D87E64E7AA0CA9792FF00FFFF
+ 00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FF
+ 51B7FE4EB2FF1F89E64E7BA2B99497FF00FFFF00FFFF00FFFF00FFFF00FFFF00
+ FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FF52B8FE4BB1FF2787D95F6A76FF
+ 00FFB0857FC09F94C09F96BC988EFF00FFFF00FFFF00FFFF00FFFF00FFFF00FF
+ FF00FFFF00FF55BDFFB5D6EDBF9D92BB9B8CE7DAC2FFFFE3FFFFE5FDFADAD8C3
+ B3B58D85FF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFCEA795FD
+ EEBEFFFFD8FFFFDAFFFFDBFFFFE6FFFFFBEADDDCAE837FFF00FFFF00FFFF00FF
+ FF00FFFF00FFFF00FFFF00FFC1A091FBDCA8FEF7D0FFFFDBFFFFE3FFFFF8FFFF
+ FDFFFFFDC6A99CFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFC1A091FEE3ACF1
+ C491FCF2CAFFFFDDFFFFE4FFFFF7FFFFF7FFFFE9EEE5CBB9948CFF00FFFF00FF
+ FF00FFFF00FFFF00FFC2A191FFE6AEEEB581F7DCAEFEFDD8FFFFDFFFFFE3FFFF
+ E4FFFFE0F3ECD2BB968EFF00FFFF00FFFF00FFFF00FFFF00FFBC978CFBE7B7F4
+ C791F2C994F8E5B9FEFCD8FFFFDDFFFFDCFFFFE0E2D2BAB68E86FF00FFFF00FF
+ FF00FFFF00FFFF00FFFF00FFD9C3A9FFFEE5F7DCB8F2C994F5D4A5FAE8BDFDF4
+ C9FDFBD6B69089FF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFB58D85E8
+ DEDDFFFEF2F9D8A3F4C48CF9D49FFDEAB8D0B49FB89086FF00FFFF00FFFF00FF
+ FF00FFFF00FFFF00FFFF00FFFF00FFAD827FC9AA9EEFE0B7EFDFB2E7CEACB890
+ 86B89086FF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF
+ 00FFFF00FFBA968ABB988CB79188FF00FFFF00FFFF00FFFF00FF}
+ ParentShowHint = False
+ ShowHint = True
+ OnClick = btnApiKeyGeminiViewClick
+ end
+ object lbLinkGemini03: TLabel
+ Left = 232
+ Top = 83
+ Width = 67
+ Height = 13
+ Cursor = crHandPoint
+ Hint = 'https://ai.google.dev/gemini-api/docs/models/gemini?hl=pt-br'
+ Caption = 'Gemini Models'
+ Font.Charset = DEFAULT_CHARSET
+ Font.Color = clBlue
+ Font.Height = -11
+ Font.Name = 'Tahoma'
+ Font.Style = []
+ ParentFont = False
+ ParentShowHint = False
+ ShowHint = True
+ OnClick = lbLinkGpt01Click
+ end
+ object edtBaseUrlGemini: TEdit
+ Left = 16
+ Top = 20
+ Width = 249
+ Height = 21
+ TabOrder = 0
+ end
+ object edtApiKeyGemini: TEdit
+ Left = 16
+ Top = 60
+ Width = 563
+ Height = 21
+ PasswordChar = '*'
+ TabOrder = 2
+ end
+ object cBoxModelGemini: TComboBox
+ Left = 267
+ Top = 20
+ Width = 333
+ Height = 21
+ TabOrder = 1
+ Items.Strings = (
+ 'v1/models/gemini-1.5-flash:generateContent'
+ 'v1beta/models/gemini-pro:generateContent'
+ 'v1beta/models/gemini-1.5-flash:generateContent')
+ end
+ end
+ end
+ object gBoxOpenAI: TGroupBox
+ Left = 0
+ Top = 128
+ Width = 659
+ Height = 125
+ Align = alTop
+ Caption = ' ChatGPT (OpenAI)'
+ ParentBackground = False
+ TabOrder = 1
+ object pnOpenAIBack: TPanel
+ AlignWithMargins = True
+ Left = 5
+ Top = 18
+ Width = 649
+ Height = 102
+ Align = alClient
+ BevelOuter = bvNone
+ ParentBackground = False
+ TabOrder = 0
+ object Label1: TLabel
+ Left = 16
+ Top = 5
+ Width = 45
+ Height = 13
+ Caption = 'Base URL'
+ end
+ object Label3: TLabel
+ Left = 16
+ Top = 44
+ Width = 37
+ Height = 13
+ Caption = 'API key'
+ end
+ object Label2: TLabel
+ Left = 374
+ Top = 5
+ Width = 28
+ Height = 13
+ Caption = 'Model'
+ end
+ object lbLinkGpt01: TLabel
+ Left = 16
+ Top = 84
+ Width = 86
+ Height = 13
+ Cursor = crHandPoint
+ Hint = 'https://platform.openai.com/api-keys'
+ Caption = 'Generate API Key'
+ Font.Charset = DEFAULT_CHARSET
+ Font.Color = clBlue
+ Font.Height = -11
+ Font.Name = 'Tahoma'
+ Font.Style = []
+ ParentFont = False
+ ParentShowHint = False
+ ShowHint = True
+ OnClick = lbLinkGpt01Click
+ end
+ object btnApiKeyOpenAIView: TSpeedButton
+ Left = 582
+ Top = 59
+ Width = 23
+ Height = 22
+ Cursor = crHandPoint
+ Hint = 'Show/Hide API Key'
+ Flat = True
+ Glyph.Data = {
+ 36030000424D3603000000000000360000002800000010000000100000000100
+ 18000000000000030000120B0000120B00000000000000000000FF00FF4A667C
+ BE9596FF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00
+ FFFF00FFFF00FFFF00FF6B9CC31E89E84B7AA3C89693FF00FFFF00FFFF00FFFF
+ 00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FF4BB4FE51B5FF
+ 2089E94B7AA2C69592FF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00
+ FFFF00FFFF00FFFF00FFFF00FF51B7FE51B3FF1D87E64E7AA0CA9792FF00FFFF
+ 00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FF
+ 51B7FE4EB2FF1F89E64E7BA2B99497FF00FFFF00FFFF00FFFF00FFFF00FFFF00
+ FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FF52B8FE4BB1FF2787D95F6A76FF
+ 00FFB0857FC09F94C09F96BC988EFF00FFFF00FFFF00FFFF00FFFF00FFFF00FF
+ FF00FFFF00FF55BDFFB5D6EDBF9D92BB9B8CE7DAC2FFFFE3FFFFE5FDFADAD8C3
+ B3B58D85FF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFCEA795FD
+ EEBEFFFFD8FFFFDAFFFFDBFFFFE6FFFFFBEADDDCAE837FFF00FFFF00FFFF00FF
+ FF00FFFF00FFFF00FFFF00FFC1A091FBDCA8FEF7D0FFFFDBFFFFE3FFFFF8FFFF
+ FDFFFFFDC6A99CFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFC1A091FEE3ACF1
+ C491FCF2CAFFFFDDFFFFE4FFFFF7FFFFF7FFFFE9EEE5CBB9948CFF00FFFF00FF
+ FF00FFFF00FFFF00FFC2A191FFE6AEEEB581F7DCAEFEFDD8FFFFDFFFFFE3FFFF
+ E4FFFFE0F3ECD2BB968EFF00FFFF00FFFF00FFFF00FFFF00FFBC978CFBE7B7F4
+ C791F2C994F8E5B9FEFCD8FFFFDDFFFFDCFFFFE0E2D2BAB68E86FF00FFFF00FF
+ FF00FFFF00FFFF00FFFF00FFD9C3A9FFFEE5F7DCB8F2C994F5D4A5FAE8BDFDF4
+ C9FDFBD6B69089FF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFB58D85E8
+ DEDDFFFEF2F9D8A3F4C48CF9D49FFDEAB8D0B49FB89086FF00FFFF00FFFF00FF
+ FF00FFFF00FFFF00FFFF00FFFF00FFAD827FC9AA9EEFE0B7EFDFB2E7CEACB890
+ 86B89086FF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF
+ 00FFFF00FFBA968ABB988CB79188FF00FFFF00FFFF00FFFF00FF}
+ ParentShowHint = False
+ ShowHint = True
+ OnClick = btnApiKeyOpenAIViewClick
+ end
+ object lbLinkGpt02: TLabel
+ Left = 128
+ Top = 84
+ Width = 72
+ Height = 13
+ Cursor = crHandPoint
+ Hint = 'https://platform.openai.com/docs/api-reference/making-requests'
+ Caption = 'Documentation'
+ Font.Charset = DEFAULT_CHARSET
+ Font.Color = clBlue
+ Font.Height = -11
+ Font.Name = 'Tahoma'
+ Font.Style = []
+ ParentFont = False
+ ParentShowHint = False
+ ShowHint = True
+ OnClick = lbLinkGpt01Click
+ end
+ object edtBaseUrlOpenAI: TEdit
+ Left = 16
+ Top = 21
+ Width = 356
+ Height = 21
+ TabOrder = 0
+ end
+ object edtApiKeyOpenAI: TEdit
+ Left = 16
+ Top = 60
+ Width = 563
+ Height = 21
+ PasswordChar = '*'
+ TabOrder = 2
+ end
+ object cBoxModelOpenAI: TComboBox
+ Left = 374
+ Top = 21
+ Width = 226
+ Height = 21
+ TabOrder = 1
+ Items.Strings = (
+ 'gpt-3.5-turbo'
+ 'gpt-3.5-turbo-16k'
+ 'gpt-4'
+ 'gpt-4o-2024-05-13'
+ 'gpt-4o-2024-08-06'
+ 'gpt-4-turbo')
+ end
+ end
+ end
+ object gBoxGroq: TGroupBox
+ Left = 0
+ Top = 257
+ Width = 659
+ Height = 124
+ Align = alTop
+ Caption = ' Groq '
+ ParentBackground = False
+ TabOrder = 2
+ object pnGroqBack: TPanel
+ AlignWithMargins = True
+ Left = 5
+ Top = 18
+ Width = 649
+ Height = 101
+ Align = alClient
+ BevelOuter = bvNone
+ ParentBackground = False
+ TabOrder = 0
+ object Label8: TLabel
+ Left = 16
+ Top = 5
+ Width = 45
+ Height = 13
+ Caption = 'Base URL'
+ end
+ object Label9: TLabel
+ Left = 16
+ Top = 44
+ Width = 37
+ Height = 13
+ Caption = 'API key'
+ end
+ object Label10: TLabel
+ Left = 374
+ Top = 5
+ Width = 28
+ Height = 13
+ Caption = 'Model'
+ end
+ object lbLinkGroq01: TLabel
+ Left = 16
+ Top = 84
+ Width = 86
+ Height = 13
+ Cursor = crHandPoint
+ Hint = 'https://console.groq.com/keys'
+ Caption = 'Generate API Key'
+ Font.Charset = DEFAULT_CHARSET
+ Font.Color = clBlue
+ Font.Height = -11
+ Font.Name = 'Tahoma'
+ Font.Style = []
+ ParentFont = False
+ ParentShowHint = False
+ ShowHint = True
+ OnClick = lbLinkGpt01Click
+ end
+ object btnApiKeyGroqView: TSpeedButton
+ Left = 582
+ Top = 59
+ Width = 23
+ Height = 22
+ Cursor = crHandPoint
+ Hint = 'Show/Hide API Key'
+ Flat = True
+ Glyph.Data = {
+ 36030000424D3603000000000000360000002800000010000000100000000100
+ 18000000000000030000120B0000120B00000000000000000000FF00FF4A667C
+ BE9596FF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00
+ FFFF00FFFF00FFFF00FF6B9CC31E89E84B7AA3C89693FF00FFFF00FFFF00FFFF
+ 00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FF4BB4FE51B5FF
+ 2089E94B7AA2C69592FF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00
+ FFFF00FFFF00FFFF00FFFF00FF51B7FE51B3FF1D87E64E7AA0CA9792FF00FFFF
+ 00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FF
+ 51B7FE4EB2FF1F89E64E7BA2B99497FF00FFFF00FFFF00FFFF00FFFF00FFFF00
+ FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FF52B8FE4BB1FF2787D95F6A76FF
+ 00FFB0857FC09F94C09F96BC988EFF00FFFF00FFFF00FFFF00FFFF00FFFF00FF
+ FF00FFFF00FF55BDFFB5D6EDBF9D92BB9B8CE7DAC2FFFFE3FFFFE5FDFADAD8C3
+ B3B58D85FF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFCEA795FD
+ EEBEFFFFD8FFFFDAFFFFDBFFFFE6FFFFFBEADDDCAE837FFF00FFFF00FFFF00FF
+ FF00FFFF00FFFF00FFFF00FFC1A091FBDCA8FEF7D0FFFFDBFFFFE3FFFFF8FFFF
+ FDFFFFFDC6A99CFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFC1A091FEE3ACF1
+ C491FCF2CAFFFFDDFFFFE4FFFFF7FFFFF7FFFFE9EEE5CBB9948CFF00FFFF00FF
+ FF00FFFF00FFFF00FFC2A191FFE6AEEEB581F7DCAEFEFDD8FFFFDFFFFFE3FFFF
+ E4FFFFE0F3ECD2BB968EFF00FFFF00FFFF00FFFF00FFFF00FFBC978CFBE7B7F4
+ C791F2C994F8E5B9FEFCD8FFFFDDFFFFDCFFFFE0E2D2BAB68E86FF00FFFF00FF
+ FF00FFFF00FFFF00FFFF00FFD9C3A9FFFEE5F7DCB8F2C994F5D4A5FAE8BDFDF4
+ C9FDFBD6B69089FF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFB58D85E8
+ DEDDFFFEF2F9D8A3F4C48CF9D49FFDEAB8D0B49FB89086FF00FFFF00FFFF00FF
+ FF00FFFF00FFFF00FFFF00FFFF00FFAD827FC9AA9EEFE0B7EFDFB2E7CEACB890
+ 86B89086FF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF
+ 00FFFF00FFBA968ABB988CB79188FF00FFFF00FFFF00FFFF00FF}
+ ParentShowHint = False
+ ShowHint = True
+ OnClick = btnApiKeyGroqViewClick
+ end
+ object lbLinkGroq02: TLabel
+ Left = 128
+ Top = 84
+ Width = 72
+ Height = 13
+ Cursor = crHandPoint
+ Hint = 'https://console.groq.com/docs/quickstart'
+ Caption = 'Documentation'
+ Font.Charset = DEFAULT_CHARSET
+ Font.Color = clBlue
+ Font.Height = -11
+ Font.Name = 'Tahoma'
+ Font.Style = []
+ ParentFont = False
+ ParentShowHint = False
+ ShowHint = True
+ OnClick = lbLinkGpt01Click
+ end
+ object lbLinkGroq03: TLabel
+ Left = 232
+ Top = 84
+ Width = 59
+ Height = 13
+ Cursor = crHandPoint
+ Hint = 'https://console.groq.com/docs/models'
+ Caption = 'Groq Models'
+ Font.Charset = DEFAULT_CHARSET
+ Font.Color = clBlue
+ Font.Height = -11
+ Font.Name = 'Tahoma'
+ Font.Style = []
+ ParentFont = False
+ ParentShowHint = False
+ ShowHint = True
+ OnClick = lbLinkGpt01Click
+ end
+ object edtBaseUrlGroq: TEdit
+ Left = 16
+ Top = 21
+ Width = 356
+ Height = 21
+ TabOrder = 0
+ end
+ object edtApiKeyGroq: TEdit
+ Left = 16
+ Top = 60
+ Width = 563
+ Height = 21
+ PasswordChar = '*'
+ TabOrder = 2
+ end
+ object cBoxModelGroq: TComboBox
+ Left = 374
+ Top = 21
+ Width = 226
+ Height = 21
+ TabOrder = 1
+ Items.Strings = (
+ 'llama3-8b-8192'
+ 'llama3-70b-8192'
+ 'llama3-groq-8b-8192-tool-use-preview'
+ 'llama3-groq-70b-8192-tool-use-preview'
+ 'mixtral-8x7b-32768'
+ 'gemma-7b-it'
+ 'gemma2-9b-it'
+ 'whisper-large-v3')
+ end
+ end
+ end
+ object gBoxMistral: TGroupBox
+ Left = 0
+ Top = 381
+ Width = 659
+ Height = 124
+ Align = alTop
+ Caption = ' Mistral '
+ ParentBackground = False
+ TabOrder = 3
+ object pnMistralBack: TPanel
+ AlignWithMargins = True
+ Left = 5
+ Top = 18
+ Width = 649
+ Height = 101
+ Align = alClient
+ BevelOuter = bvNone
+ ParentBackground = False
+ TabOrder = 0
+ object Label20: TLabel
+ Left = 16
+ Top = 5
+ Width = 45
+ Height = 13
+ Caption = 'Base URL'
+ end
+ object Label21: TLabel
+ Left = 16
+ Top = 44
+ Width = 37
+ Height = 13
+ Caption = 'API key'
+ end
+ object Label22: TLabel
+ Left = 374
+ Top = 5
+ Width = 28
+ Height = 13
+ Caption = 'Model'
+ end
+ object lbLinkMistral01: TLabel
+ Left = 16
+ Top = 84
+ Width = 86
+ Height = 13
+ Cursor = crHandPoint
+ Hint = 'https://console.mistral.ai/api-keys/'
+ Caption = 'Generate API Key'
+ Font.Charset = DEFAULT_CHARSET
+ Font.Color = clBlue
+ Font.Height = -11
+ Font.Name = 'Tahoma'
+ Font.Style = []
+ ParentFont = False
+ ParentShowHint = False
+ ShowHint = True
+ OnClick = lbLinkGpt01Click
+ end
+ object btnApiKeyMistralView: TSpeedButton
+ Left = 582
+ Top = 59
+ Width = 23
+ Height = 22
+ Cursor = crHandPoint
+ Hint = 'Show/Hide API Key'
+ Flat = True
+ Glyph.Data = {
+ 36030000424D3603000000000000360000002800000010000000100000000100
+ 18000000000000030000120B0000120B00000000000000000000FF00FF4A667C
+ BE9596FF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00
+ FFFF00FFFF00FFFF00FF6B9CC31E89E84B7AA3C89693FF00FFFF00FFFF00FFFF
+ 00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FF4BB4FE51B5FF
+ 2089E94B7AA2C69592FF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00
+ FFFF00FFFF00FFFF00FFFF00FF51B7FE51B3FF1D87E64E7AA0CA9792FF00FFFF
+ 00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FF
+ 51B7FE4EB2FF1F89E64E7BA2B99497FF00FFFF00FFFF00FFFF00FFFF00FFFF00
+ FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FF52B8FE4BB1FF2787D95F6A76FF
+ 00FFB0857FC09F94C09F96BC988EFF00FFFF00FFFF00FFFF00FFFF00FFFF00FF
+ FF00FFFF00FF55BDFFB5D6EDBF9D92BB9B8CE7DAC2FFFFE3FFFFE5FDFADAD8C3
+ B3B58D85FF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFCEA795FD
+ EEBEFFFFD8FFFFDAFFFFDBFFFFE6FFFFFBEADDDCAE837FFF00FFFF00FFFF00FF
+ FF00FFFF00FFFF00FFFF00FFC1A091FBDCA8FEF7D0FFFFDBFFFFE3FFFFF8FFFF
+ FDFFFFFDC6A99CFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFC1A091FEE3ACF1
+ C491FCF2CAFFFFDDFFFFE4FFFFF7FFFFF7FFFFE9EEE5CBB9948CFF00FFFF00FF
+ FF00FFFF00FFFF00FFC2A191FFE6AEEEB581F7DCAEFEFDD8FFFFDFFFFFE3FFFF
+ E4FFFFE0F3ECD2BB968EFF00FFFF00FFFF00FFFF00FFFF00FFBC978CFBE7B7F4
+ C791F2C994F8E5B9FEFCD8FFFFDDFFFFDCFFFFE0E2D2BAB68E86FF00FFFF00FF
+ FF00FFFF00FFFF00FFFF00FFD9C3A9FFFEE5F7DCB8F2C994F5D4A5FAE8BDFDF4
+ C9FDFBD6B69089FF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFB58D85E8
+ DEDDFFFEF2F9D8A3F4C48CF9D49FFDEAB8D0B49FB89086FF00FFFF00FFFF00FF
+ FF00FFFF00FFFF00FFFF00FFFF00FFAD827FC9AA9EEFE0B7EFDFB2E7CEACB890
+ 86B89086FF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF
+ 00FFFF00FFBA968ABB988CB79188FF00FFFF00FFFF00FFFF00FF}
+ ParentShowHint = False
+ ShowHint = True
+ OnClick = btnApiKeyMistralViewClick
+ end
+ object lbLinkMistral02: TLabel
+ Left = 128
+ Top = 84
+ Width = 72
+ Height = 13
+ Cursor = crHandPoint
+ Hint = 'https://docs.mistral.ai/getting-started/quickstart/'
+ Caption = 'Documentation'
+ Font.Charset = DEFAULT_CHARSET
+ Font.Color = clBlue
+ Font.Height = -11
+ Font.Name = 'Tahoma'
+ Font.Style = []
+ ParentFont = False
+ ParentShowHint = False
+ ShowHint = True
+ OnClick = lbLinkGpt01Click
+ end
+ object lbLinkMistral03: TLabel
+ Left = 232
+ Top = 84
+ Width = 67
+ Height = 13
+ Cursor = crHandPoint
+ Hint = 'https://docs.mistral.ai/getting-started/models/models_overview/'
+ Caption = 'Mistral Models'
+ Font.Charset = DEFAULT_CHARSET
+ Font.Color = clBlue
+ Font.Height = -11
+ Font.Name = 'Tahoma'
+ Font.Style = []
+ ParentFont = False
+ ParentShowHint = False
+ ShowHint = True
+ OnClick = lbLinkGpt01Click
+ end
+ object edtBaseUrlMistral: TEdit
+ Left = 16
+ Top = 21
+ Width = 356
+ Height = 21
+ TabOrder = 0
+ end
+ object edtApiKeyMistral: TEdit
+ Left = 16
+ Top = 60
+ Width = 563
+ Height = 21
+ PasswordChar = '*'
+ TabOrder = 2
+ end
+ object cBoxModelMistral: TComboBox
+ Left = 374
+ Top = 21
+ Width = 226
+ Height = 21
+ TabOrder = 1
+ Items.Strings = (
+ 'codestral-latest'
+ 'mistral-large-latest'
+ 'ministral-3b-latest'
+ 'ministral-8b-latest'
+ 'mistral-small-latest'
+ 'open-codestral-mamba')
+ end
+ end
+ end
+ end
+ end
+ object TabSheet3: TTabSheet
+ Caption = 'AI off-Line'
+ ImageIndex = 2
+ object pnIAsOffLineBack: TPanel
+ Left = 0
+ Top = 0
+ Width = 659
+ Height = 493
+ Align = alClient
+ BevelOuter = bvNone
+ ParentBackground = False
+ TabOrder = 0
+ object GroupBox1: TGroupBox
+ Left = 0
+ Top = 0
+ Width = 659
+ Height = 152
+ Align = alTop
+ Caption = ' Ollama (offline) '
+ ParentBackground = False
+ TabOrder = 0
+ object Panel1: TPanel
+ AlignWithMargins = True
+ Left = 5
+ Top = 18
+ Width = 649
+ Height = 129
+ Align = alClient
+ BevelOuter = bvNone
+ ParentBackground = False
+ TabOrder = 0
+ object Label12: TLabel
+ Left = 16
+ Top = 5
+ Width = 45
+ Height = 13
+ Caption = 'Base URL'
+ end
+ object Label13: TLabel
+ Left = 16
+ Top = 44
+ Width = 29
+ Height = 13
+ Caption = 'Token'
+ end
+ object Label14: TLabel
+ Left = 374
+ Top = 5
+ Width = 28
+ Height = 13
+ Caption = 'Model'
+ end
+ object btnApiKeyOllamaView: TSpeedButton
+ Left = 582
+ Top = 59
+ Width = 23
+ Height = 22
+ Cursor = crHandPoint
+ Hint = 'Show/Hide API Key'
+ Flat = True
+ Glyph.Data = {
+ 36030000424D3603000000000000360000002800000010000000100000000100
+ 18000000000000030000120B0000120B00000000000000000000FF00FF4A667C
+ BE9596FF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00
+ FFFF00FFFF00FFFF00FF6B9CC31E89E84B7AA3C89693FF00FFFF00FFFF00FFFF
+ 00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FF4BB4FE51B5FF
+ 2089E94B7AA2C69592FF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00
+ FFFF00FFFF00FFFF00FFFF00FF51B7FE51B3FF1D87E64E7AA0CA9792FF00FFFF
+ 00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FF
+ 51B7FE4EB2FF1F89E64E7BA2B99497FF00FFFF00FFFF00FFFF00FFFF00FFFF00
+ FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FF52B8FE4BB1FF2787D95F6A76FF
+ 00FFB0857FC09F94C09F96BC988EFF00FFFF00FFFF00FFFF00FFFF00FFFF00FF
+ FF00FFFF00FF55BDFFB5D6EDBF9D92BB9B8CE7DAC2FFFFE3FFFFE5FDFADAD8C3
+ B3B58D85FF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFCEA795FD
+ EEBEFFFFD8FFFFDAFFFFDBFFFFE6FFFFFBEADDDCAE837FFF00FFFF00FFFF00FF
+ FF00FFFF00FFFF00FFFF00FFC1A091FBDCA8FEF7D0FFFFDBFFFFE3FFFFF8FFFF
+ FDFFFFFDC6A99CFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFC1A091FEE3ACF1
+ C491FCF2CAFFFFDDFFFFE4FFFFF7FFFFF7FFFFE9EEE5CBB9948CFF00FFFF00FF
+ FF00FFFF00FFFF00FFC2A191FFE6AEEEB581F7DCAEFEFDD8FFFFDFFFFFE3FFFF
+ E4FFFFE0F3ECD2BB968EFF00FFFF00FFFF00FFFF00FFFF00FFBC978CFBE7B7F4
+ C791F2C994F8E5B9FEFCD8FFFFDDFFFFDCFFFFE0E2D2BAB68E86FF00FFFF00FF
+ FF00FFFF00FFFF00FFFF00FFD9C3A9FFFEE5F7DCB8F2C994F5D4A5FAE8BDFDF4
+ C9FDFBD6B69089FF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFB58D85E8
+ DEDDFFFEF2F9D8A3F4C48CF9D49FFDEAB8D0B49FB89086FF00FFFF00FFFF00FF
+ FF00FFFF00FFFF00FFFF00FFFF00FFAD827FC9AA9EEFE0B7EFDFB2E7CEACB890
+ 86B89086FF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF
+ 00FFFF00FFBA968ABB988CB79188FF00FFFF00FFFF00FFFF00FF}
+ ParentShowHint = False
+ ShowHint = True
+ OnClick = btnApiKeyOllamaViewClick
+ end
+ object lbLinkOllama02: TLabel
+ Left = 128
+ Top = 84
+ Width = 72
+ Height = 13
+ Cursor = crHandPoint
+ Hint = 'https://github.com/ollama/ollama/blob/main/docs/api.md'
+ Caption = 'Documentation'
+ Font.Charset = DEFAULT_CHARSET
+ Font.Color = clBlue
+ Font.Height = -11
+ Font.Name = 'Tahoma'
+ Font.Style = []
+ ParentFont = False
+ ParentShowHint = False
+ ShowHint = True
+ OnClick = lbLinkGpt01Click
+ end
+ object lbLinkOllama03: TLabel
+ Left = 232
+ Top = 84
+ Width = 68
+ Height = 13
+ Cursor = crHandPoint
+ Hint = 'https://ollama.com/library'
+ Caption = 'Ollama Models'
+ Font.Charset = DEFAULT_CHARSET
+ Font.Color = clBlue
+ Font.Height = -11
+ Font.Name = 'Tahoma'
+ Font.Style = []
+ ParentFont = False
+ ParentShowHint = False
+ ShowHint = True
+ OnClick = lbLinkGpt01Click
+ end
+ object lbLinkOllama01: TLabel
+ Left = 16
+ Top = 84
+ Width = 82
+ Height = 13
+ Cursor = crHandPoint
+ Hint = 'https://ollama.com/download'
+ Caption = 'Ollama Download'
+ Font.Charset = DEFAULT_CHARSET
+ Font.Color = clBlue
+ Font.Height = -11
+ Font.Name = 'Tahoma'
+ Font.Style = []
+ ParentFont = False
+ ParentShowHint = False
+ ShowHint = True
+ OnClick = lbLinkGpt01Click
+ end
+ object edtBaseUrlOllama: TEdit
+ Left = 16
+ Top = 21
+ Width = 356
+ Height = 21
+ TabOrder = 0
+ end
+ object edtApiKeyOllama: TEdit
+ Left = 16
+ Top = 60
+ Width = 563
+ Height = 21
+ PasswordChar = '*'
+ TabOrder = 2
+ end
+ object cBoxModelOllama: TComboBox
+ Left = 374
+ Top = 21
+ Width = 226
+ Height = 21
+ TabOrder = 1
+ Items.Strings = (
+ 'llama2'
+ 'llama3'
+ 'llama3.1'
+ 'codellama'
+ 'tinyllama'
+ 'mistral')
+ end
+ end
+ end
+ end
+ end
+ object TabSheet4: TTabSheet
+ Caption = 'Code Completion'
+ ImageIndex = 3
+ object pnCodeCompletionBack: TPanel
+ Left = 0
+ Top = 0
+ Width = 659
+ Height = 493
+ Align = alClient
+ BevelOuter = bvNone
+ ParentBackground = False
+ TabOrder = 0
+ object GroupBox3: TGroupBox
+ Left = 0
+ Top = 0
+ Width = 659
+ Height = 493
+ Align = alClient
+ Caption = ' Code Completion (BETA) '
+ ParentBackground = False
+ TabOrder = 0
+ object Panel2: TPanel
+ AlignWithMargins = True
+ Left = 5
+ Top = 18
+ Width = 649
+ Height = 470
+ Align = alClient
+ BevelOuter = bvNone
+ ParentBackground = False
+ TabOrder = 0
+ object Label15: TLabel
+ Left = 16
+ Top = 29
+ Width = 48
+ Height = 13
+ Caption = 'AI default'
+ end
+ object Label16: TLabel
+ Left = 16
+ Top = 138
+ Width = 231
+ Height = 13
+ Caption = 'Shortcut for invoke (Delphi IDE restart required)'
+ end
+ object Label17: TLabel
+ Left = 16
+ Top = 443
+ Width = 316
+ Height = 13
+ Caption = '* Attention! This feature is in Beta and may be unstable.'
+ Font.Charset = DEFAULT_CHARSET
+ Font.Color = clWindowText
+ Font.Height = -11
+ Font.Name = 'Tahoma'
+ Font.Style = [fsBold]
+ ParentFont = False
+ end
+ object Label18: TLabel
+ Left = 16
+ Top = 187
+ Width = 72
+ Height = 13
+ Caption = 'Default Prompt'
+ end
+ object ckCodeCompletionUse: TCheckBox
+ Left = 16
+ Top = 5
+ Width = 111
+ Height = 17
+ Cursor = crHandPoint
+ Caption = 'Code Completion'
+ TabOrder = 0
+ end
+ object cBoxCodeCompletionAIDefault: TComboBox
+ Left = 16
+ Top = 48
+ Width = 333
+ Height = 21
+ Style = csDropDownList
+ TabOrder = 1
+ Items.Strings = (
+ '')
+ end
+ object ColorBoxCodeCompletionSuggestionColor: TColorBox
+ Left = 16
+ Top = 102
+ Width = 333
+ Height = 22
+ TabOrder = 2
+ end
+ object ckCodeCompletionSuggestionColorUse: TCheckBox
+ Left = 16
+ Top = 81
+ Width = 131
+ Height = 17
+ Cursor = crHandPoint
+ Caption = 'Suggestion Code Color'
+ TabOrder = 3
+ OnClick = ckCodeCompletionSuggestionColorUseClick
+ end
+ object edtCodeCompletionShortcutInvoke: TEdit
+ Left = 16
+ Top = 155
+ Width = 333
+ Height = 21
+ TabOrder = 4
+ end
+ object mmCodeCompletionDefaultPrompt: TMemo
+ Left = 16
+ Top = 204
+ Width = 617
+ Height = 201
+ ScrollBars = ssVertical
+ TabOrder = 5
+ end
+ end
+ end
+ end
+ end
end
end
diff --git a/Src/Settings/DelphiAIDev.Settings.View.pas b/Src/Settings/DelphiAIDev.Settings.View.pas
index 764b65e..5703288 100644
--- a/Src/Settings/DelphiAIDev.Settings.View.pas
+++ b/Src/Settings/DelphiAIDev.Settings.View.pas
@@ -14,9 +14,12 @@ interface
Vcl.Dialogs,
Vcl.StdCtrls,
Vcl.ExtCtrls,
+ Vcl.Buttons,
+ Vcl.ComCtrls,
+ Vcl.Menus,
DelphiAIDev.Settings,
DelphiAIDev.Types,
- Vcl.Buttons;
+ DelphiAIDev.Consts;
type
TDelphiAIDevSettingsView = class(TForm)
@@ -24,40 +27,66 @@ TDelphiAIDevSettingsView = class(TForm)
btnConfirm: TButton;
btnClose: TButton;
pnBackAll: TPanel;
- pnBody: TPanel;
+ lbRestoreDefaults: TLabel;
+ PageControl1: TPageControl;
+ TabSheet1: TTabSheet;
+ TabSheet2: TTabSheet;
+ pnMyControl: TPanel;
+ pnMyControlButtons: TPanel;
+ btnPreferences: TButton;
+ btnIAsOnline: TButton;
+ pnPreferencesBack: TPanel;
+ GroupBox2: TGroupBox;
+ Label11: TLabel;
+ Label4: TLabel;
+ cBoxAIDefault: TComboBox;
+ ColorBoxColorHighlightCodeDelphi: TColorBox;
+ ckColorHighlightCodeDelphiUse: TCheckBox;
+ cBoxLanguageQuestions: TComboBox;
+ TabSheet3: TTabSheet;
+ pnIAsOffLineBack: TPanel;
+ GroupBox1: TGroupBox;
+ Panel1: TPanel;
+ Label12: TLabel;
+ Label13: TLabel;
+ Label14: TLabel;
+ btnApiKeyOllamaView: TSpeedButton;
+ lbLinkOllama02: TLabel;
+ lbLinkOllama03: TLabel;
+ lbLinkOllama01: TLabel;
+ edtBaseUrlOllama: TEdit;
+ edtApiKeyOllama: TEdit;
+ cBoxModelOllama: TComboBox;
+ TabSheet4: TTabSheet;
+ pnCodeCompletionBack: TPanel;
+ pnIAsOnLineBack: TPanel;
+ Bevel1: TBevel;
+ Bevel2: TBevel;
+ Bevel3: TBevel;
+ Bevel4: TBevel;
gBoxGemini: TGroupBox;
pnGeminiBack: TPanel;
Label5: TLabel;
Label6: TLabel;
Label7: TLabel;
lbLinkGemini01: TLabel;
+ lbLinkGemini02: TLabel;
+ btnApiKeyGeminiView: TSpeedButton;
+ lbLinkGemini03: TLabel;
edtBaseUrlGemini: TEdit;
edtApiKeyGemini: TEdit;
cBoxModelGemini: TComboBox;
- lbLinkGemini02: TLabel;
- GroupBox2: TGroupBox;
gBoxOpenAI: TGroupBox;
pnOpenAIBack: TPanel;
Label1: TLabel;
Label3: TLabel;
Label2: TLabel;
lbLinkGpt01: TLabel;
+ btnApiKeyOpenAIView: TSpeedButton;
+ lbLinkGpt02: TLabel;
edtBaseUrlOpenAI: TEdit;
edtApiKeyOpenAI: TEdit;
cBoxModelOpenAI: TComboBox;
- Label11: TLabel;
- cBoxAIDefault: TComboBox;
- btnApiKeyGeminiView: TSpeedButton;
- btnApiKeyOpenAIView: TSpeedButton;
- lbLinkGpt02: TLabel;
- lbRestoreDefaults: TLabel;
- ColorBoxColorHighlightCodeDelphi: TColorBox;
- ckColorHighlightCodeDelphiUse: TCheckBox;
- lbLinkGemini03: TLabel;
- Label4: TLabel;
- cBoxLanguageQuestions: TComboBox;
- gboxData: TGroupBox;
- btnOpenDataFolder: TButton;
gBoxGroq: TGroupBox;
pnGroqBack: TPanel;
Label8: TLabel;
@@ -66,10 +95,42 @@ TDelphiAIDevSettingsView = class(TForm)
lbLinkGroq01: TLabel;
btnApiKeyGroqView: TSpeedButton;
lbLinkGroq02: TLabel;
+ lbLinkGroq03: TLabel;
edtBaseUrlGroq: TEdit;
edtApiKeyGroq: TEdit;
cBoxModelGroq: TComboBox;
- lbLinkGroq03: TLabel;
+ pnBody: TPanel;
+ btnIAsOffline: TButton;
+ btnCodeCompletion: TButton;
+ Bevel5: TBevel;
+ GroupBox3: TGroupBox;
+ Panel2: TPanel;
+ ckCodeCompletionUse: TCheckBox;
+ Label15: TLabel;
+ cBoxCodeCompletionAIDefault: TComboBox;
+ ColorBoxCodeCompletionSuggestionColor: TColorBox;
+ ckCodeCompletionSuggestionColorUse: TCheckBox;
+ Label16: TLabel;
+ gboxData: TGroupBox;
+ btnOpenDataFolder: TButton;
+ edtCodeCompletionShortcutInvoke: TEdit;
+ Label17: TLabel;
+ Label18: TLabel;
+ mmCodeCompletionDefaultPrompt: TMemo;
+ Label19: TLabel;
+ mmDefaultPrompt: TMemo;
+ gBoxMistral: TGroupBox;
+ pnMistralBack: TPanel;
+ Label20: TLabel;
+ Label21: TLabel;
+ Label22: TLabel;
+ lbLinkMistral01: TLabel;
+ btnApiKeyMistralView: TSpeedButton;
+ lbLinkMistral02: TLabel;
+ lbLinkMistral03: TLabel;
+ edtBaseUrlMistral: TEdit;
+ edtApiKeyMistral: TEdit;
+ cBoxModelMistral: TComboBox;
procedure FormCreate(Sender: TObject);
procedure FormKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState);
procedure btnCloseClick(Sender: TObject);
@@ -81,8 +142,15 @@ TDelphiAIDevSettingsView = class(TForm)
procedure FormClose(Sender: TObject; var Action: TCloseAction);
procedure lbRestoreDefaultsClick(Sender: TObject);
procedure ckColorHighlightCodeDelphiUseClick(Sender: TObject);
- procedure btnOpenDataFolderClick(Sender: TObject);
procedure btnApiKeyGroqViewClick(Sender: TObject);
+ procedure btnApiKeyOllamaViewClick(Sender: TObject);
+ procedure btnPreferencesClick(Sender: TObject);
+ procedure btnIAsOnlineClick(Sender: TObject);
+ procedure btnIAsOfflineClick(Sender: TObject);
+ procedure btnCodeCompletionClick(Sender: TObject);
+ procedure btnOpenDataFolderClick(Sender: TObject);
+ procedure ckCodeCompletionSuggestionColorUseClick(Sender: TObject);
+ procedure btnApiKeyMistralViewClick(Sender: TObject);
private
FSettings: TDelphiAIDevSettings;
procedure SaveSettings;
@@ -91,6 +159,11 @@ TDelphiAIDevSettingsView = class(TForm)
procedure ConfigFieldsColorHighlightDelphi;
procedure FillcBoxLanguageQuestions;
procedure FillcBoxAIDefault;
+ procedure FillcBoxCodeCompletionAIDefault;
+ procedure ShowPanel(const AButton: TButton; const APanel: TPanel);
+ procedure PanelsSetParent;
+ procedure ValidateCodeCompletionShortcutInvoke;
+ procedure ConfigFieldsCodeCompletionSuggestionColor;
public
end;
@@ -111,15 +184,16 @@ procedure TDelphiAIDevSettingsView.FormCreate(Sender: TObject);
TUtilsOTA.IDEThemingAll(TDelphiAIDevSettingsView, Self);
FSettings := TDelphiAIDevSettings.GetInstance;
+ Self.PanelsSetParent;
Self.FillcBoxLanguageQuestions;
Self.FillcBoxAIDefault;
+ Self.FillcBoxCodeCompletionAIDefault;
end;
procedure TDelphiAIDevSettingsView.FormShow(Sender: TObject);
begin
FSettings.LoadData;
Self.ConfigScreen;
- //FSettings.LoadData;
Self.LoadSettings;
end;
@@ -139,13 +213,22 @@ procedure TDelphiAIDevSettingsView.FillcBoxLanguageQuestions;
procedure TDelphiAIDevSettingsView.FillcBoxAIDefault;
var
- LItem: TC4DAIsAvailable;
+ LItem: TC4DAiAvailable;
begin
cBoxAIDefault.Items.Clear;
- for LItem := Low(TC4DAIsAvailable) to High(TC4DAIsAvailable) do
+ for LItem := Low(TC4DAiAvailable) to High(TC4DAiAvailable) do
cBoxAIDefault.Items.Add(LItem.ToString);
end;
+procedure TDelphiAIDevSettingsView.FillcBoxCodeCompletionAIDefault;
+var
+ LItem: TC4DAiAvailable;
+begin
+ cBoxCodeCompletionAIDefault.Items.Clear;
+ for LItem := Low(TC4DAiAvailable) to High(TC4DAiAvailable) do
+ cBoxCodeCompletionAIDefault.Items.Add(LItem.ToString);
+end;
+
procedure TDelphiAIDevSettingsView.ConfigScreen;
var
LColor: TColor;
@@ -159,7 +242,13 @@ procedure TDelphiAIDevSettingsView.ConfigScreen;
lbLinkGroq01.Font.Color := LColor;
lbLinkGroq02.Font.Color := LColor;
lbLinkGroq03.Font.Color := LColor;
+ lbLinkMistral01.Font.Color := LColor;
+ lbLinkMistral02.Font.Color := LColor;
+ lbLinkMistral03.Font.Color := LColor;
lbRestoreDefaults.Font.Color := LColor;
+ lbLinkOllama01.Font.Color := LColor;
+ lbLinkOllama02.Font.Color := LColor;
+ lbLinkOllama03.Font.Color := LColor;
end;
procedure TDelphiAIDevSettingsView.btnApiKeyGeminiViewClick(Sender: TObject);
@@ -177,6 +266,11 @@ procedure TDelphiAIDevSettingsView.btnApiKeyGroqViewClick(Sender: TObject);
TUtils.TogglePasswordChar(edtApiKeyGroq);
end;
+procedure TDelphiAIDevSettingsView.btnApiKeyMistralViewClick(Sender: TObject);
+begin
+ TUtils.TogglePasswordChar(edtApiKeyMistral);
+end;
+
procedure TDelphiAIDevSettingsView.btnCloseClick(Sender: TObject);
begin
Self.Close;
@@ -197,7 +291,7 @@ procedure TDelphiAIDevSettingsView.FormKeyDown(Sender: TObject; var Key: Word; S
procedure TDelphiAIDevSettingsView.lbLinkGpt01Click(Sender: TObject);
begin
- //**Several
+ //**SEVERAL
TUtils.OpenLink(TLabel(Sender).Hint.Trim);
end;
@@ -206,27 +300,60 @@ procedure TDelphiAIDevSettingsView.lbRestoreDefaultsClick(Sender: TObject);
LApiKeyGemini: string;
LApiKeyOpenAI: string;
LApiKeyGroq: string;
+ LApiKeyMistral: string;
+ LApiKeyOllama: string;
begin
LApiKeyGemini := FSettings.ApiKeyGemini;
LApiKeyOpenAI := FSettings.ApiKeyOpenAI;
LApiKeyGroq := FSettings.ApiKeyGroq;
+ LApiKeyMistral := FSettings.ApiKeyMistral;
+ LApiKeyOllama := FSettings.ApiKeyOllama;
FSettings.LoadDefaults;
FSettings.ApiKeyGemini := LApiKeyGemini;
FSettings.ApiKeyOpenAI := LApiKeyOpenAI;
FSettings.ApiKeyGroq := LApiKeyGroq;
+ FSettings.ApiKeyMistral := LApiKeyMistral;
+ FSettings.ApiKeyOllama := LApiKeyOllama;
Self.LoadSettings;
end;
procedure TDelphiAIDevSettingsView.btnConfirmClick(Sender: TObject);
begin
+ Self.ValidateCodeCompletionShortcutInvoke;
+
Self.SaveSettings;
Self.Close;
Self.ModalResult := mrOk;
end;
+procedure TDelphiAIDevSettingsView.ValidateCodeCompletionShortcutInvoke;
+var
+ LShortcutStr: string;
+ LShortCut: TShortCut;
+begin
+ LShortcutStr := Trim(edtCodeCompletionShortcutInvoke.Text);
+ if LShortcutStr.Length = 1 then
+ raise Exception.Create('Invalid CodeCompletion shortcut');
+
+ LShortCut := TextToShortCut(LShortcutStr);
+
+ if ShortCutToText(LShortCut).Trim.IsEmpty then
+ edtCodeCompletionShortcutInvoke.Text := TConsts.CODE_COMPLETION_SHORTCUT_INVOKE;
+end;
+
+procedure TDelphiAIDevSettingsView.ckCodeCompletionSuggestionColorUseClick(Sender: TObject);
+begin
+ Self.ConfigFieldsCodeCompletionSuggestionColor;
+end;
+
+procedure TDelphiAIDevSettingsView.ConfigFieldsCodeCompletionSuggestionColor;
+begin
+ ColorBoxCodeCompletionSuggestionColor.Enabled := ckCodeCompletionSuggestionColorUse.Checked;
+end;
+
procedure TDelphiAIDevSettingsView.ckColorHighlightCodeDelphiUseClick(Sender: TObject);
begin
Self.ConfigFieldsColorHighlightDelphi;
@@ -245,27 +372,61 @@ procedure TDelphiAIDevSettingsView.LoadSettings;
ckColorHighlightCodeDelphiUse.Checked := FSettings.ColorHighlightCodeDelphiUse;
ColorBoxColorHighlightCodeDelphi.Selected := FSettings.ColorHighlightCodeDelphi;
Self.ConfigFieldsColorHighlightDelphi;
+ mmDefaultPrompt.Lines.Text := FSettings.DefaultPrompt;
+
+ ckCodeCompletionUse.Checked := FSettings.CodeCompletionUse;
+ cBoxCodeCompletionAIDefault.ItemIndex := Integer(FSettings.CodeCompletionAIDefault);
+ ckCodeCompletionSuggestionColorUse.Checked := FSettings.CodeCompletionSuggestionColorUse;
+ ColorBoxCodeCompletionSuggestionColor.Selected := FSettings.CodeCompletionSuggestionColor;
+ edtCodeCompletionShortcutInvoke.Text := FSettings.CodeCompletionShortcutInvoke;
+ mmCodeCompletionDefaultPrompt.Lines.Text := FSettings.CodeCompletionDefaultPrompt;
edtBaseUrlGemini.Text := FSettings.BaseUrlGemini;
cBoxModelGemini.ItemIndex := cBoxModelGemini.Items.IndexOf(FSettings.ModelGemini);
+ if cBoxModelGemini.ItemIndex < 0 then
+ cBoxModelGemini.Text := FSettings.ModelGemini;
edtApiKeyGemini.Text := FSettings.ApiKeyGemini;
edtBaseUrlOpenAI.Text := FSettings.BaseUrlOpenAI;
cBoxModelOpenAI.ItemIndex := cBoxModelOpenAI.Items.IndexOf(FSettings.ModelOpenAI);
+ if cBoxModelOpenAI.ItemIndex < 0 then
+ cBoxModelOpenAI.Text := FSettings.ModelOpenAI;
edtApiKeyOpenAI.Text := FSettings.ApiKeyOpenAI;
edtBaseUrlGroq.Text := FSettings.BaseUrlGroq;
cBoxModelGroq.ItemIndex := cBoxModelGroq.Items.IndexOf(FSettings.ModelGroq);
+ if cBoxModelGroq.ItemIndex < 0 then
+ cBoxModelGroq.Text := FSettings.ModelGroq;
edtApiKeyGroq.Text := FSettings.ApiKeyGroq;
+
+ edtBaseUrlMistral.Text := FSettings.BaseUrlMistral;
+ cBoxModelMistral.ItemIndex := cBoxModelMistral.Items.IndexOf(FSettings.ModelMistral);
+ if cBoxModelMistral.ItemIndex < 0 then
+ cBoxModelMistral.Text := FSettings.ModelMistral;
+ edtApiKeyMistral.Text := FSettings.ApiKeyMistral;
+
+ edtBaseUrlOllama.Text := FSettings.BaseUrlOllama;
+ cBoxModelOllama.ItemIndex := cBoxModelOllama.Items.IndexOf(FSettings.ModelOllama);
+ if cBoxModelOllama.ItemIndex < 0 then
+ cBoxModelOllama.Text := FSettings.ModelOllama;
+ edtApiKeyOllama.Text := FSettings.ApiKeyOllama;
end;
procedure TDelphiAIDevSettingsView.SaveSettings;
begin
FSettings.LanguageQuestions := TC4DLanguage(cBoxLanguageQuestions.ItemIndex);
- FSettings.AIDefault := TC4DAIsAvailable(cBoxAIDefault.ItemIndex);
+ FSettings.AIDefault := TC4DAiAvailable(cBoxAIDefault.ItemIndex);
FSettings.ColorHighlightCodeDelphiUse := ckColorHighlightCodeDelphiUse.Checked;
FSettings.ColorHighlightCodeDelphi := ColorBoxColorHighlightCodeDelphi.Selected;
+ FSettings.DefaultPrompt := mmDefaultPrompt.Lines.Text;
+
+ FSettings.CodeCompletionUse := ckCodeCompletionUse.Checked;
+ FSettings.CodeCompletionAIDefault := TC4DAiAvailable(cBoxCodeCompletionAIDefault.ItemIndex);
+ FSettings.CodeCompletionSuggestionColorUse := ckCodeCompletionSuggestionColorUse.Checked;
+ FSettings.CodeCompletionSuggestionColor := ColorBoxCodeCompletionSuggestionColor.Selected;
+ FSettings.CodeCompletionShortcutInvoke := edtCodeCompletionShortcutInvoke.Text;
+ FSettings.CodeCompletionDefaultPrompt := mmCodeCompletionDefaultPrompt.Lines.Text;
FSettings.BaseUrlGemini := edtBaseUrlGemini.Text;
FSettings.ModelGemini := cBoxModelGemini.Text;
@@ -279,18 +440,82 @@ procedure TDelphiAIDevSettingsView.SaveSettings;
FSettings.ModelGroq := cBoxModelGroq.Text;
FSettings.ApiKeyGroq := edtApiKeyGroq.Text;
+ FSettings.BaseUrlMistral := edtBaseUrlMistral.Text;
+ FSettings.ModelMistral := cBoxModelMistral.Text;
+ FSettings.ApiKeyMistral := edtApiKeyMistral.Text;
+
+ FSettings.BaseUrlOllama := edtBaseUrlOllama.Text;
+ FSettings.ModelOllama := cBoxModelOllama.Text;
+ FSettings.ApiKeyOllama := edtApiKeyOllama.Text;
+
FSettings.SaveData;
end;
+procedure TDelphiAIDevSettingsView.btnApiKeyOllamaViewClick(Sender: TObject);
+begin
+ TUtils.TogglePasswordChar(edtApiKeyOllama);
+end;
+
+procedure TDelphiAIDevSettingsView.PanelsSetParent;
+begin
+ pnPreferencesBack.Visible := False;
+ pnIAsOnLineBack.Visible := False;
+ pnIAsOffLineBack.Visible := False;
+ pnCodeCompletionBack.Visible := False;
+
+ pnPreferencesBack.Parent := pnBody;
+ pnIAsOnLineBack.Parent := pnBody;
+ pnIAsOffLineBack.Parent := pnBody;
+ pnCodeCompletionBack.Parent := pnBody;
+ PageControl1.Visible := False;
+
+ btnPreferences.Click;
+end;
+
+procedure TDelphiAIDevSettingsView.btnPreferencesClick(Sender: TObject);
+begin
+ Self.ShowPanel(TButton(Sender), pnPreferencesBack);
+end;
+
+procedure TDelphiAIDevSettingsView.btnIAsOnlineClick(Sender: TObject);
+begin
+ Self.ShowPanel(TButton(Sender), pnIAsOnLineBack);
+end;
+
procedure TDelphiAIDevSettingsView.btnOpenDataFolderClick(Sender: TObject);
var
LPathFolder: string;
begin
LPathFolder := TUtils.GetPathFolderRoot;
- if(not DirectoryExists(LPathFolder))then
+ if not DirectoryExists(LPathFolder) then
TUtils.ShowMsg('Forder not found: ' + LPathFolder);
TUtils.OpenFolder(LPathFolder);
end;
+procedure TDelphiAIDevSettingsView.btnIAsOfflineClick(Sender: TObject);
+begin
+ Self.ShowPanel(TButton(Sender), pnIAsOffLineBack);
+end;
+
+procedure TDelphiAIDevSettingsView.btnCodeCompletionClick(Sender: TObject);
+begin
+ Self.ShowPanel(TButton(Sender), pnCodeCompletionBack);
+end;
+
+procedure TDelphiAIDevSettingsView.ShowPanel(const AButton: TButton; const APanel: TPanel);
+begin
+ btnPreferences.Default := False;
+ btnIAsOnline.Default := False;
+ btnIAsOffline.Default := False;
+ btnCodeCompletion.Default := False;
+ AButton.Default := True;
+
+ pnPreferencesBack.Visible := False;
+ pnIAsOnLineBack.Visible := False;
+ pnIAsOffLineBack.Visible := False;
+ pnCodeCompletionBack.Visible := False;
+ APanel.Visible := True;
+end;
+
end.
diff --git a/Src/Settings/DelphiAIDev.Settings.pas b/Src/Settings/DelphiAIDev.Settings.pas
index f5bc2c9..7b73466 100644
--- a/Src/Settings/DelphiAIDev.Settings.pas
+++ b/Src/Settings/DelphiAIDev.Settings.pas
@@ -15,10 +15,17 @@ interface
type
TDelphiAIDevSettings = class
private const
- FIELD_LanguageQuestions = 'LanguageQuestions';
+ FIELD_LanguageQuestions = 'LanguageQuestions';
FIELD_AIDefault = 'AIDefault';
FIELD_ColorHighlightCodeDelphiUse = 'ColorHighlightCodeDelphiUse';
- FIELD_ColorHighlightCodeDelphi = 'ColorHighlightCodeDelphi';
+ FIELD_ColorHighlightCodeDelphi = 'ColorHighlightCodeDelphi';
+ FIELD_DefaultPrompt = 'DefaultPrompt';
+ FIELD_CodeCompletionUse = 'CodeCompletionUse';
+ FIELD_CodeCompletionAIDefault = 'CodeCompletionAIDefault';
+ FIELD_CodeCompletionSuggestionColorUse = 'CodeCompletionSuggestionColorUse';
+ FIELD_CodeCompletionSuggestionColor = 'CodeCompletionSuggestionColor';
+ FIELD_CodeCompletionShortcutInvoke = 'CodeCompletionShortcutInvoke';
+ FIELD_CodeCompletionDefaultPrompt = 'CodeCompletionDefaultPrompt';
FIELD_BaseUrlGemini = 'BaseUrlGemini';
FIELD_ModelGemini = 'ModelGemini';
FIELD_ApiKeyGemini = 'ApiKeyGemini';
@@ -28,11 +35,25 @@ TDelphiAIDevSettings = class
FIELD_BaseUrlGroq = 'BaseUrlGroq';
FIELD_ModelGroq = 'ModelGroq';
FIELD_ApiKeyGroq = 'ApiKeyGroq';
+ FIELD_BaseUrlMistral = 'BaseUrlMistral';
+ FIELD_ModelMistral = 'ModelMistral';
+ FIELD_ApiKeyMistral = 'ApiKeyMistral';
+ FIELD_BaseUrlOllama = 'BaseUrlOllama';
+ FIELD_ModelOllama = 'ModelOllama';
+ FIELD_ApiKeyOllama = 'ApiKeyOllama';
private
FLanguageQuestions: TC4DLanguage;
- FAIDefault: TC4DAIsAvailable;
+ FAIDefault: TC4DAiAvailable;
FColorHighlightCodeDelphiUse: Boolean;
FColorHighlightCodeDelphi: TColor;
+ FDefaultPrompt: string;
+
+ FCodeCompletionUse: Boolean;
+ FCodeCompletionAIDefault: TC4DAiAvailable;
+ FCodeCompletionSuggestionColorUse: Boolean;
+ FCodeCompletionSuggestionColor: TColor;
+ FCodeCompletionShortcutInvoke: string;
+ FCodeCompletionDefaultPrompt: string;
FBaseUrlGemini: string;
FModelGemini: string;
@@ -45,17 +66,38 @@ TDelphiAIDevSettings = class
FBaseUrlGroq: string;
FModelGroq: string;
FApiKeyGroq: string;
+
+ FBaseUrlMistral: string;
+ FModelMistral: string;
+ FApiKeyMistral: string;
+
+ FBaseUrlOllama: string;
+ FModelOllama: string;
+ FApiKeyOllama: string;
+
constructor Create;
+ procedure ValidateFillingSelectedAIInternal(
+ const AShowMsg: TShowMsg; const AAiUse: TC4DAiAvailable);
public
class function GetInstance: TDelphiAIDevSettings;
procedure LoadDefaults;
procedure SaveData;
procedure LoadData;
+ procedure ValidateFillingSelectedAI(const AShowMsg: TShowMsg = TShowMsg.Yes);
+ procedure ValidateFillingSelectedAICodeCompletion(const AShowMsg: TShowMsg = TShowMsg.Yes);
property LanguageQuestions: TC4DLanguage read FLanguageQuestions write FLanguageQuestions;
- property AIDefault: TC4DAIsAvailable read FAIDefault write FAIDefault;
+ property AIDefault: TC4DAiAvailable read FAIDefault write FAIDefault;
property ColorHighlightCodeDelphiUse: Boolean read FColorHighlightCodeDelphiUse write FColorHighlightCodeDelphiUse;
property ColorHighlightCodeDelphi: TColor read FColorHighlightCodeDelphi write FColorHighlightCodeDelphi;
+ property DefaultPrompt: string read FDefaultPrompt write FDefaultPrompt;
+
+ property CodeCompletionUse: Boolean read FCodeCompletionUse write FCodeCompletionUse;
+ property CodeCompletionAIDefault: TC4DAiAvailable read FCodeCompletionAIDefault write FCodeCompletionAIDefault;
+ property CodeCompletionSuggestionColorUse: Boolean read FCodeCompletionSuggestionColorUse write FCodeCompletionSuggestionColorUse;
+ property CodeCompletionSuggestionColor: TColor read FCodeCompletionSuggestionColor write FCodeCompletionSuggestionColor;
+ property CodeCompletionShortcutInvoke: string read FCodeCompletionShortcutInvoke write FCodeCompletionShortcutInvoke;
+ property CodeCompletionDefaultPrompt: string read FCodeCompletionDefaultPrompt write FCodeCompletionDefaultPrompt;
property BaseUrlGemini: string read FBaseUrlGemini write FBaseUrlGemini;
property ModelGemini: string read FModelGemini write FModelGemini;
@@ -68,6 +110,14 @@ TDelphiAIDevSettings = class
property BaseUrlGroq: string read FBaseUrlGroq write FBaseUrlGroq;
property ModelGroq: string read FModelGroq write FModelGroq;
property ApiKeyGroq: string read FApiKeyGroq write FApiKeyGroq;
+
+ property BaseUrlMistral: string read FBaseUrlMistral write FBaseUrlMistral;
+ property ModelMistral: string read FModelMistral write FModelMistral;
+ property ApiKeyMistral: string read FApiKeyMistral write FApiKeyMistral;
+
+ property BaseUrlOllama: string read FBaseUrlOllama write FBaseUrlOllama;
+ property ModelOllama: string read FModelOllama write FModelOllama;
+ property ApiKeyOllama: string read FApiKeyOllama write FApiKeyOllama;
end;
implementation
@@ -90,22 +140,38 @@ constructor TDelphiAIDevSettings.Create;
procedure TDelphiAIDevSettings.LoadDefaults;
begin
FLanguageQuestions := TC4DLanguage.ptBR;
- FAIDefault := TC4DAIsAvailable.Groq;
+ FAIDefault := TC4DAiAvailable.Groq;
FColorHighlightCodeDelphiUse := False;
FColorHighlightCodeDelphi := clNone;
+ FDefaultPrompt := '';
+
+ FCodeCompletionUse := False;
+ FCodeCompletionAIDefault := TC4DAiAvailable.Gemini;
+ FCodeCompletionSuggestionColorUse := False;
+ FCodeCompletionSuggestionColor := TConsts.CODE_COMPLETION_SUGGESTION_COLOR;
+ FCodeCompletionShortcutInvoke := TConsts.CODE_COMPLETION_SHORTCUT_INVOKE;
+ FCodeCompletionDefaultPrompt := '';
FBaseUrlGemini := TConsts.BASE_URL_GEMINI_DEFAULT;
FModelGemini := TConsts.MODEL_GEMINI_DEFAULT;
FApiKeyGemini := '';
FBaseUrlOpenAI := TConsts.BASE_URL_OPEN_AI;
- FModelOpenAI := 'gpt-3.5-turbo';
+ FModelOpenAI := TConsts.MODEL_OPEN_AI_DEFAULT;
FApiKeyOpenAI := '';
FBaseUrlGroq := TConsts.BASE_URL_GROQ;
- FModelGroq := 'llama3-8b-8192';
+ FModelGroq := TConsts.MODEL_GROQ_DEFAULT;
FApiKeyGroq := '';
+
+ FBaseUrlMistral := TConsts.BASE_URL_Mistral;
+ FModelMistral := TConsts.MODEL_Mistral_DEFAULT;
+ FApiKeyMistral := '';
+
+ FBaseUrlOllama := TConsts.BASE_URL_OLLAMA;
+ FModelOllama := TConsts.MODEL_OLLAMA_DEFAULT;
+ FApiKeyOllama := '';
end;
procedure TDelphiAIDevSettings.SaveData;
@@ -124,6 +190,14 @@ procedure TDelphiAIDevSettings.SaveData;
LReg.WriteBool(FIELD_ColorHighlightCodeDelphiUse, FColorHighlightCodeDelphiUse);
LReg.WriteString(FIELD_ColorHighlightCodeDelphi, ColorToString(FColorHighlightCodeDelphi));
+ LReg.WriteString(FIELD_DefaultPrompt, FDefaultPrompt);
+
+ LReg.WriteBool(FIELD_CodeCompletionUse, FCodeCompletionUse);
+ LReg.WriteInteger(FIELD_CodeCompletionAIDefault, Integer(FCodeCompletionAIDefault));
+ LReg.WriteBool(FIELD_CodeCompletionSuggestionColorUse, FCodeCompletionSuggestionColorUse);
+ LReg.WriteString(FIELD_CodeCompletionSuggestionColor, ColorToString(FCodeCompletionSuggestionColor));
+ LReg.WriteString(FIELD_CodeCompletionShortcutInvoke, FCodeCompletionShortcutInvoke);
+ LReg.WriteString(FIELD_CodeCompletionDefaultPrompt, FCodeCompletionDefaultPrompt);
LReg.WriteString(FIELD_BaseUrlGemini, FBaseUrlGemini);
LReg.WriteString(FIELD_ModelGemini, FModelGemini);
@@ -136,6 +210,14 @@ procedure TDelphiAIDevSettings.SaveData;
LReg.WriteString(FIELD_BaseUrlGroq, FBaseUrlGroq);
LReg.WriteString(FIELD_ModelGroq, FModelGroq);
LReg.WriteString(FIELD_ApiKeyGroq, FApiKeyGroq);
+
+ LReg.WriteString(FIELD_BaseUrlMistral, FBaseUrlMistral);
+ LReg.WriteString(FIELD_ModelMistral, FModelMistral);
+ LReg.WriteString(FIELD_ApiKeyMistral, FApiKeyMistral);
+
+ LReg.WriteString(FIELD_BaseUrlOllama, FBaseUrlOllama);
+ LReg.WriteString(FIELD_ModelOllama, FModelOllama);
+ LReg.WriteString(FIELD_ApiKeyOllama, FApiKeyOllama);
finally
LReg.Free;
end;
@@ -152,14 +234,14 @@ procedure TDelphiAIDevSettings.LoadData;
LReg.CloseKey;
LReg.RootKey := HKEY_CURRENT_USER;
- if not(LReg.OpenKey(TConsts.KEY_SETTINGS_IN_WINDOWS_REGISTRY, False)) then
+ if not LReg.OpenKey(TConsts.KEY_SETTINGS_IN_WINDOWS_REGISTRY, False) then
Exit;
if LReg.ValueExists(FIELD_LanguageQuestions) then
FLanguageQuestions := TC4DLanguage(LReg.ReadInteger(FIELD_LanguageQuestions));
if LReg.ValueExists(FIELD_AIDefault) then
- FAIDefault := TC4DAIsAvailable(LReg.ReadInteger(FIELD_AIDefault));
+ FAIDefault := TC4DAiAvailable(LReg.ReadInteger(FIELD_AIDefault));
//COLOR FOR HIGHLIGHT CODE DELPHI/PASCAL
if LReg.ValueExists(FIELD_ColorHighlightCodeDelphiUse) then
@@ -169,6 +251,29 @@ procedure TDelphiAIDevSettings.LoadData;
FColorHighlightCodeDelphi := TUtils.StringToColorDef(LReg.ReadString(FIELD_ColorHighlightCodeDelphi),
TUtilsOTA.ActiveThemeForCode);
+ if LReg.ValueExists(FIELD_DefaultPrompt) then
+ FDefaultPrompt := LReg.ReadString(FIELD_DefaultPrompt);
+
+ //Code Completion
+ if LReg.ValueExists(FIELD_CodeCompletionUse) then
+ FCodeCompletionUse := LReg.ReadBool(FIELD_CodeCompletionUse);
+
+ if LReg.ValueExists(FIELD_CodeCompletionAIDefault) then
+ FCodeCompletionAIDefault := TC4DAiAvailable(LReg.ReadInteger(FIELD_CodeCompletionAIDefault));
+
+ if LReg.ValueExists(FIELD_CodeCompletionSuggestionColorUse) then
+ FCodeCompletionSuggestionColorUse := LReg.ReadBool(FIELD_CodeCompletionSuggestionColorUse);
+
+ if LReg.ValueExists(FIELD_CodeCompletionSuggestionColor) then
+ FCodeCompletionSuggestionColor := TUtils.StringToColorDef(LReg.ReadString(FIELD_CodeCompletionSuggestionColor),
+ TUtilsOTA.ActiveThemeForCode);
+
+ if LReg.ValueExists(FIELD_CodeCompletionShortcutInvoke) then
+ FCodeCompletionShortcutInvoke := LReg.ReadString(FIELD_CodeCompletionShortcutInvoke);
+
+ if LReg.ValueExists(FIELD_CodeCompletionDefaultPrompt) then
+ FCodeCompletionDefaultPrompt := LReg.ReadString(FIELD_CodeCompletionDefaultPrompt);
+
//GEMINI
if LReg.ValueExists(FIELD_BaseUrlGemini) then
FBaseUrlGemini := LReg.ReadString(FIELD_BaseUrlGemini);
@@ -198,6 +303,26 @@ procedure TDelphiAIDevSettings.LoadData;
if LReg.ValueExists(FIELD_ApiKeyGroq) then
fApiKeyGroq := LReg.ReadString(FIELD_ApiKeyGroq);
+
+ //MISTRAL
+ if LReg.ValueExists(FIELD_BaseUrlMistral) then
+ fBaseUrlMistral := LReg.ReadString(FIELD_BaseUrlMistral);
+
+ if LReg.ValueExists(FIELD_ModelMistral) then
+ fModelMistral := LReg.ReadString(FIELD_ModelMistral);
+
+ if LReg.ValueExists(FIELD_ApiKeyMistral) then
+ fApiKeyMistral := LReg.ReadString(FIELD_ApiKeyMistral);
+
+ //OLLAMA
+ if LReg.ValueExists(FIELD_BaseUrlOllama) then
+ fBaseUrlOllama := LReg.ReadString(FIELD_BaseUrlOllama);
+
+ if LReg.ValueExists(FIELD_ModelOllama) then
+ fModelOllama := LReg.ReadString(FIELD_ModelOllama);
+
+ if LReg.ValueExists(FIELD_ApiKeyOllama) then
+ fApiKeyOllama := LReg.ReadString(FIELD_ApiKeyOllama);
except
Self.LoadDefaults;
end;
@@ -206,6 +331,85 @@ procedure TDelphiAIDevSettings.LoadData;
end;
end;
+procedure TDelphiAIDevSettings.ValidateFillingSelectedAI(const AShowMsg: TShowMsg = TShowMsg.Yes);
+begin
+ Self.ValidateFillingSelectedAIInternal(AShowMsg, FAIDefault);
+end;
+
+procedure TDelphiAIDevSettings.ValidateFillingSelectedAICodeCompletion(const AShowMsg: TShowMsg = TShowMsg.Yes);
+begin
+ Self.ValidateFillingSelectedAIInternal(AShowMsg, FCodeCompletionAIDefault);
+end;
+
+procedure TDelphiAIDevSettings.ValidateFillingSelectedAIInternal(
+ const AShowMsg: TShowMsg; const AAiUse: TC4DAiAvailable);
+const
+ MSG = '"%s" for IA %s not specified in settings.' + sLineBreak + sLineBreak +
+ 'Access menu > AI Developer > Settings';
+
+ procedure ShowMsgInternal(const AArgs: array of const);//(const AMsg: string);
+ begin
+ if AShowMsg = TShowMsg.Yes then
+ TUtils.ShowMsg(Format(MSG, AArgs));
+ Abort;
+ end;
+begin
+ case AAiUse of
+ TC4DAiAvailable.Gemini:
+ begin
+ if FBaseUrlGemini.Trim.IsEmpty then
+ ShowMsgInternal(['Base URL', 'Gemini']);
+
+ if FModelGemini.Trim.IsEmpty then
+ ShowMsgInternal(['Model', 'Gemini']);
+
+ if FApiKeyGemini.Trim.IsEmpty then
+ ShowMsgInternal(['API Key', 'Gemini']);
+ end;
+ TC4DAiAvailable.OpenAI:
+ begin
+ if FBaseUrlOpenAI.Trim.IsEmpty then
+ ShowMsgInternal(['Base URL', 'ChatGPT']);
+
+ if FModelOpenAI.Trim.IsEmpty then
+ ShowMsgInternal(['Model', 'ChatGPT']);
+
+ if FApiKeyOpenAI.Trim.IsEmpty then
+ ShowMsgInternal(['API Key', 'ChatGPT']);
+ end;
+ TC4DAiAvailable.Groq:
+ begin
+ if FBaseUrlGroq.Trim.IsEmpty then
+ ShowMsgInternal(['Base URL', 'Groq']);
+
+ if FModelGroq.Trim.IsEmpty then
+ ShowMsgInternal(['Model', 'Groq']);
+
+ if FApiKeyGroq.Trim.IsEmpty then
+ ShowMsgInternal(['API Key', 'Groq']);
+ end;
+ TC4DAiAvailable.Mistral:
+ begin
+ if FBaseUrlMistral.Trim.IsEmpty then
+ ShowMsgInternal(['Base URL', 'Mistral']);
+
+ if FModelMistral.Trim.IsEmpty then
+ ShowMsgInternal(['Model', 'Mistral']);
+
+ if FApiKeyMistral.Trim.IsEmpty then
+ ShowMsgInternal(['API Key', 'Mistral']);
+ end;
+ TC4DAiAvailable.Ollama:
+ begin
+ if FBaseUrlOllama.Trim.IsEmpty then
+ ShowMsgInternal(['Base URL', 'Ollama']);
+
+ if FModelOllama.Trim.IsEmpty then
+ ShowMsgInternal(['Model', 'Ollama']);
+ end;
+ end;
+end;
+
initialization
finalization
diff --git a/Src/Test/DelphiAIDev.Test.Client.pas b/Src/Test/DelphiAIDev.Test.Client.pas
new file mode 100644
index 0000000..5c67f6a
--- /dev/null
+++ b/Src/Test/DelphiAIDev.Test.Client.pas
@@ -0,0 +1,39 @@
+unit DelphiAIDev.Test.Client;
+
+interface
+
+type
+ TDelphiAIDevTestClient = class
+ private
+ FNome: string;
+ FCPF: string;
+ FEndereco: string;
+ FIdade: Integer;
+ public
+ constructor Create(ANome: string; ACpf: string; AEndereco: string);
+ property Nome: string read FNome write FNome;
+ property CPF: string read FCPF write FCPF;
+ property Endereco: string read FEndereco write FEndereco;
+ property Idade: Integer read FIdade write FIdade;
+ procedure LimparVariaveis;
+ end;
+
+implementation
+
+
+{ TDelphiAIDevTestClient }
+
+constructor TDelphiAIDevTestClient.Create(ANome, ACpf, AEndereco: string);
+begin
+
+end;
+
+procedure TDelphiAIDevTestClient.LimparVariaveis;
+begin
+ FNome := '';
+ FCPF := '';
+ FEndereco := '';
+ FIdade := 0;
+end;
+
+end.
diff --git a/Src/Test/DelphiAIDev.Test.pas b/Src/Test/DelphiAIDev.Test.pas
index 4fc715f..16205ab 100644
--- a/Src/Test/DelphiAIDev.Test.pas
+++ b/Src/Test/DelphiAIDev.Test.pas
@@ -5,9 +5,33 @@ interface
type
TDelphiAIDevTest = class
private
+ FNome: string;
+ FEndereco: string;
+ FBairro: string;
+ FNumero: Integer;
+ FTelefone: string;
+ FEmail: string;
+ FDataNascimento: TDateTime;
+ FApelido: string;
+ FCep: Integer;
public
- end;
+ property Nome: string read FNome write FNome;
+ property Endereco: string read FEndereco write FEndereco;
+ property Bairro: string read FBairro write FBairro;
+ property Numero: Integer read FNumero write FNumero;
+ property Telefone: string read FTelefone write FTelefone;
+ property Email: string read FEmail write FEmail;
+ property DataNascimento: TDateTime read FDataNascimento write FDataNascimento;
+ property Apelido: string read FApelido write FApelido;
+ property Cep: Integer read FCep write FCep;
+ procedure Clear;
+ end;
implementation
+procedure TDelphiAIDevTest.Clear;
+begin
+
+end;
+
end.
diff --git a/Src/Types/DelphiAIDev.Types.pas b/Src/Types/DelphiAIDev.Types.pas
index 7ea08fb..08a8b70 100644
--- a/Src/Types/DelphiAIDev.Types.pas
+++ b/Src/Types/DelphiAIDev.Types.pas
@@ -8,19 +8,24 @@ interface
System.TypInfo;
type
+ TC4DWizardMenuContextList = procedure(const MenuContextList: IInterfaceList) of object;
+
{$SCOPEDENUMS ON}
- TC4DAIsAvailable = (Gemini, OpenAI, Groq);
+ TC4DAiAvailable = (Gemini, OpenAI, Groq, Mistral, Ollama);
TC4DLanguage = (en, ptBR, es);
- TC4DExtensionsFiles = (None, PAS, DFM, FMX, DPR, DPK, DPROJ, ZIP, BMP, INI, ALL);
+ TC4DExtensionsFiles = (None, PAS, DFM, FMX, DPR, DPK, DPROJ, GROUPPROJ, ZIP, BMP, INI, ALL);
TC4DExtensionsOfFiles = set of TC4DExtensionsFiles;
- TC4DExtensionsCommon = (rtf);
+ TC4DExtensionsCommon = (rtf, csv, txt);
TC4DIcon = (Information, Question, Warning, Error, Success);
TC4DButtons = (OK, OK_Cancel);
TC4DBtnFocu = (OK, Cancel);
TC4DQuestionKind = (None, ItemMenuNormal, MenuMasterOnly, Separators);
+ TC4DDriverID = (None, MySQL, Firebird);
+ TAutoFreeField = (Yes, No);
+ TShowMsg = (Yes, No);
{$SCOPEDENUMS OFF}
- TC4DAIsAvailableHelper = record helper for TC4DAIsAvailable
+ TC4DAiAvailableHelper = record helper for TC4DAiAvailable
function ToString: string;
function ToStringWithCreator: string;
end;
@@ -29,6 +34,10 @@ TC4DLanguageHelper = record helper for TC4DLanguage
function ToString: string;
function GetLanguageDefinition: string;
function GetMsgCodeOnly: string;
+ function GetMsgSQLOnly: string;
+ function GetMsgJSONIsDatabaseStructure(ASGBDName: string): string;
+ function GetMsgJSONInformedAnswerQuestion: string;
+ function GetMsgCodeCompletionSuggestion: string;
end;
TC4DExtensionsFilesHelper = record helper for TC4DExtensionsFiles
@@ -49,33 +58,38 @@ TC4DQuestionKindHelper = record helper for TC4DQuestionKind
function ToString: string;
end;
+ TC4DDriverIDHelper = record helper for TC4DDriverID
+ function ToString: string;
+ function ToStringID: string;
+ end;
+
implementation
uses
DelphiAIDev.Consts;
{ TAIsAvailableHelper }
-function TC4DAIsAvailableHelper.ToString: string;
+function TC4DAiAvailableHelper.ToString: string;
begin
case Self of
- TC4DAIsAvailable.Gemini:
+ TC4DAiAvailable.Gemini:
Result := 'Gemini';
- TC4DAIsAvailable.OpenAI:
+ TC4DAiAvailable.OpenAI:
Result := 'ChatGPT';
else
- Result := GetEnumName(TypeInfo(TC4DAIsAvailable), Integer(Self));
+ Result := GetEnumName(TypeInfo(TC4DAiAvailable), Integer(Self));
end;
end;
-function TC4DAIsAvailableHelper.ToStringWithCreator: string;
+function TC4DAiAvailableHelper.ToStringWithCreator: string;
begin
case Self of
- TC4DAIsAvailable.Gemini:
+ TC4DAiAvailable.Gemini:
Result := 'Gemini (Google)';
- TC4DAIsAvailable.OpenAI:
+ TC4DAiAvailable.OpenAI:
Result := 'ChatGPT (OpenAI)';
else
- Result := GetEnumName(TypeInfo(TC4DAIsAvailable), Integer(Self));
+ Result := GetEnumName(TypeInfo(TC4DAiAvailable), Integer(Self));
end;
end;
@@ -107,13 +121,82 @@ function TC4DLanguageHelper.GetLanguageDefinition: string;
function TC4DLanguageHelper.GetMsgCodeOnly: string;
begin
- Result := 'Faa a seguinte ao sem adicionar comentrios:' + sLineBreak;
+ //Result := 'Faa a seguinte ao sem adicionar nenhum comentrios';
+ Result := 'Responda a pergunta sem adicionar nenhum comentrios, retorne apenas o cdigo fonte';
+ case Self of
+ TC4DLanguage.en:
+ Result := 'Perform the following action without adding comments:';
+ TC4DLanguage.es:
+ Result := 'Realice la siguiente accin sin agregar comentarios:';
+ end;
+
+ Result := Result + sLineBreak;
+end;
+
+function TC4DLanguageHelper.GetMsgSQLOnly: string;
+begin
+ Result := 'Faa a seguinte ao sem adicionar comentrios e retorne apenas os Comandos SQLs:';
+ case Self of
+ TC4DLanguage.en:
+ Result := 'Perform the following action without adding comments, returning only the SQL commands:';
+ TC4DLanguage.es:
+ Result := 'Realice la siguiente accin sin agregar comentarios, devolviendo solo comandos SQL:';
+ end;
+
+ Result := Result + sLineBreak;
+end;
+
+function TC4DLanguageHelper.GetMsgJSONIsDatabaseStructure(ASGBDName: string): string;
+begin
+ Result := 'O seguinte JSON se refere a estrutura SQL de um banco de dados ';
+ case Self of
+ TC4DLanguage.en:
+ Result := 'The following JSON refers to the SQL structure of a database ';
+ TC4DLanguage.es:
+ Result := 'El siguiente JSON hace referencia a la estructura SQL de una base de datos ';
+ end;
+
+ Result := Result + ASGBDName + ' ' + sLineBreak;
+end;
+
+function TC4DLanguageHelper.GetMsgJSONInformedAnswerQuestion: string;
+begin
+ Result := 'Com base nesta estrutura responda a seguinte pergunta e retorne o comando SQL correspondente:';
case Self of
TC4DLanguage.en:
- Result := 'Perform the following action without adding comments:' + sLineBreak;
+ Result := 'Based on the structure that was provided, answer the following question and return the corresponding SQL command:';
TC4DLanguage.es:
- Result := 'Realice la siguiente accin sin agregar comentarios:' + sLineBreak;
+ Result := 'Segn la estructura proporcionada, responda la siguiente pregunta y devuelva el comando SQL correspondiente:';
end;
+
+ Result := Result + sLineBreak;
+end;
+
+function TC4DLanguageHelper.GetMsgCodeCompletionSuggestion: string;
+begin
+ Result := 'Com base no seguinte cdigo delphi, de uma sugesto ' +
+ 'de cdigo para ser adicionado onde esta o comentrio %s ' + sLineBreak +
+ 'Importante: antes do implementation e dentro dos especificadores '+
+ 'private, protected, public, published deve-se adicionar apenas declaraes '+
+ 'e nunca se deve adicionar implementaes de cdigos delphi que contenham begin. ' + sLineBreak +
+ 'Nas sugestes, nunca repita um cdigo que j exista. ';
+ case Self of
+ TC4DLanguage.en:
+ Result := 'Based on the following Delphi code, give a suggestion of code to be added where the comment %s is ' + sLineBreak +
+ 'Important: before implementation and within the '+
+ 'private, protected, public, published specifiers, you should only add declarations '+
+ 'and never add Delphi code implementations that contain begin. '+ sLineBreak +
+ 'In suggestions, never repeat code that already exists. ';
+ TC4DLanguage.es:
+ Result := 'Basado en el siguiente cdigo Delphi, se agregar una sugerencia de cdigo donde est el comentario %s ' + sLineBreak +
+ 'Importante: antes de la implementacin y dentro de los especificadores '+
+ 'privados, protegidos, pblicos y publicados, solo se deben agregar declaraciones '+
+ 'y nunca se deben agregar implementaciones de cdigos Delphi que contienen begin. ' + sLineBreak +
+ 'En sugerencias, nunca repita cdigo que ya existe. ';
+ end;
+
+ Result := Format(Result, [TConsts.TAG_CODE_COMPLETION]);
+ Result := Result + sLineBreak;
end;
{ TC4DExtensionsFilesHelper }
@@ -134,30 +217,32 @@ function TC4DExtensionsOfFilesHelper.ContainsStr(const AExtension: string): Bool
begin
Result := False;
LExtension := AExtension.Trim.ToLower;
- if(LExtension = '.pas')then
+ if LExtension = TC4DExtensionsFiles.PAS.ToStringWithPoint then
Result := TC4DExtensionsFiles.PAS in Self
- else if(LExtension = '.dfm')then
+ else if LExtension = TC4DExtensionsFiles.DFM.ToStringWithPoint then
Result := TC4DExtensionsFiles.DFM in Self
- else if(LExtension = '.fmx')then
+ else if LExtension = TC4DExtensionsFiles.FMX.ToStringWithPoint then
Result := TC4DExtensionsFiles.FMX in Self
- else if(LExtension = '.dpr')then
+ else if LExtension = TC4DExtensionsFiles.DPR.ToStringWithPoint then
Result := TC4DExtensionsFiles.DPR in Self
- else if(LExtension = '.dpk')then
+ else if LExtension = TC4DExtensionsFiles.DPK.ToStringWithPoint then
Result := TC4DExtensionsFiles.DPK in Self
- else if(LExtension = '.dproj')then
+ else if LExtension = TC4DExtensionsFiles.DPROJ.ToStringWithPoint then
Result := TC4DExtensionsFiles.DPROJ in Self
- else if(LExtension = '.zip')then
+ else if LExtension = TC4DExtensionsFiles.GROUPPROJ.ToStringWithPoint then
+ Result := TC4DExtensionsFiles.GROUPPROJ in Self
+ else if LExtension =TC4DExtensionsFiles.ZIP.ToStringWithPoint then
Result := TC4DExtensionsFiles.ZIP in Self
- else if(LExtension = '.bmp')then
+ else if LExtension = TC4DExtensionsFiles.BMP.ToStringWithPoint then
Result := TC4DExtensionsFiles.BMP in Self
- else if(LExtension = '.ini')then
+ else if LExtension = TC4DExtensionsFiles.INI.ToStringWithPoint then
Result := TC4DExtensionsFiles.INI in Self;
end;
{ TC4DExtensionsCommonHelper }
function TC4DExtensionsCommonHelper.ToString: string;
begin
- Result := GetEnumName(TypeInfo(TC4DExtensionsFiles), Integer(Self)).ToLower;
+ Result := GetEnumName(TypeInfo(TC4DExtensionsCommon), Integer(Self)).ToLower;
end;
function TC4DExtensionsCommonHelper.ToStringWithPoint: string;
@@ -168,14 +253,29 @@ function TC4DExtensionsCommonHelper.ToStringWithPoint: string;
{ TC4DQuestionKindHelper }
function TC4DQuestionKindHelper.ToString: string;
begin
- if(Self = TC4DQuestionKind.ItemMenuNormal)then
+ if Self = TC4DQuestionKind.ItemMenuNormal then
Exit('Item menu normal')
- else if(Self = TC4DQuestionKind.MenuMasterOnly)then
+ else if Self = TC4DQuestionKind.MenuMasterOnly then
Exit('Menu master only')
- else if(Self = TC4DQuestionKind.Separators)then
+ else if Self = TC4DQuestionKind.Separators then
Exit('Separator')
else
Result := GetEnumName(TypeInfo(TC4DQuestionKind), Integer(Self));
end;
+{ TC4DDriverIDHelper }
+
+function TC4DDriverIDHelper.ToString: string;
+begin
+ Result := GetEnumName(TypeInfo(TC4DDriverID), Integer(Self));
+end;
+
+function TC4DDriverIDHelper.ToStringID: string;
+begin
+ if Self = TC4DDriverID.Firebird then
+ Exit('FB');
+
+ Result := GetEnumName(TypeInfo(TC4DDriverID), Integer(Self));
+end;
+
end.
diff --git a/Src/Utils/DelphiAIDev.Utils.ABMenuAction.pas b/Src/Utils/DelphiAIDev.Utils.ABMenuAction.pas
index 4e4a820..46f533a 100644
--- a/Src/Utils/DelphiAIDev.Utils.ABMenuAction.pas
+++ b/Src/Utils/DelphiAIDev.Utils.ABMenuAction.pas
@@ -28,23 +28,23 @@ implementation
function GetMenuItemOfSender(Sender: TObject): TMenuItem;
begin
Result := nil;
- if(Sender.ClassType.ClassName = TMenuItem.ClassName)then
+ if Sender.ClassType.ClassName = TMenuItem.ClassName then
Result := TMenuItem(Sender)
- else if(Sender.ClassType.ClassName = TABMenuAction.ClassName)then
+ else if Sender.ClassType.ClassName = TABMenuAction.ClassName then
Result := TABMenuAction(Sender).MenuItem
end;
{TABMenuAction}
destructor TABMenuAction.Destroy;
begin
- if(Assigned(FMenuItem))then
+ if Assigned(FMenuItem) then
FMenuItem.RemoveFreeNotification(Self);
inherited;
end;
procedure TABMenuAction.ExecuteTarget(Target: TObject);
begin
- if(Assigned(FMenuItem))then
+ if Assigned(FMenuItem) then
FMenuItem.Click;
end;
@@ -55,7 +55,7 @@ function TABMenuAction.HandlesTarget(Target: TObject): Boolean;
procedure TABMenuAction.Notification(AComponent: TComponent; Operation: TOperation);
begin
- if(Operation = opRemove) and (AComponent = FMenuItem)then
+ if (Operation = opRemove) and (AComponent = FMenuItem) then
FMenuItem := nil;
end;
diff --git a/Src/Utils/DelphiAIDev.Utils.Crypt.pas b/Src/Utils/DelphiAIDev.Utils.Crypt.pas
new file mode 100644
index 0000000..4efc1a4
--- /dev/null
+++ b/Src/Utils/DelphiAIDev.Utils.Crypt.pas
@@ -0,0 +1,43 @@
+unit DelphiAIDev.Utils.Crypt;
+
+interface
+
+uses
+ System.SysUtils;
+
+type
+ TUtilsCrypt = class
+ public
+ class function Decrypt(Value: string): string;
+ class function Encrypt(Value: string): string;
+ end;
+
+implementation
+
+const
+ SEQUENCE01 = '1234567890ABCDEFGHIJLMNOPQRSTUVXZWYKabcdefghijlmnopqrstuvxzwyk';
+ SEQUENCE02 = '1MTPkSXCgvRb23eQ0JzarhAE64FD95BpsYKqom7wVtUuHxiZdWcflLIjGnO8yN';
+
+class function TUtilsCrypt.Encrypt(Value: string): string;
+var
+ i: Integer;
+begin
+ for i := 1 to Length(Value)do
+ if Pos(Value[i], SEQUENCE01) <> 0 then
+ Value[i] := SEQUENCE02[Pos(Value[i], SEQUENCE01)];
+
+ Result := Value;
+end;
+
+class function TUtilsCrypt.Decrypt(Value: string): string;
+var
+ i: Integer;
+begin
+ for i := 1 to Length(Value) do
+ if Pos(Value[i], SEQUENCE02) <> 0 then
+ Value[i] := SEQUENCE01[Pos(Value[i], SEQUENCE02)];
+
+ Result := Value;
+end;
+
+end.
diff --git a/Src/Utils/DelphiAIDev.Utils.DBGrids.pas b/Src/Utils/DelphiAIDev.Utils.DBGrids.pas
new file mode 100644
index 0000000..d310562
--- /dev/null
+++ b/Src/Utils/DelphiAIDev.Utils.DBGrids.pas
@@ -0,0 +1,226 @@
+unit DelphiAIDev.Utils.DBGrids;
+
+interface
+
+uses
+ System.SysUtils,
+ System.Types,
+ System.Classes,
+ Data.DB,
+ Vcl.DBGrids,
+ Vcl.Grids,
+ Vcl.Graphics,
+ Vcl.Clipbrd,
+ DelphiAIDev.Utils,
+ DelphiAIDev.Utils.Ota,
+ DelphiAIDev.Types;
+
+type
+ TUtilsDBGrids = class
+ private
+ class procedure DrawColumnCellLight(const ADBGrid: TDBGrid; const ARect: TRect; const ADataCol: Integer; const AColumn: TColumn;
+ const AState: TGridDrawState);
+ class procedure DrawColumnCellDark(const ADBGrid: TDBGrid; const ARect: TRect; const ADataCol: Integer; const AColumn: TColumn;
+ const AState: TGridDrawState);
+ public
+ class procedure DBGridToClipboardCurrentColumn(const ADBGrid: TDBGrid);
+ class procedure DBGridToClipboardCurrentLine(ADBGrid: TDBGrid; ACopyTitle: Boolean = True);
+ class procedure DBGridToClipboardAll(ADBGrid: TDBGrid; ACopyTitle: Boolean = True);
+ class procedure DBGridToCSV(ADBGrid: TDBGrid; ACopyTitle: Boolean = True);
+ class procedure DBGridToTxt(ADBGrid: TDBGrid; ACopyTitle: Boolean = True);
+ class procedure DBGridToFile(ADBGrid: TDBGrid; const AExtension: string;
+ const ASeparator: string; ACopyTitle: Boolean = True);
+ class function DBGridToString(ADBGrid: TDBGrid; const AExtension: string;
+ ACopyTitle: Boolean = True): string;
+
+ class procedure ConfDBGrid(const ADBGrid: TDBGrid);
+ class procedure DrawColumnCell(const ADBGrid: TDBGrid; const ARect: TRect; const ADataCol: Integer; const AColumn: TColumn;
+ const AState: TGridDrawState);
+ end;
+
+implementation
+
+class procedure TUtilsDBGrids.DBGridToClipboardCurrentColumn(const ADBGrid: TDBGrid);
+var
+ LText: string;
+begin
+ if ADBGrid.DataSource.DataSet.IsEmpty then
+ Exit;
+
+ if ADBGrid.SelectedIndex < 0 then
+ Exit;
+
+ LText := ADBGrid.Columns[ADBGrid.SelectedIndex].Field.AsString;
+ ClipBoard.Clear;
+ ClipBoard.SetTextBuf(PWideChar(LText));
+end;
+
+class procedure TUtilsDBGrids.DBGridToClipboardCurrentLine(ADBGrid: TDBGrid; ACopyTitle: Boolean = True);
+var
+ LText: string;
+ LContCol: Integer;
+begin
+ if ADBGrid.DataSource.DataSet.IsEmpty then
+ Exit;
+
+ LText := '';
+ if ACopyTitle then
+ begin
+ LText := ADBGrid.Columns[0].Title.Caption;
+ for LContCol := 1 to Pred(ADBGrid.Columns.Count) do
+ LText := format('%s|%s', [LText, ADBGrid.Columns[LContCol].Title.Caption]);
+
+ LText := LText + sLineBreak;
+ end;
+
+ LText := LText + ADBGrid.Columns[0].Field.AsString;
+ for LContCol := 1 to Pred(ADBGrid.Columns.Count) do
+ LText := format('%s|%s', [LText, ADBGrid.Columns[LContCol].Field.AsString]);
+
+ LText := LText + sLineBreak;
+ ClipBoard.Clear;
+ ClipBoard.SetTextBuf(PWideChar(LText));
+end;
+
+class procedure TUtilsDBGrids.DBGridToClipboardAll(ADBGrid: TDBGrid; ACopyTitle: Boolean = True);
+var
+ LText: string;
+begin
+ LText := Self.DBGridToString(ADBGrid, ';', ACopyTitle);
+ ClipBoard.Clear;
+ ClipBoard.SetTextBuf(PWideChar(LText));
+end;
+
+class procedure TUtilsDBGrids.DBGridToCSV(ADBGrid: TDBGrid; ACopyTitle: Boolean = True);
+begin
+ Self.DBGridToFile(ADBGrid, TC4DExtensionsCommon.csv.ToString, ';', ACopyTitle);
+end;
+
+class procedure TUtilsDBGrids.DBGridToTxt(ADBGrid: TDBGrid; ACopyTitle: Boolean = True);
+begin
+ Self.DBGridToFile(ADBGrid, TC4DExtensionsCommon.txt.ToString, '|', ACopyTitle);
+end;
+
+class procedure TUtilsDBGrids.DBGridToFile(ADBGrid: TDBGrid; const AExtension: string;
+ const ASeparator: string; ACopyTitle: Boolean = True);
+var
+ LStrings: TStringList;
+ LFileName: string;
+begin
+ LFileName := TUtils.GetFileName(AExtension);
+
+ LStrings := TStringList.Create;
+ try
+ LStrings.Text := Self.DBGridToString(ADBGrid, ASeparator, ACopyTitle);
+ LStrings.SaveToFile(LFileName);
+ finally
+ LStrings.Free;
+ end;
+end;
+
+class function TUtilsDBGrids.DBGridToString(ADBGrid: TDBGrid; const AExtension: string;
+ ACopyTitle: Boolean = True): string;
+var
+ LContCol: Integer;
+ LBookMarkCurrent: TBookMark;
+begin
+ Result := '';
+ if ACopyTitle then
+ begin
+ Result := ADBGrid.Columns[0].Title.Caption;
+ for LContCol := 1 to Pred(ADBGrid.Columns.Count) do
+ Result := format('%s%s%s', [Result, AExtension, ADBGrid.Columns[LContCol].Title.Caption]);
+
+ Result := Result + sLineBreak;
+ end;
+
+ LBookMarkCurrent := ADBGrid.DataSource.DataSet.GetBookmark;
+ ADBGrid.DataSource.DataSet.DisableControls;
+ try
+ ADBGrid.DataSource.DataSet.First;
+ while not ADBGrid.DataSource.DataSet.Eof do
+ begin
+ Result := Result + ADBGrid.Columns[0].Field.AsString;
+ for LContCol := 1 to Pred(ADBGrid.Columns.Count) do
+ Result := format('%s%s%s', [Result, AExtension, ADBGrid.Columns[LContCol].Field.AsString]);
+ Result := Result + sLineBreak;
+ ADBGrid.DataSource.DataSet.Next;
+ end;
+
+ ADBGrid.DataSource.DataSet.GotoBookMark(LBookMarkCurrent);
+ ADBGrid.DataSource.DataSet.FreeBookMark(LBookMarkCurrent);
+ finally
+ ADBGrid.DataSource.DataSet.EnableControls;
+ end;
+end;
+
+class procedure TUtilsDBGrids.DrawColumnCell(const ADBGrid: TDBGrid; const ARect: TRect;
+ const ADataCol: Integer; const AColumn: TColumn; const AState: TGridDrawState);
+begin
+ if TUtilsOTA.ActiveThemeIsDark then
+ Self.DrawColumnCellDark(ADBGrid, ARect, ADataCol, AColumn, AState)
+ else
+ Self.DrawColumnCellLight(ADBGrid, ARect, ADataCol, AColumn, AState);
+end;
+
+class procedure TUtilsDBGrids.DrawColumnCellLight(const ADBGrid: TDBGrid; const ARect: TRect;
+ const ADataCol: Integer; const AColumn: TColumn; const AState: TGridDrawState);
+begin
+ ADBGrid.Canvas.Brush.Color := $00E6ECEC; //$00E6ECEC;
+ //EMULA dgRowSelect
+ if ARect.Top = TStringGrid(ADBGrid).CellRect(0, TStringGrid(ADBGrid).Row).Top then
+ begin
+ ADBGrid.Canvas.FillRect(ARect);
+ ADBGrid.Canvas.Brush.Color := $0056BBF9;
+ ADBGrid.Canvas.Font.Color := clWindowText;
+ ADBGrid.DefaultDrawDataCell(ARect, AColumn.Field, AState)
+ end
+ else if Odd(ADBGrid.DataSource.DataSet.RecNo) then
+ ADBGrid.Canvas.Brush.Color := clwhite;
+
+
+ ADBGrid.DefaultDrawColumnCell(ARect, ADataCol, AColumn, AState);
+end;
+
+class procedure TUtilsDBGrids.DrawColumnCellDark(const ADBGrid: TDBGrid; const ARect: TRect; const ADataCol: Integer; const AColumn: TColumn; const AState: TGridDrawState);
+begin
+ ADBGrid.Canvas.Brush.Color := $00322F2D; //$004A4136; //$00E6ECEC
+ ADBGrid.Canvas.Font.Color := clWindow;
+ //EMULA dgRowSelect
+ if ARect.Top = TStringGrid(ADBGrid).CellRect(0, TStringGrid(ADBGrid).Row).Top then
+ begin
+ ADBGrid.Canvas.FillRect(ARect);
+ ADBGrid.Canvas.Brush.Color := $00C08000; //$005B4224;
+ ADBGrid.Canvas.Font.Color := clWindowText;
+ ADBGrid.DefaultDrawDataCell(ARect, AColumn.Field, AState)
+ end
+ else if Odd(ADBGrid.DataSource.DataSet.RecNo) then
+ ADBGrid.Canvas.Brush.Color := $004A4132; //$00535353;
+
+ //ADBGrid.Canvas.FillRect(ARect);
+
+ ADBGrid.DefaultDrawColumnCell(ARect, ADataCol, AColumn, AState);
+end;
+
+class procedure TUtilsDBGrids.ConfDBGrid(const ADBGrid: TDBGrid);
+begin
+ ADBGrid.Options := ADBGrid.Options + [dgColumnResize];
+ ADBGrid.Options := ADBGrid.Options + [dgTitleClick];
+ ADBGrid.Options := ADBGrid.Options - [dgRowSelect];
+ ADBGrid.TitleFont.Style := ADBGrid.TitleFont.Style + [fsBold];
+ ADBGrid.TitleFont.Name := 'Arial';
+ ADBGrid.TitleFont.Color := clWindowText;
+ ADBGrid.DrawingStyle := TGridDrawingStyle.gdsThemed;
+
+ if TUtilsOTA.ActiveThemeIsDark then
+ begin
+ ADBGrid.TitleFont.Color := clWindow;
+ ADBGrid.DrawingStyle := TGridDrawingStyle.gdsGradient;
+ ADBGrid.GradientStartColor := $005C5143;
+ ADBGrid.GradientEndColor := $00342D25; //$00FFF1D5;
+
+ ADBGrid.Color := $00322F2D;
+ end;
+end;
+
+end.
diff --git a/Src/Utils/DelphiAIDev.Utils.GetIniPositionStr.pas b/Src/Utils/DelphiAIDev.Utils.GetIniPositionStr.pas
index 8b3bdc4..cc155cc 100644
--- a/Src/Utils/DelphiAIDev.Utils.GetIniPositionStr.pas
+++ b/Src/Utils/DelphiAIDev.Utils.GetIniPositionStr.pas
@@ -75,8 +75,8 @@ function TDelphiAIDevUtilsGetIniPositionStr.TextIgnore(Value: string): IDelphiAI
//ESTA ROTINA CONFERE DE A LETRA ANTERIOR/POSTERIOR A PALAVRA FECHA COM VAZIO OU NO LETRA NEM NUMERO
procedure TDelphiAIDevUtilsGetIniPositionStr.CheckWholeWord;
begin
- if((IfThen(FColCurrent = 0, '', Copy(FStrOriginal, FColCurrent - 1, 1)) <> '')and(Copy(FStrOriginal, FColCurrent - 1, 1)[1] in ['0'..'9', 'A'..'Z', 'a'..'z']))
- or((IfThen(FColCurrent = 0, '', Copy(FStrOriginal, FColCurrent + Length(FStrToLocate), 1)) <> '')and(Copy(FStrOriginal, FColCurrent + Length(FStrToLocate), 1)[1] in ['0'..'9', 'A'..'Z', 'a'..'z']))
+ if ((IfThen(FColCurrent = 0, '', Copy(FStrOriginal, FColCurrent - 1, 1)) <> '') and (Copy(FStrOriginal, FColCurrent - 1, 1)[1] in ['0'..'9', 'A'..'Z', 'a'..'z']))
+ or ((IfThen(FColCurrent = 0, '', Copy(FStrOriginal, FColCurrent + Length(FStrToLocate), 1)) <> '') and (Copy(FStrOriginal, FColCurrent + Length(FStrToLocate), 1)[1] in ['0'..'9', 'A'..'Z', 'a'..'z']))
then
FFound := False;
end;
@@ -89,13 +89,13 @@ function TDelphiAIDevUtilsGetIniPositionStr.GetWholeWord: string;
LChar: Char;
begin
Result := '';
- if(FStrToLocate = ' ')then
+ if FStrToLocate = ' ' then
Exit;
Result := FStrOriginal[FColCurrent];
LColIni := FColCurrent;
- if(LColIni > 0)then
+ if LColIni > 0 then
begin
Dec(LColIni);
LChar := FStrOriginal[LColIni];
@@ -109,7 +109,7 @@ function TDelphiAIDevUtilsGetIniPositionStr.GetWholeWord: string;
LColEnd := FColCurrent;
LLastColLine := FStrOriginal.Length;
- if(LColEnd < LLastColLine)then
+ if LColEnd < LLastColLine then
begin
Inc(LColEnd);
LChar := FStrOriginal[LColEnd];
@@ -127,21 +127,21 @@ procedure TDelphiAIDevUtilsGetIniPositionStr.CheckWordIgnore;
LStrValidate: string;
LStrIgnore: string;
begin
- if(FTextIgnore.Trim.IsEmpty)then
+ if FTextIgnore.Trim.IsEmpty then
Exit;
LStrValidate := Self.GetWholeWord;
- if(LStrValidate.Trim.IsEmpty)then
+ if LStrValidate.Trim.IsEmpty then
Exit;
LStrIgnore := FTextIgnore;
- if(not FCaseSensitive)then
+ if not FCaseSensitive then
begin
LStrValidate := LStrValidate.ToLower;
LStrIgnore := LStrIgnore.ToLower;
end;
- if(LStrValidate.Contains(LStrIgnore))then
+ if LStrValidate.Contains(LStrIgnore) then
FFound := False;
end;
@@ -157,21 +157,21 @@ function TDelphiAIDevUtilsGetIniPositionStr.GetInitialPosition(const AStrOrigina
begin
FColCurrent := LColCurrent;
- if(FCaseSensitive)then
+ if FCaseSensitive then
FFound := FStrToLocate = Copy(FStrOriginal, FColCurrent, Length(FStrToLocate))
else
FFound := AnsiUpperCase(FStrToLocate) = AnsiUpperCase(Copy(FStrOriginal, FColCurrent, Length(FStrToLocate)));
- if(FFound)and(FWholeWordOnly)then
+ if (FFound) and (FWholeWordOnly) then
Self.CheckWholeWord;
- if(FFound)then
+ if FFound then
Self.CheckWordIgnore;
- if(FFound)then
+ if FFound then
begin
Result := FColCurrent - 1;
- if(Result < 0)then
+ if Result < 0 then
Result := 0;
Break;
end;
diff --git a/Src/Utils/DelphiAIDev.Utils.ListView.pas b/Src/Utils/DelphiAIDev.Utils.ListView.pas
index 375e1b0..5ec432b 100644
--- a/Src/Utils/DelphiAIDev.Utils.ListView.pas
+++ b/Src/Utils/DelphiAIDev.Utils.ListView.pas
@@ -73,18 +73,18 @@ function IsValidDate(Astring: string; var ADateTime: TDateTime): Boolean;
function CompareDates(dt1, dt2: TDateTime): Integer;
begin
Result := -1;
- if(dt1 > dt2)then
+ if dt1 > dt2 then
Result := 1
- else if(dt1 = dt2)then
+ else if dt1 = dt2 then
Result := 0;
end;
function CompareNumeric(AInt1, AInt2: Integer): Integer;
begin
Result := -1;
- if(AInt1 > AInt2)then
+ if AInt1 > AInt2 then
Result := 1
- else if(AInt1 = AInt2)then
+ else if AInt1 = AInt2 then
Result := 0;
end;
{$ENDREGION}
@@ -101,11 +101,11 @@ procedure TDelphiAIDevUtilsListView.FindAndSelectItems(const AStrFind: string;
LStrSource: string;
LStrFind: string;
begin
- if(FListView.Items.Count <= 0)then
+ if FListView.Items.Count <= 0 then
Exit;
LStrFind := AStrFind.ToLower;
- if(LStrFind.Trim.IsEmpty)then
+ if LStrFind.Trim.IsEmpty then
Exit;
LUtilsGetIniPositionStr := TDelphiAIDevUtilsGetIniPositionStr.New
@@ -113,20 +113,20 @@ procedure TDelphiAIDevUtilsListView.FindAndSelectItems(const AStrFind: string;
.CaseSensitive(False);
LIndexCurrent := 0;
- if(FListView.Selected <> nil)then
+ if FListView.Selected <> nil then
LIndexCurrent := FListView.Selected.Index + 1;
for i := LIndexCurrent to Pred(FListView.Items.Count) do
begin
LListItem := FListView.Items[i];
- if(ANumColumn = 0)then
+ if ANumColumn = 0 then
LStrSource := LowerCase(LListItem.Caption)
- else if(ANumColumn > 0)then
+ else if ANumColumn > 0 then
LStrSource := LowerCase(LListItem.SubItems[Pred(ANumColumn)]);
LColIni := 0;
LColIni := LUtilsGetIniPositionStr.GetInitialPosition(LStrSource, LStrFind, LColIni);
- if(LColIni > -1)then
+ if LColIni > -1 then
begin
FListView.Selected := LListItem;
LListItem.MakeVisible(False);
@@ -134,9 +134,9 @@ procedure TDelphiAIDevUtilsListView.FindAndSelectItems(const AStrFind: string;
end;
end;
- if(AAutoRestart)then
+ if AAutoRestart then
begin
- if(FListView.Items.Count > 0)then
+ if FListView.Items.Count > 0 then
FListView.Items.Item[0].Selected := True;
Self.FindAndSelectItems(AStrFind, ANumColumn, False);
end;
@@ -147,19 +147,19 @@ procedure TDelphiAIDevUtilsListView.CopyIndexListView(const AIndexSubItem: Integ
LListItemSel: TListItem;
LStrCopy: string;
begin
- if(AIndexSubItem < -1)then
+ if AIndexSubItem < -1 then
Exit;
- if(FListView.Selected = nil)then
+ if FListView.Selected = nil then
Exit;
LListItemSel := FListView.Items[FListView.Selected.Index];
- if(AIndexSubItem = -1)then
+ if AIndexSubItem = -1 then
LStrCopy := LListItemSel.Caption
else
LStrCopy := LListItemSel.SubItems[AIndexSubItem];
- if(not LStrCopy.Trim.IsEmpty)then
+ if not LStrCopy.Trim.IsEmpty then
Clipboard.AsText := LStrCopy;
end;
@@ -171,41 +171,39 @@ function ListViewCustomSortProc(Item1, Item2: TListItem; SortColumn: Integer): I
LDhItem1, LDhItem2: TDateTime;
begin
Result := 0;
- if(Item1 = nil)or(Item2 = nil)then
+ if (Item1 = nil) or (Item2 = nil) then
Exit;
- case(SortColumn)of
+ case SortColumn of
-1: //COMPARE CAPTIONS
begin
LStrItem1 := Item1.Caption;
LStrItem2 := Item2.Caption;
end;
- else //COMPARE SUBITEMS
+ else //COMPARE SUBITEMS
LStrItem1 := '';
LStrItem2 := '';
//CHECK RANGE
- if(SortColumn < Item1.SubItems.Count)then
+ if SortColumn < Item1.SubItems.Count then
LStrItem1 := Item1.SubItems[SortColumn];
- if(SortColumn < Item2.SubItems.Count)then
+ if SortColumn < Item2.SubItems.Count then
LStrItem2 := Item2.SubItems[SortColumn]
end;
//SORT STYLES
- case(TDelphiAIDevUtilsListView.FSortStyle)of
+ case TDelphiAIDevUtilsListView.FSortStyle of
TDelphiAIDevUtilsListViewSortStyle.AlphaNum:
- begin
Result := lstrcmp(PChar(LStrItem1), PChar(LStrItem2));
- end;
TDelphiAIDevUtilsListViewSortStyle.Numeric:
begin
LValidItem1 := IsValidNumber(LStrItem1, LIntItem1);
LValidItem2 := IsValidNumber(LStrItem2, LIntItem2);
Result := ord(LValidItem1 or LValidItem2);
- if(Result <> 0)then
+ if Result <> 0 then
begin
- if(LIntItem1 = 0)then
+ if LIntItem1 = 0 then
LIntItem1 := 99999999;
- if(LIntItem2 = 0)then
+ if LIntItem2 = 0 then
LIntItem2 := 99999999;
Result := CompareNumeric(LIntItem2, LIntItem1);
end;
@@ -215,13 +213,13 @@ function ListViewCustomSortProc(Item1, Item2: TListItem; SortColumn: Integer): I
LValidItem1 := IsValidDate(LStrItem1, LDhItem1);
LValidItem2 := IsValidDate(LStrItem2, LDhItem2);
Result := ord(LValidItem1 or LValidItem2);
- if(Result <> 0)then
+ if Result <> 0 then
Result := CompareDates(LDhItem1, LDhItem2);
end;
end;
//SORT DIRECTION
- if(not TDelphiAIDevUtilsListView.FSortOrder[SortColumn + 1])then
+ if not TDelphiAIDevUtilsListView.FSortOrder[SortColumn + 1] then
Result := - Result;
end;
@@ -262,7 +260,7 @@ function TDelphiAIDevUtilsListView.ColumnIndex(const AColumnIndex: Integer): IDe
procedure TDelphiAIDevUtilsListView.CustomSort;
begin
- if(FInvertOrder)then
+ if FInvertOrder then
FSortOrder[FColumnIndex] := not FSortOrder[FColumnIndex];
FListView.CustomSort(@ListViewCustomSortProc, FColumnIndex -1);
end;
diff --git a/Src/Utils/DelphiAIDev.Utils.OTA.pas b/Src/Utils/DelphiAIDev.Utils.OTA.pas
index 11f4cce..68ebe78 100644
--- a/Src/Utils/DelphiAIDev.Utils.OTA.pas
+++ b/Src/Utils/DelphiAIDev.Utils.OTA.pas
@@ -18,6 +18,8 @@ interface
TUtilsOTA = class
private
public
+ class procedure GetCursorPosition(var ALine, AColumn: Integer);
+ class procedure GetCursorPositionPixel(var AX, AY: Integer);
class function CurrentProjectIsDelphiAIDeveloperDPROJ: Boolean;
class function CurrentModuleIsReadOnly: Boolean;
class procedure SaveAllModifiedModules;
@@ -40,7 +42,7 @@ TUtilsOTA = class
class function ActiveThemeForCode: TColor;
class function ActiveThemeIsDark: Boolean;
class function GetIOTAFormEditor(const AIOTAModule: IOTAModule): IOTAFormEditor;
- {$IF CompilerVersion >= 32.0} //Tokyo
+ {$IF CompilerVersion > 32.0} //Tokyo
class function GetIOTAIDEThemingServices: IOTAIDEThemingServices;
class function GetIOTAIDEThemingServices250: IOTAIDEThemingServices250;
{$ENDIF}
@@ -88,6 +90,95 @@ implementation
uses
DelphiAIDev.Utils;
+class procedure TUtilsOTA.GetCursorPosition(var ALine, AColumn: Integer);
+var
+ LOTAEditorServices: IOTAEditorServices;
+ LIOTAEditView: IOTAEditView;
+ LOTAEditPos: TOTAEditPos;
+ //LIOTAEditPosition: IOTAEditPosition;
+begin
+ ALine := 0;
+ AColumn := 0;
+
+ LOTAEditorServices := Self.GetIOTAEditorServices;
+ if not Assigned(LOTAEditorServices) then
+ Exit;
+
+ LIOTAEditView := LOTAEditorServices.TopView;
+ if Assigned(LIOTAEditView) then
+ begin
+ LOTAEditPos := LIOTAEditView.CursorPos;
+ ALine := LOTAEditPos.Line;
+ AColumn := LOTAEditPos.Col;
+
+ {LIOTAEditPosition := LIOTAEditView.Position;
+ if Assigned(LIOTAEditPosition) then
+ begin
+ ALine := LIOTAEditPosition.Row;
+ AColumn := LIOTAEditPosition.Column;
+ //TUtils.AddLog(Format('%d : %d', [ALine, AColumn]));
+ end;}
+ end;
+end;
+
+class procedure TUtilsOTA.GetCursorPositionPixel(var AX, AY: Integer);
+var
+ LIOTAEditorServices: IOTAEditorServices;
+ LIOTAEditView: IOTAEditView;
+ LIOTAEditPosition: IOTAEditPosition;
+ LLineHeight: Integer;
+ LCharWidth: Integer;
+ LEditorWindow: TCustomForm;
+ LHDC: HDC;
+ LCanvas: TCanvas;
+ LTextMetric: TTextMetric;
+begin
+ // Obtm a instncia do Editor Services
+ LIOTAEditorServices := BorlandIDEServices as IOTAEditorServices;
+
+ if Assigned(LIOTAEditorServices) then
+ begin
+ // Obtm a visualizao de edio ativa
+ LIOTAEditView := LIOTAEditorServices.TopView;
+ if Assigned(LIOTAEditView) then
+ begin
+ // Obtm a posio do cursor
+ LIOTAEditPosition := LIOTAEditView.Position;
+ if Assigned(LIOTAEditPosition) then
+ begin
+ // Obtm a janela do editor
+ LEditorWindow := LIOTAEditView.GetEditWindow.Form;
+
+ // Cria um DC (Device Context) para a janela do editor
+ LHDC := GetDC(LEditorWindow.Handle);
+ try
+ LCanvas := TCanvas.Create;
+ try
+ LCanvas.Handle := LHDC;
+
+ // Obtm as mtricas do texto (altura da linha e largura do caractere)
+ GetTextMetrics(LCanvas.Handle, LTextMetric);
+ LLineHeight := LTextMetric.tmHeight;
+ LCharWidth := LTextMetric.tmAveCharWidth;
+ finally
+ LCanvas.Free;
+ end;
+ finally
+ ReleaseDC(LEditorWindow.Handle, LHDC);
+ end;
+
+ // Calcula a posio em pixels
+ AX := (LIOTAEditPosition.Column - 1) * LCharWidth;
+ AY := (LIOTAEditPosition.Row - 1) * LLineHeight;
+
+ // Agora voc tem a posio do cursor em pixels
+ //ShowMessage(Format('Cursor est em X: %d, Y: %d pixels', [PixelX, PixelY]));
+ TUtils.AddLog(Format('Cursor est em X: %d, Y: %d pixels', [AX, AY]));
+ end;
+ end;
+ end;
+end;
+
class function TUtilsOTA.CurrentProjectIsDelphiAIDeveloperDPROJ: Boolean;
var
LIOTAProject: IOTAProject;
@@ -95,7 +186,7 @@ class function TUtilsOTA.CurrentProjectIsDelphiAIDeveloperDPROJ: Boolean;
Result := False;
LIOTAProject := Self.GetCurrentProject;
- if(LIOTAProject = nil)then
+ if LIOTAProject = nil then
Exit;
Result := TUtils.FileNameIsDelphiAIDeveloperDPROJ(LIOTAProject.FileName);
@@ -108,7 +199,7 @@ class function TUtilsOTA.CurrentModuleIsReadOnly: Boolean;
Result := False;
LIOTAEditBuffer := Self.GetIOTAEditBufferCurrentModule;
- if(LIOTAEditBuffer = nil)then
+ if LIOTAEditBuffer = nil then
Exit;
Result := LIOTAEditBuffer.IsReadOnly;
@@ -140,7 +231,7 @@ class function TUtilsOTA.AddImgIDEResourceName(AResourceName: string): Integer;
LMaskColor: TColor;
begin
Result := -1;
- if(FindResource(hInstance, PChar(AResourceName), RT_BITMAP) <= 0)then
+ if FindResource(hInstance, PChar(AResourceName), RT_BITMAP) <= 0 then
Exit;
LBitmap := TBitmap.Create;
@@ -218,10 +309,7 @@ class function TUtilsOTA.EditorAsString(AIOTAModule: IOTAModule): string;
LOTASourceEditor := Self.GetIOTASourceEditor(AIOTAModule);
if LOTASourceEditor = nil then
- begin
- //TUtils.ShowMsgSynchronize('Unable to get SourceEditor.');
Exit;
- end;
LIOTAEditReader := LOTASourceEditor.CreateReader;
try
@@ -248,7 +336,7 @@ class procedure TUtilsOTA.DeleteBlockTextSelectedInEditor;
begin
LIOTAEditorServices := Self.GetIOTAEditorServices;
LIOTAEditView := LIOTAEditorServices.TopView;
- if(LIOTAEditView = nil)then
+ if LIOTAEditView = nil then
TUtils.ShowMsgAndAbort('No projects or files selected');
LIOTAEditBlock := LIOTAEditView.Block;
@@ -268,9 +356,9 @@ class procedure TUtilsOTA.InsertBlockTextIntoEditor(const AText: string);
var
LOTAEditorServices: IOTAEditorServices;
LIOTAEditView: IOTAEditView;
+ LOTAEditPos: TOTAEditPos;
LPosition: Longint;
LOTACharPos: TOTACharPos;
- LOTAEditPos: TOTAEditPos;
LIOTAEditWriter: IOTAEditWriter;
begin
LOTAEditorServices := Self.GetIOTAEditorServices;
@@ -295,7 +383,7 @@ class function TUtilsOTA.GetBlockTextSelect: string;
begin
Result := '';
LIOTAEditorServices := Self.GetIOTAEditorServices;
- if(LIOTAEditorServices.TopView <> nil)then
+ if LIOTAEditorServices.TopView <> nil then
Result := LIOTAEditorServices.TopView.GetBlock.Text;
end;
@@ -308,10 +396,10 @@ class function TUtilsOTA.GetSelectedBlockOrAllCodeUnit: string;
class procedure TUtilsOTA.OpenFilePathInIDE(AFilePath: string);
begin
- if(not FileExists(AFilePath))then
+ if not FileExists(AFilePath) then
Exit;
- if(TUtils.IsProject(AFilePath))then
+ if TUtils.IsProject(AFilePath) then
Self.GetIOTAActionServices.OpenProject(AFilePath, True)
else
Self.GetIOTAActionServices.OpenFile(AFilePath);
@@ -328,7 +416,7 @@ class function TUtilsOTA.RefreshProject: Boolean;
begin
Result := True;
LIOTAProject := GetCurrentProject;
- if(LIOTAProject = nil)then
+ if LIOTAProject = nil then
Exit(False);
LIOTAProject.Refresh(False);
end;
@@ -339,14 +427,14 @@ class function TUtilsOTA.RefreshModule: Boolean;
begin
Result := True;
LIOTAModule := GetCurrentModule;
- if(LIOTAModule = nil)then
+ if LIOTAModule = nil then
Exit(False);
LIOTAModule.Refresh(False);
end;
class procedure TUtilsOTA.RefreshProjectOrModule;
begin
- if(not Self.RefreshProject)then
+ if not Self.RefreshProject then
Self.RefreshModule;
end;
@@ -358,7 +446,7 @@ class function TUtilsOTA.FileIsOpenInIDE(const APathFile: string): Boolean;
i: Integer;
begin
Result := False;
- if(APathFile.Trim.IsEmpty)then
+ if APathFile.Trim.IsEmpty then
Exit;
LIOTAModuleServices := Self.GetIOTAModuleServices;
@@ -374,7 +462,7 @@ class function TUtilsOTA.FileIsOpenInIDE(const APathFile: string): Boolean;
Continue;
Result := SameFileName(APathFile, LIOTAModule.FileName);
- if(Result)then
+ if Result then
Exit;
end;
end;
@@ -384,27 +472,27 @@ class function TUtilsOTA.CheckIfExistFileInCurrentsProjectGroups(const ANameFile
LIOTAModuleServices: IOTAModuleServices;
LIOTAModuleCurrent: IOTAModule;
LOTAProjectGroup: IOTAProjectGroup;
- LIOTAProjectCurrent: IOTAProject;
LContModule: Integer;
+ LIOTAProjectCurrent: IOTAProject;
LContProject: Integer;
LContFile: Integer;
LFilePath: string;
begin
Result := False;
LIOTAModuleServices := Self.GetIOTAModuleServices;
- if(LIOTAModuleServices = nil)then
+ if LIOTAModuleServices = nil then
Exit;
- if(LIOTAModuleServices.ModuleCount = 0)then
+ if LIOTAModuleServices.ModuleCount = 0 then
Exit;
for LContModule := 0 to Pred(LIOTAModuleServices.ModuleCount) do
begin
LIOTAModuleCurrent := LIOTAModuleServices.Modules[LContModule];
- if(ExtractFileName(LIOTAModuleCurrent.FileName) = ANameFileWithExtension)then
+ if ExtractFileName(LIOTAModuleCurrent.FileName) = ANameFileWithExtension then
Exit(True);
- if(Supports(LIOTAModuleCurrent, IOTAProjectGroup, LOTAProjectGroup))then
+ if Supports(LIOTAModuleCurrent, IOTAProjectGroup, LOTAProjectGroup) then
begin
for LContProject := 0 to Pred(LOTAProjectGroup.ProjectCount) do
begin
@@ -412,10 +500,10 @@ class function TUtilsOTA.CheckIfExistFileInCurrentsProjectGroups(const ANameFile
for LContFile := 0 to Pred(LIOTAProjectCurrent.GetModuleCount) do
begin
LFilePath := LIOTAProjectCurrent.GetModule(LContFile).FileName;
- if(LFilePath.Trim.IsEmpty)then
+ if LFilePath.Trim.IsEmpty then
Continue;
- if(ExtractFileName(LFilePath) = ANameFileWithExtension)then
+ if ExtractFileName(LFilePath) = ANameFileWithExtension then
Exit(True);
end;
end;
@@ -424,7 +512,7 @@ class function TUtilsOTA.CheckIfExistFileInCurrentsProjectGroups(const ANameFile
end;
class procedure TUtilsOTA.IDEThemingAll(AFormClass: TCustomFormClass; AForm: TForm);
-{$IF CompilerVersion >= 32.0} //Tokyo
+{$IF CompilerVersion > 32.0} //Tokyo
var
i: Integer;
LIOTAIDEThemingServices250: IOTAIDEThemingServices250;
@@ -433,14 +521,14 @@ class procedure TUtilsOTA.IDEThemingAll(AFormClass: TCustomFormClass; AForm: TFo
AForm.Constraints.MinHeight := AForm.Height;
AForm.Constraints.MinWidth := AForm.Width;
- {$IF CompilerVersion >= 32.0}
+ {$IF CompilerVersion > 32.0}
LIOTAIDEThemingServices250 := Self.GetIOTAIDEThemingServices250;
LIOTAIDEThemingServices250.RegisterFormClass(AFormClass);
LIOTAIDEThemingServices250.ApplyTheme(AForm);
for i := 0 to Pred(AForm.ComponentCount) do
begin
- if(AForm.Components[i] is TPanel)then
+ if AForm.Components[i] is TPanel then
TPanel(AForm.Components[i]).ParentBackground := True;
LIOTAIDEThemingServices250.ApplyTheme(AForm.Components[i]);
@@ -467,7 +555,7 @@ class function TUtilsOTA.ActiveThemeIsDark: Boolean;
const
THEME_DARK = 'dark';
begin
- {$IF CompilerVersion >= 32.0} //Tokyo
+ {$IF CompilerVersion > 32.0} //Tokyo
Result := Self.GetIOTAIDEThemingServices.ActiveTheme.ToLower.Equals(THEME_DARK);
{$ELSE}
Result := False;
@@ -481,14 +569,14 @@ class function TUtilsOTA.GetIOTAFormEditor(const AIOTAModule: IOTAModule): IOTAF
LIOTAFormEditor: IOTAFormEditor;
begin
Result := nil;
- if(not Assigned(AIOTAModule))then
+ if not Assigned(AIOTAModule) then
Exit;
for i := 0 to Pred(AIOTAModule.GetModuleFileCount) do
begin
LIOTAEditor := AIOTAModule.GetModuleFileEditor(i);
- if(Supports(LIOTAEditor, IOTAFormEditor, LIOTAFormEditor))then
+ if Supports(LIOTAEditor, IOTAFormEditor, LIOTAFormEditor) then
begin
Result := LIOTAFormEditor;
Break;
@@ -496,29 +584,29 @@ class function TUtilsOTA.GetIOTAFormEditor(const AIOTAModule: IOTAModule): IOTAF
end;
end;
-{$IF CompilerVersion >= 32.0} //Tokyo
+{$IF CompilerVersion > 32.0} //Tokyo
class function TUtilsOTA.GetIOTAIDEThemingServices: IOTAIDEThemingServices;
begin
- if(not Supports(BorlandIDEServices, IOTAIDEThemingServices, Result))then
+ if not Supports(BorlandIDEServices, IOTAIDEThemingServices, Result) then
raise Exception.Create('Interface not supported: IOTAIDEThemingServices');
end;
class function TUtilsOTA.GetIOTAIDEThemingServices250: IOTAIDEThemingServices250;
begin
- if(not Supports(BorlandIDEServices, IOTAIDEThemingServices250, Result))then
+ if not Supports(BorlandIDEServices, IOTAIDEThemingServices250, Result) then
raise Exception.Create('Interface not supported: IOTAIDEThemingServices250');
end;
{$ENDIF}
class function TUtilsOTA.GetIOTACompileServices: IOTACompileServices;
begin
- if(not Supports(BorlandIDEServices, IOTACompileServices, Result))then
+ if not Supports(BorlandIDEServices, IOTACompileServices, Result) then
raise Exception.Create('Interface not supported: IOTACompileServices');
end;
class function TUtilsOTA.GetIOTAWizardServices: IOTAWizardServices;
begin
- if(not Supports(BorlandIDEServices, IOTAWizardServices, Result))then
+ if not Supports(BorlandIDEServices, IOTAWizardServices, Result) then
raise Exception.Create('Interface not supported: IOTAWizardServices');
end;
@@ -528,11 +616,11 @@ class function TUtilsOTA.GetIOTAEditView(AIOTAModule: IOTAModule): IOTAEditView;
LIOTAEditView: IOTAEditView;
begin
LIOTASourceEditor := Self.GetIOTASourceEditor(AIOTAModule);
- if(LIOTASourceEditor = nil)then
+ if LIOTASourceEditor = nil then
Exit;
LIOTAEditView := Self.GetIOTAEditView(LIOTASourceEditor);
- if(LIOTAEditView = nil)then
+ if LIOTAEditView = nil then
Exit;
//LIOTASourceEditor.Show;
Result := LIOTAEditView;
@@ -544,10 +632,10 @@ class function TUtilsOTA.GetIOTAEditView(AIOTASourceEditor: IOTASourceEditor): I
begin
Result := nil;
- if(not Supports(AIOTASourceEditor, IOTAEditBuffer, LIOTAEditBuffer))then
+ if not Supports(AIOTASourceEditor, IOTAEditBuffer, LIOTAEditBuffer) then
raise Exception.Create('Interface not supported: IOTAEditBuffer');
- if(LIOTAEditBuffer <> nil)then
+ if LIOTAEditBuffer <> nil then
Result := LIOTAEditBuffer.TopView
else if AIOTASourceEditor.EditViewCount > 0 then
Result := AIOTASourceEditor.EditViews[0];
@@ -562,7 +650,7 @@ class function TUtilsOTA.GetIOTASourceEditor(AIOTAModule: IOTAModule): IOTASourc
LIOTAModule := AIOTAModule;
for i := 0 to Pred(LIOTAModule.ModuleFileCount) do
begin
- if(LIOTAModule.ModuleFileEditors[i].QueryInterface(IOTASourceEditor, Result) = S_OK)then
+ if LIOTAModule.ModuleFileEditors[i].QueryInterface(IOTASourceEditor, Result) = S_OK then
Break;
end;
end;
@@ -570,7 +658,7 @@ class function TUtilsOTA.GetIOTASourceEditor(AIOTAModule: IOTAModule): IOTASourc
class function TUtilsOTA.GetIOTASourceEditor(AIOTAEditor: IOTAEditor): IOTASourceEditor;
begin
Result := nil;
- if(not Supports(AIOTAEditor, IOTASourceEditor, Result))then
+ if not Supports(AIOTAEditor, IOTASourceEditor, Result) then
raise Exception.Create('Interface not supported: IOTASourceEditor');
end;
@@ -595,9 +683,8 @@ class function TUtilsOTA.GetIOTASourceEditor(AIOTAModule: IOTAModule; const AFil
Result := nil;
end;
end;
-
begin
- if(not Assigned(AIOTAModule))then
+ if not Assigned(AIOTAModule) then
begin
Result := nil;
Exit;
@@ -606,11 +693,11 @@ class function TUtilsOTA.GetIOTASourceEditor(AIOTAModule: IOTAModule; const AFil
for i := 0 to Pred(AIOTAModule.GetModuleFileCount) do
begin
LIOTAEditor := GetFileEditorForModule(AIOTAModule, i);
- if(Supports(LIOTAEditor, IOTASourceEditor, LIOTASourceEditor))then
+ if Supports(LIOTAEditor, IOTASourceEditor, LIOTASourceEditor) then
begin
- if(Assigned(LIOTASourceEditor))then
+ if Assigned(LIOTASourceEditor) then
begin
- if(AFileName = '')or(SameFileName(LIOTASourceEditor.FileName, AFileName))then
+ if (AFileName = '') or (SameFileName(LIOTASourceEditor.FileName, AFileName)) then
begin
Result := LIOTASourceEditor;
Exit;
@@ -628,7 +715,7 @@ class function TUtilsOTA.GetIOTAEditBufferCurrentModule: IOTAEditBuffer;
Result := nil;
LIOTAModule := Self.GetCurrentModule;
- if(LIOTAModule = nil)then
+ if LIOTAModule = nil then
Exit;
Result := TUtilsOTA.GetIOTAEditBuffer(LIOTAModule);
@@ -640,58 +727,58 @@ class function TUtilsOTA.GetIOTAEditBuffer(AIOTAModule: IOTAModule): IOTAEditBuf
begin
Result := nil;
LIOTASourceEditor := Self.GetIOTASourceEditor(AIOTAModule);
- if(LIOTASourceEditor = nil)then
+ if LIOTASourceEditor = nil then
Exit;
- if(not Supports(LIOTASourceEditor, IOTAEditBuffer, Result))then
+ if not Supports(LIOTASourceEditor, IOTAEditBuffer, Result) then
raise Exception.Create('Interface not supported: IOTAEditBuffer');
end;
class function TUtilsOTA.GetIOTAMessageServices: IOTAMessageServices;
begin
- if(not Supports(BorlandIDEServices, IOTAMessageServices, Result))then
+ if not Supports(BorlandIDEServices, IOTAMessageServices, Result) then
raise Exception.Create('Interface not supported: IOTAMessageServices');
end;
class function TUtilsOTA.GetIOTAProjectManager: IOTAProjectManager;
begin
- if(not Supports(BorlandIDEServices, IOTAProjectManager, Result))then
+ if not Supports(BorlandIDEServices, IOTAProjectManager, Result) then
raise Exception.Create('Interface not supported: IOTAProjectManager');
end;
class function TUtilsOTA.GetIOTAKeyboardServices: IOTAKeyboardServices;
begin
- if(not Supports(BorlandIDEServices, IOTAKeyboardServices, Result))then
+ if not Supports(BorlandIDEServices, IOTAKeyboardServices, Result) then
raise Exception.Create('Interface not supported: IOTAKeyboardServices');
end;
class function TUtilsOTA.GetIOTAServices: IOTAServices;
begin
- if(not Supports(BorlandIDEServices, IOTAServices, Result))then
+ if not Supports(BorlandIDEServices, IOTAServices, Result) then
raise Exception.Create('Interface not supported: IOTAServices');
end;
class function TUtilsOTA.GetIOTAActionServices: IOTAActionServices;
begin
- if(not Supports(BorlandIDEServices, IOTAActionServices, Result))then
+ if not Supports(BorlandIDEServices, IOTAActionServices, Result) then
raise Exception.Create('Interface not supported: IOTAActionServices');
end;
class function TUtilsOTA.GetINTAServices: INTAServices;
begin
- if(not Supports(BorlandIDEServices, INTAServices, Result))then
+ if not Supports(BorlandIDEServices, INTAServices, Result) then
raise Exception.Create('Interface not supported: INTAServices');
end;
class function TUtilsOTA.GetIOTAModuleServices: IOTAModuleServices;
begin
- if(not Supports(BorlandIDEServices, IOTAModuleServices, Result))then
+ if not Supports(BorlandIDEServices, IOTAModuleServices, Result) then
raise Exception.Create('Interface not supported: IOTAModuleServices');
end;
class function TUtilsOTA.GetIOTAEditorServices: IOTAEditorServices;
begin
- if(not Supports(BorlandIDEServices, IOTAEditorServices, Result))then
+ if not Supports(BorlandIDEServices, IOTAEditorServices, Result) then
raise Exception.Create('Interface not supported: IOTAEditorServices');
end;
@@ -701,7 +788,7 @@ class function TUtilsOTA.GetCurrentModule: IOTAModule;
begin
Result := nil;
LIOTAModuleServices := Self.GetIOTAModuleServices;
- if(LIOTAModuleServices <> nil)then
+ if LIOTAModuleServices <> nil then
Result := LIOTAModuleServices.CurrentModule;
end;
@@ -711,7 +798,7 @@ class function TUtilsOTA.GetCurrentModuleFileName: string;
begin
Result := '';
LIOTAModule := Self.GetCurrentModule;
- if(Assigned(LIOTAModule))then
+ if Assigned(LIOTAModule) then
Result := LIOTAModule.FileName.Trim;
end;
@@ -721,7 +808,7 @@ class function TUtilsOTA.GetModule(const AFileName: string): IOTAModule;
begin
Result := nil;
LIOTAModuleServices := Self.GetIOTAModuleServices;
- if(LIOTAModuleServices <> nil)then
+ if LIOTAModuleServices <> nil then
Result := LIOTAModuleServices.FindModule(AFileName);
end;
@@ -736,7 +823,7 @@ class function TUtilsOTA.GetCurrentProject: IOTAProject;
begin
Result := nil;
LIOTAProjectGroup := Self.GetCurrentProjectGroup;
- if(not Assigned(LIOTAProjectGroup))then
+ if not Assigned(LIOTAProjectGroup) then
Exit;
try
@@ -752,7 +839,7 @@ class function TUtilsOTA.GetCurrentProjectFileName: string;
begin
Result := '';
LIOTAProject := Self.GetCurrentProject;
- if(Assigned(LIOTAProject))then
+ if Assigned(LIOTAProject) then
Result := LIOTAProject.FileName.Trim;
end;
@@ -765,7 +852,7 @@ class function TUtilsOTA.GetProjectName(const AIOTAProject: IOTAProject): string
for i := 0 to Pred(AIOTAProject.ModuleFileCount) do
begin
LExt := LowerCase(ExtractFileExt(AIOTAProject.ModuleFileEditors[i].FileName));
- if(LExt = TC4DExtensionsFiles.DPR.ToString)or(LExt = TC4DExtensionsFiles.DPK.ToString) Then
+ if (LExt = TC4DExtensionsFiles.DPR.ToString) or (LExt = TC4DExtensionsFiles.DPK.ToString) Then
begin
Result := ChangeFileExt(Result, LExt);
Break;
@@ -788,7 +875,7 @@ class function TUtilsOTA.GetFileNameDprOrDpkIfDproj(const AIOTAModule: IOTAModul
LFileName := AIOTAModule.ModuleFileEditors[i].FileName;
LExt := ExtractFileExt(LFileName);
- if(LExt = TC4DExtensionsFiles.DPR.ToStringWithPoint)or(LExt = TC4DExtensionsFiles.DPK.ToStringWithPoint)then
+ if (LExt = TC4DExtensionsFiles.DPR.ToStringWithPoint) or (LExt = TC4DExtensionsFiles.DPK.ToStringWithPoint) then
Result := LFileName;
end;
end;
@@ -800,7 +887,7 @@ class function TUtilsOTA.GetCurrentProjectOptions: IOTAProjectOptions;
begin
Result := nil;
LIOTAProject := Self.GetCurrentProject;
- if(LIOTAProject = nil)then
+ if LIOTAProject = nil then
Exit;
Result := LIOTAProject.ProjectOptions;
@@ -811,7 +898,7 @@ class function TUtilsOTA.GetCurrentOutputDir: string;
LIOTAProjectOptions: IOTAProjectOptions;
begin
LIOTAProjectOptions := Self.GetCurrentProjectOptions;
- if(LIOTAProjectOptions = nil)then
+ if LIOTAProjectOptions = nil then
Exit;
Result := VarToStr(LIOTAProjectOptions.Values['OutputDir']);
@@ -822,8 +909,8 @@ class function TUtilsOTA.GetCurrentProjectOptionsConfigurations: IOTAProjectOpti
LIOTAProjectOptions: IOTAProjectOptions;
begin
LIOTAProjectOptions := Self.GetCurrentProjectOptions;
- if(LIOTAProjectOptions <> nil)then
- if(Supports(LIOTAProjectOptions, IOTAProjectOptionsConfigurations, Result))then
+ if LIOTAProjectOptions <> nil then
+ if Supports(LIOTAProjectOptions, IOTAProjectOptionsConfigurations, Result) then
Exit;
Result := nil;
@@ -861,19 +948,19 @@ class procedure TUtilsOTA.GetAllFilesFromProjectGroup(AListFiles: TStrings;
LFilterIsProject: Boolean;
begin
LIOTAModuleServices := Self.GetIOTAModuleServices;
- if(LIOTAModuleServices = nil)then
+ if LIOTAModuleServices = nil then
Exit;
- if(LIOTAModuleServices.ModuleCount = 0)then
+ if LIOTAModuleServices.ModuleCount = 0 then
Exit;
LFilterIsProjectGroup := False;
LFilterIsProject := False;
- if(not AFilePathProjectOrGroupForFilter.Trim.IsEmpty)then
+ if not AFilePathProjectOrGroupForFilter.Trim.IsEmpty then
begin
- if(TUtils.IsProjectGroup(AFilePathProjectOrGroupForFilter))then
+ if TUtils.IsProjectGroup(AFilePathProjectOrGroupForFilter) then
LFilterIsProjectGroup := True
- else if(TUtils.IsProject(AFilePathProjectOrGroupForFilter))
+ else if TUtils.IsProject(AFilePathProjectOrGroupForFilter)
or(TUtils.IsDPROJ(AFilePathProjectOrGroupForFilter))
then
LFilterIsProject := True;
@@ -883,25 +970,25 @@ class procedure TUtilsOTA.GetAllFilesFromProjectGroup(AListFiles: TStrings;
begin
LIOTAModuleCurrent := LIOTAModuleServices.Modules[LContModule];
LFilePath := LIOTAModuleCurrent.FileName;
- if(Supports(LIOTAModuleCurrent, IOTAProjectGroup, LOTAProjectGroup))then
+ if Supports(LIOTAModuleCurrent, IOTAProjectGroup, LOTAProjectGroup) then
begin
- if(LFilterIsProjectGroup)and(LFilePath <> AFilePathProjectOrGroupForFilter)then
+ if (LFilterIsProjectGroup) and (LFilePath <> AFilePathProjectOrGroupForFilter) then
Continue;
for LContProject := 0 to Pred(LOTAProjectGroup.ProjectCount) do
begin
LIOTAProjectCurrent := LOTAProjectGroup.Projects[LContProject];
- if(LFilterIsProject)and(LIOTAProjectCurrent.FileName <> AFilePathProjectOrGroupForFilter)then
+ if (LFilterIsProject) and (LIOTAProjectCurrent.FileName <> AFilePathProjectOrGroupForFilter) then
Continue;
for LContFile := 0 to Pred(LIOTAProjectCurrent.GetModuleCount) do
begin
LFilePath := LIOTAProjectCurrent.GetModule(LContFile).FileName;
- if(LFilePath.Trim.IsEmpty)then
+ if LFilePath.Trim.IsEmpty then
Continue;
- if(not AC4DExtensions.ContainsStr(ExtractFileExt(LFilePath)))then
+ if not AC4DExtensions.ContainsStr(ExtractFileExt(LFilePath)) then
Continue;
AListFiles.Add(LFilePath);
diff --git a/Src/Utils/DelphiAIDev.Utils.pas b/Src/Utils/DelphiAIDev.Utils.pas
index cb19999..68067a3 100644
--- a/Src/Utils/DelphiAIDev.Utils.pas
+++ b/Src/Utils/DelphiAIDev.Utils.pas
@@ -11,6 +11,8 @@ interface
System.StrUtils,
System.Classes,
System.TypInfo,
+ System.JSON,
+ System.Generics.Collections,
Vcl.Controls,
Vcl.Forms,
Vcl.Graphics,
@@ -29,9 +31,14 @@ TUtils = class
public
class function GetExceptionMessage(const E: Exception): string;
class function StrToDefaultsQuestionsKind(Value: string): TC4DQuestionKind;
+ class function StrToDriverID(Value: string): TC4DDriverID;
+ class procedure DriverIDFillItemsTStrings(AStrings: TStrings);
class procedure DefaultsQuestionsKindFillItemsTStrings(AStrings: TStrings);
class function AdjustQuestionToJson(const AValue: string): string;
+ class function DebugMyIsOn: Boolean;
class procedure AddLog(const AMessage: string);
+ class procedure AddLogDeleteFileFirst(const AMessage: string; const ANameFile: string);
+ class procedure AddLogInFileTxt(const AMessage: string; const ANameFile: string; ADeleteFileFirst: Boolean = False);
class function GetFileName(const AExtension: string): string;
class procedure MemoFocusOnTheEnd(const AMemo: TMemo);
class function IfThenColor(const Conditional: Boolean; const AColorTrue, AColorFalse: TColor): TColor;
@@ -78,8 +85,12 @@ TUtils = class
class function GetPathFolderRoot: string;
//class function GetPathFileIniGeneralSettings: string;
class function GetPathFileChat: string;
+ class function GetPathFileChatDB: string;
class function GetPathFileJSONDefaultsQuestions: string;
+ class function GetPathFileJSONDatabases: string;
+ class function GetPathFileJSONProjects: string;
class function CreateIfNecessaryAndGetPathFolderTemp: string;
+ class function GetPathFolderMetaInfo: string;
class function GetGuidStr: string;
class function GuidToFileName(const AGuid: string; const AExtension: string): string;
class function GetNamespace(AText: string): string;
@@ -137,16 +148,6 @@ implementation
DelphiAIDev.View.Dialog,
DelphiAIDev.WaitingScreen;
-//Winapi.WinInet
-//class function TUtils.TestInternetConnection: Boolean;
-//var
-// LFlags: DWord;
-//begin
-// Result := InternetGetConnectedState(@LFlags, 0);
-// if Result then
-// Result := InternetCheckConnection('http://google.com', 1, 0);
-//end;
-
class function TUtils.GetExceptionMessage(const E: Exception): string;
begin
Result := E.Message;
@@ -176,6 +177,26 @@ class procedure TUtils.DefaultsQuestionsKindFillItemsTStrings(AStrings: TStrings
AStrings.Add(LItem.ToString);
end;
+class function TUtils.StrToDriverID(Value: string): TC4DDriverID;
+begin
+ Result := TC4DDriverID.None;
+ if Value = TC4DDriverID.MySQL.ToString then
+ Result := TC4DDriverID.MySQL
+ else if Value = TC4DDriverID.Firebird.ToString then
+ Result := TC4DDriverID.Firebird
+end;
+
+class procedure TUtils.DriverIDFillItemsTStrings(AStrings: TStrings);
+var
+ LItem: TC4DDriverID;
+begin
+ if AStrings = nil then
+ Exit;
+
+ for LItem := Low(TC4DDriverID) to High(TC4DDriverID) do
+ AStrings.Add(LItem.ToString);
+end;
+
class function TUtils.AdjustQuestionToJson(const AValue: string): string;
begin
Result := AValue
@@ -185,32 +206,54 @@ class function TUtils.AdjustQuestionToJson(const AValue: string): string;
Result := Result.Replace('\\"', '\"', [rfReplaceAll, rfIgnoreCase]);
end;
+class function TUtils.DebugMyIsOn: Boolean;
+begin
+ Result := FileExists('C:\Temp\DelphiAIDev\DebugOn.c4d');
+end;
+
class procedure TUtils.AddLog(const AMessage: string);
+begin
+ Self.AddLogInFileTxt(AMessage, FormatDateTime('yyyy-mm-dd', Now));
+end;
+
+class procedure TUtils.AddLogDeleteFileFirst(const AMessage: string; const ANameFile: string);
+begin
+ Self.AddLogInFileTxt(AMessage, ANameFile, True);
+end;
+
+class procedure TUtils.AddLogInFileTxt(const AMessage: string; const ANameFile: string; ADeleteFileFirst: Boolean = False);
const
- DIRECTORY = 'C:\TempLog\DelphiAIDev\';
+ DIRECTORY = 'C:\Temp\DelphiAIDev\Logs\';
var
LFileName: string;
LTextFile: TextFile;
begin
try
- if not(DirectoryExists(DIRECTORY)) then
+ if not DirectoryExists(DIRECTORY) then
ForceDirectories(DIRECTORY);
- LFileName := DIRECTORY + FormatDateTime('yyyy-mm-dd', Now) + '.txt';
+ LFileName := DIRECTORY + ANameFile + '.txt';
+
+ if ADeleteFileFirst then
+ begin
+ if FileExists(LFileName)then
+ DeleteFile(LFileName);
+ end;
+
AssignFile(LTextFile, LFileName);
if not FileExists(LFileName)then
Rewrite(LTextFile);
Append(LTextFile);
- Writeln(LTextFile, AMessage);
+ Writeln(LTextFile, Format('%s: %s', [DateTimeToStr(Now), AMessage]));
CloseFile(LTextFile);
except
-// on E: Exception do
-// ShowMsg('Unable to generate log. Message: ' + E.Message + sLineBreak + 'Filename: ' + LFileName);
+ //on E: Exception do
+ // ShowMsg('Unable to generate log. Message: ' + E.Message + sLineBreak + 'Filename: ' + LFileName);
end;
end;
-class function TUtils.GetFileName(const AExtension: string): string;
+class function TUtils.GetFileName(const AExtension: string): string;
var
LFileName: string;
LSaveDialog: TSaveDialog;
@@ -310,8 +353,8 @@ class procedure TUtils.CenterPanel(const APanel: TPanel; const AWinControl: TWin
if AWinControl = nil then
Exit;
- LCenterX := AWinControl.Width div 2;
- LCenterY := AWinControl.Height div 2;
+ LCenterX := AWinControl.Left + (AWinControl.Width div 2);
+ LCenterY := AWinControl.Top + (AWinControl.Height div 2);
APanel.Left := LCenterX - (APanel.Width div 2);
APanel.Top := LCenterY - (APanel.Height div 2);
@@ -328,17 +371,43 @@ class procedure TUtils.TogglePasswordChar(const AEdit: TEdit);
class function TUtils.CodeIdMarkBeginCode(const AValue: string): Boolean;
begin
Result := (AValue.Trim = TConsts.MARK_BEGIN_DELPHI)
- or(AValue.Trim = TConsts.MARK_BEGIN_PASCAL);
+ or(AValue.Trim = TConsts.MARK_BEGIN_PASCAL)
+ or(AValue.Trim = TConsts.MARK_BEGIN_SQL);
//or(AValue.Trim = TConsts.MARK_BEGIN_PASCAL2);
end;
class function TUtils.ConfReturnAI(const AValue: string): string;
+var
+ LStrings: TStrings;
+ LStrLine: string;
+ i: Integer;
begin
Result := AValue.Trim
.Replace(TConsts.MARK_BEGIN_DELPHI, '', [rfReplaceAll, rfIgnoreCase])
.Replace(TConsts.MARK_BEGIN_PASCAL, '', [rfReplaceAll, rfIgnoreCase])
//.Replace(TConsts.MARK_BEGIN_PASCAL2, '', [rfReplaceAll, rfIgnoreCase])
+ .Replace(TConsts.MARK_BEGIN_SQL, '', [rfReplaceAll, rfIgnoreCase])
+ .Replace(TConsts.MARK_BEGIN_SQL2, '', [rfReplaceAll, rfIgnoreCase])
.Replace(TConsts.MARK_END, '', [rfReplaceAll, rfIgnoreCase]);
+
+ LStrings := TStringList.Create;
+ try
+ LStrings.Text := Result;
+
+ Result := '';
+ for i := 0 to Pred(LStrings.Count) do
+ begin
+ LStrLine := LStrings[i];
+ if (i = 0) and ((LStrLine.Trim.IsEmpty)or(LStrLine = sLineBreak)) then
+ Continue;
+
+ Result := Result + LStrLine + sLineBreak;
+ end;
+
+ Result := Result.TrimRight;
+ finally
+ LStrings.Free;
+ end;
end;
class function TUtils.ProcessTextForEditor(const AText: string): string;
@@ -399,7 +468,7 @@ class function TUtils.FileNameIsDelphiAIDeveloperDPROJ(const AFileName: string):
class procedure TUtils.RemoveBlankSpaceInBegin(var AValue: string; const ACount: Integer);
begin
- if(ACount <= 0)then
+ if ACount <= 0 then
Exit;
if Trim(copy(AValue, 1, ACount)).IsEmpty then
@@ -441,9 +510,9 @@ class procedure TUtils.ExplodeList(const AText, ASeparator: string; AStrings: TS
I := 1;
while(I <= LLengthText)do
begin
- if(Copy(LText, I, LLengthSeparator) = ASeparator)or(I = LLengthText)then
+ if (Copy(LText, I, LLengthSeparator) = ASeparator) or (I = LLengthText) then
begin
- if(I = LLengthText)then
+ if I = LLengthText then
LItem := LItem + StringReplace(LText[I], ASeparator, '', [rfReplaceAll, rfIgnoreCase]);
AStrings.Add(Trim(LItem));
@@ -466,7 +535,7 @@ class procedure TUtils.MemoVerticalCenter(AMemo: TMemo; ANumLines: Integer; ATex
AMemo.Lines.Text := AText.Trim;
LLinesCount := AMemo.Lines.Count;
AMemo.ScrollBars := System.UITypes.TScrollStyle.ssVertical;
- if(LLinesCount < ANumLines)then
+ if LLinesCount < ANumLines then
begin
AMemo.ScrollBars := System.UITypes.TScrollStyle.ssNone;
AMemo.Lines.Clear;
@@ -483,14 +552,14 @@ class function TUtils.StatusBarNumPanelDblClick(AStatusBar: TStatusBar): Integer
LNumPanel: Integer;
begin
LNumPanel := 0;
- if(not AStatusBar.SimplePanel)and(AStatusBar.Panels.Count > 0)then
+ if (not AStatusBar.SimplePanel) and (AStatusBar.Panels.Count > 0) then
begin
LPointMouse := AStatusBar.ScreenToClient(Mouse.CursorPos);
LWidth := 0;
for LNumPanel := 0 to AStatusBar.Panels.Count - 2 do
begin
LWidth := LWidth + AStatusBar.Panels[LNumPanel].Width;
- if(LPointMouse.X <= LWidth)then
+ if LPointMouse.X <= LWidth then
Break;
end;
end;
@@ -510,7 +579,7 @@ class function TUtils.StrToBoolC4D(Value: string): Boolean;
class function TUtils.RemoveCommentAfterTwoBars(Value: string): string;
begin
Result := Value;
- if(Result.Contains('//'))then
+ if Result.Contains('//') then
Result := Copy(Result, 1, (Pos('//', Result) - 1));
end;
@@ -518,12 +587,12 @@ class procedure TUtils.FindListVewItem(AListView: TListView; AIndexSubItem: Inte
var
I: Integer;
begin
- if(AStrFind.Trim.IsEmpty)then
+ if AStrFind.Trim.IsEmpty then
Exit;
for I := 0 to Pred(AListView.Items.Count)do
begin
- if(AListView.Items[I].SubItems[AIndexSubItem] = AStrFind)then
+ if AListView.Items[I].SubItems[AIndexSubItem] = AStrFind then
begin
AListView.ItemIndex := I;
AListView.SetFocus;
@@ -575,23 +644,23 @@ class function TUtils.SelectFile(const ADefaultFile: string; const ADefaultExt:
LOpenDialog := TOpenDialog.Create(nil);
try
LOpenDialog.Title := 'C4D - Select a file';
- if(not ADefaultFile.Trim.IsEmpty)then
+ if not ADefaultFile.Trim.IsEmpty then
begin
LFolder := ExtractFilePath(ADefaultFile);
- if(System.SysUtils.DirectoryExists(LFolder))then
+ if System.SysUtils.DirectoryExists(LFolder) then
LOpenDialog.InitialDir := LFolder;
- if(System.SysUtils.FileExists(ADefaultFile))then
+ if System.SysUtils.FileExists(ADefaultFile) then
LOpenDialog.FileName := ExtractFileName(ADefaultFile);
end;
- if(ADefaultExt <> TC4DExtensionsFiles.All)then
+ if ADefaultExt <> TC4DExtensionsFiles.All then
begin
LOpenDialog.DefaultExt := ADefaultExt.ToString;
LOpenDialog.Filter := Format('Arquivo %s|*.%s', [ADefaultExt.ToString.ToUpper, ADefaultExt.ToString]);
end;
- if(not LOpenDialog.Execute)then
+ if not LOpenDialog.Execute then
Exit(ADefaultFile);
Result := LOpenDialog.FileName;
finally
@@ -611,12 +680,12 @@ class function TUtils.SelectFolder(const ADefaultFolder: string; const ADefaultF
LFileOpenDialog.Title := 'Delphi AI Developer - Select a folder';
LFileOpenDialog.Options := [fdoPickFolders];
- if(not ADefaultFolder.Trim.IsEmpty)and(System.SysUtils.DirectoryExists(ADefaultFolder))then
+ if (not ADefaultFolder.Trim.IsEmpty) and (System.SysUtils.DirectoryExists(ADefaultFolder)) then
LFileOpenDialog.DefaultFolder := ADefaultFolder;
- if(not LFileOpenDialog.Execute)then
+ if not LFileOpenDialog.Execute then
begin
- if(ADefaultFolderIfCancel)then
+ if ADefaultFolderIfCancel then
Result := ADefaultFolder;
Exit;
end;
@@ -640,7 +709,7 @@ class function TUtils.StringToColorDef(AValue: string; AColorDefault: TColor = c
class function TUtils.DateTimeToStrEmpty(AValue: TDateTime): string;
begin
Result := '';
- if(AValue > 0)then
+ if AValue > 0 then
Result := DateTimeToStr(AValue);
end;
@@ -649,19 +718,19 @@ class function TUtils.DirectoryDelete(AFullPath: string): Boolean;
LSr: TSearchRec;
LFullName: string;
begin
- if(not System.SysUtils.DirectoryExists(AFullPath))then
+ if not System.SysUtils.DirectoryExists(AFullPath) then
Exit(False);
try
Result := True;
- if(FindFirst(AFullPath + '\*.*', faAnyFile, LSr) = 0)then
+ if FindFirst(AFullPath + '\*.*', faAnyFile, LSr) = 0 then
begin
try
repeat
LFullName := IncludeTrailingPathDelimiter(AFullPath) + LSr.Name;
- if(LSr.Name <> '.')and(LSr.Name <> '..')then
+ if (LSr.Name <> '.') and (LSr.Name <> '..') then
begin
- if((LSr.Attr and faDirectory) = 0)then
+ if ((LSr.Attr and faDirectory) = 0) then
Result := System.SysUtils.DeleteFile(LFullName)
else
Result := DirectoryDelete(LFullName);
@@ -681,7 +750,7 @@ class function TUtils.DirectoryOrFileMove(AFrom, ATo: string): Boolean;
begin
Result := False;
try
- if(MoveFile(PWideChar(AFrom), PWideChar(ATo)))then
+ if MoveFile(PWideChar(AFrom), PWideChar(ATo)) then
Result := True;
except
on E: Exception do
@@ -707,7 +776,7 @@ class procedure TUtils.OpenFile(AFilePath: string);
class procedure TUtils.OpenFileOrFolder(APath: string);
begin
- if(FileExists(APath))then
+ if FileExists(APath) then
Self.OpenFile(APath)
else
Self.OpenFolder(APath);
@@ -745,15 +814,37 @@ class function TUtils.GetPathFileChat: string;
Result := Self.GetPathFolderRoot + TConsts.FILE_RTF_CHAT;
end;
+class function TUtils.GetPathFileChatDB: string;
+begin
+ Result := Self.GetPathFolderRoot + TConsts.FILE_RTF_CHAT_DB;
+end;
+
class function TUtils.GetPathFileJSONDefaultsQuestions: string;
begin
Result := Self.GetPathFolderRoot + TConsts.FILE_JSON_DEFAULTS_QUESTIONS;
end;
+class function TUtils.GetPathFileJSONDatabases: string;
+begin
+ Result := Self.GetPathFolderRoot + TConsts.FILE_JSON_DATABASES;
+end;
+
+class function TUtils.GetPathFileJSONProjects: string;
+begin
+ Result := Self.GetPathFolderRoot + TConsts.FILE_JSON_PROJECTS;
+end;
+
class function TUtils.CreateIfNecessaryAndGetPathFolderTemp: string;
begin
Result := Self.GetPathFolderRoot + TConsts.NAME_FOLDER_TEMP;
- if(not DirectoryExists(Result))then
+ if not DirectoryExists(Result) then
+ ForceDirectories(Result);
+end;
+
+class function TUtils.GetPathFolderMetaInfo: string;
+begin
+ Result := IncludeTrailingPathDelimiter(Self.GetPathFolderRoot + TConsts.NAME_FOLDER_MetaInfo);
+ if not DirectoryExists(Result) then
ForceDirectories(Result);
end;
@@ -774,7 +865,7 @@ class function TUtils.GuidToFileName(const AGuid: string; const AExtension: stri
class function TUtils.GetNamespace(AText: string): string;
begin
Result := '';
- if(ContainsStr(AText, '.'))then
+ if ContainsStr(AText, '.') then
Result := Copy(AText, 1, Pos('.', AText));
end;
@@ -786,23 +877,23 @@ class function TUtils.GetTextBetween(AText, ADelimitador1, ADelimitador2: string
begin
Result := '';
LText := AText;
- if(ACaseSensitive)then
+ if ACaseSensitive then
LPosIni := Pos(ADelimitador1, LText)
else
LPosIni := Pos(AnsiUpperCase(ADelimitador1), AnsiUpperCase(LText));
- if(LPosIni > 0)then
+ if LPosIni > 0 then
LText := Copy(LText, LPosIni, Length(LText));
- if(ACaseSensitive)then
+ if ACaseSensitive then
LPosFim := Pos(ADelimitador2, LText)
else
LPosFim := Pos(AnsiUpperCase(ADelimitador2), AnsiUpperCase(LText));
- if(LPosFim > 0)then
+ if LPosFim > 0 then
LText := Copy(LText, 1, LPosFim + Length(ADelimitador2) - 1);
- if(LPosIni > 0)or(LPosFim > 0)then
+ if (LPosIni > 0) or (LPosFim > 0) then
Result := LText;
end;
@@ -852,9 +943,9 @@ class function TUtils.ChangeLastComma(AValue: string; ANewLastChar: Char): strin
begin
Result := AValue;
AValue := AValue.TrimRight;
- if(not AValue.IsEmpty)then
+ if not AValue.IsEmpty then
begin
- if(RightStr(AValue, 1) = ',')then
+ if RightStr(AValue, 1) = ',' then
begin
Delete(AValue, AValue.Length, 1);
Result := AValue + ANewLastChar;
@@ -866,9 +957,9 @@ class function TUtils.RemoveLastChar(AValue: string; AChar: Char): string;
begin
Result := AValue;
AValue := AValue.Trim;
- if(not AValue.IsEmpty)then
+ if not AValue.IsEmpty then
begin
- if(RightStr(AValue, 1) = AChar)then
+ if RightStr(AValue, 1) = AChar then
begin
Delete(AValue, AValue.Length, 1);
Result := AValue;
@@ -889,7 +980,7 @@ class function TUtils.RemoveAccents(AValue: string): string;
I: Integer;
begin
for I := 1 to Length(AValue) do
- if(Pos(AValue[I], WITH_ACCENTS) <> 0)then
+ if Pos(AValue[I], WITH_ACCENTS) <> 0 then
AValue[I] := OUT_ACCENTS[Pos(AValue[I], WITH_ACCENTS)];
Result := AValue;
@@ -903,7 +994,7 @@ class function TUtils.SwapSymbols(AValue: string): string;
I: Integer;
begin
for I := 1 to Length(AValue)do
- if(Pos(AValue[I], SYMBOLS_OLD) <> 0)then
+ if Pos(AValue[I], SYMBOLS_OLD) <> 0 then
AValue[I] := SYMBOLS_NEW[Pos(AValue[I], SYMBOLS_OLD)];
Result := AValue;
@@ -992,7 +1083,7 @@ class function TUtils.IsDPK(const AFilePath: string): Boolean;
class function TUtils.IsProjectGroup(const AFilePath: string): Boolean;
begin
- Result := ExtractFileExt(AFilePath).ToLower = '.groupproj';
+ Result := ExtractFileExt(AFilePath).ToLower = TC4DExtensionsFiles.GROUPPROJ.ToStringWithPoint;
end;
class function TUtils.IsProject(const AFilePath: string): Boolean;
diff --git a/Src/View/DelphiAIDev.View.About.dfm b/Src/View/DelphiAIDev.View.About.dfm
index 056b279..3a7fe14 100644
--- a/Src/View/DelphiAIDev.View.About.dfm
+++ b/Src/View/DelphiAIDev.View.About.dfm
@@ -2103,15 +2103,16 @@ object DelphiAIDevViewAbout: TDelphiAIDevViewAbout
TabOrder = 0
OnClick = btnOKClick
end
- object btnTeste: TButton
+ object btnTest: TButton
Left = 2
Top = 2
Width = 75
Height = 31
Align = alLeft
- Caption = 'Teste'
+ Caption = 'Test'
TabOrder = 1
- OnClick = btnTesteClick
+ Visible = False
+ OnClick = btnTestClick
end
end
end
diff --git a/Src/View/DelphiAIDev.View.About.pas b/Src/View/DelphiAIDev.View.About.pas
index b694cdb..e4f78e0 100644
--- a/Src/View/DelphiAIDev.View.About.pas
+++ b/Src/View/DelphiAIDev.View.About.pas
@@ -32,7 +32,7 @@ TDelphiAIDevViewAbout = class(TForm)
imgGithub: TImage;
pnButtons: TPanel;
btnOK: TButton;
- btnTeste: TButton;
+ btnTest: TButton;
Panel1: TPanel;
lbDonateToCode4Delphi: TLabel;
imgDonate: TImage;
@@ -44,7 +44,7 @@ TDelphiAIDevViewAbout = class(TForm)
procedure lbSiteCode4DelphiMouseLeave(Sender: TObject);
procedure lbGitHubCode4DelphiClick(Sender: TObject);
procedure FormCreate(Sender: TObject);
- procedure btnTesteClick(Sender: TObject);
+ procedure btnTestClick(Sender: TObject);
procedure lbDonateToCode4DelphiClick(Sender: TObject);
private
@@ -121,7 +121,7 @@ procedure TDelphiAIDevViewAbout.lbSiteCode4DelphiMouseMove(Sender: TObject; Shif
TLabel(Sender).Font.Style := TLabel(Sender).Font.Style + [fsUnderline];
end;
-procedure TDelphiAIDevViewAbout.btnTesteClick(Sender: TObject);
+procedure TDelphiAIDevViewAbout.btnTestClick(Sender: TObject);
begin
//
end;
diff --git a/Src/View/DelphiAIDev.View.Dialog.dfm b/Src/View/DelphiAIDev.View.Dialog.dfm
index 63d2404..441b4d7 100644
--- a/Src/View/DelphiAIDev.View.Dialog.dfm
+++ b/Src/View/DelphiAIDev.View.Dialog.dfm
@@ -100,8 +100,8 @@ object DelphiAIDevViewDialog: TDelphiAIDevViewDialog
object lbMsg: TLabel
Left = 32
Top = 0
- Width = 432
- Height = 133
+ Width = 30
+ Height = 14
Align = alClient
Alignment = taCenter
Caption = 'lbMsg'
@@ -114,8 +114,6 @@ object DelphiAIDevViewDialog: TDelphiAIDevViewDialog
PopupMenu = PopupMenu1
Layout = tlCenter
WordWrap = True
- ExplicitWidth = 30
- ExplicitHeight = 14
end
object pnDetailsLabel: TPanel
Left = 0
@@ -132,7 +130,7 @@ object DelphiAIDevViewDialog: TDelphiAIDevViewDialog
Left = 389
Top = 0
Width = 68
- Height = 17
+ Height = 14
Cursor = crHandPoint
Margins.Left = 0
Margins.Top = 0
@@ -149,14 +147,13 @@ object DelphiAIDevViewDialog: TDelphiAIDevViewDialog
ParentFont = False
Layout = tlCenter
OnClick = lbViewDetailsClick
- ExplicitHeight = 14
end
object lbViewDetails02: TLabel
AlignWithMargins = True
Left = 462
Top = 0
Width = 12
- Height = 17
+ Height = 14
Cursor = crHandPoint
Margins.Left = 0
Margins.Top = 0
@@ -173,7 +170,6 @@ object DelphiAIDevViewDialog: TDelphiAIDevViewDialog
ParentFont = False
Layout = tlCenter
OnClick = lbViewDetailsClick
- ExplicitHeight = 14
end
end
object pnImg: TPanel
diff --git a/Src/View/DelphiAIDev.View.Dialog.pas b/Src/View/DelphiAIDev.View.Dialog.pas
index 556a0a7..4ffb25a 100644
--- a/Src/View/DelphiAIDev.View.Dialog.pas
+++ b/Src/View/DelphiAIDev.View.Dialog.pas
@@ -112,7 +112,7 @@ procedure TDelphiAIDevViewDialog.FormKeyDown(Sender: TObject; var Key: Word; Shi
VK_ESCAPE:
if Shift = [] then
begin
- if(btnCancel.Visible)then
+ if btnCancel.Visible then
btnCancel.Click
else
Self.Close;
@@ -132,7 +132,7 @@ procedure TDelphiAIDevViewDialog.ConfHeightForm;
begin
pnDetailsLabel.Visible := True;
pnDetails.Visible := True;
- if(FDetails.Trim.IsEmpty)then
+ if FDetails.Trim.IsEmpty then
begin
pnDetailsLabel.Visible := False;
pnDetails.Visible := False;
@@ -149,14 +149,14 @@ procedure TDelphiAIDevViewDialog.ConfButtons;
begin
btnCancel.Visible := FButtons = TC4DButtons.OK_Cancel;
btnOK.SetFocus;
- if(btnCancel.Visible)and(FBtnFocu = TC4DBtnFocu.Cancel)then
+ if (btnCancel.Visible) and (FBtnFocu = TC4DBtnFocu.Cancel) then
btnCancel.SetFocus;
end;
procedure TDelphiAIDevViewDialog.lbViewDetailsClick(Sender: TObject);
begin
try
- if(mmDetails.Visible)then
+ if mmDetails.Visible then
begin
mmDetails.Visible := False;
lbViewDetails02.Caption := '>>';
diff --git a/Src/View/DelphiAIDev.View.Memo.pas b/Src/View/DelphiAIDev.View.Memo.pas
index cb7a9f8..becf793 100644
--- a/Src/View/DelphiAIDev.View.Memo.pas
+++ b/Src/View/DelphiAIDev.View.Memo.pas
@@ -56,7 +56,7 @@ procedure TDelphiAIDevViewMemo.mmMensagemKeyDown(Sender: TObject; var Key: Word;
const
KEY_A = $41;
begin
- if(Key = KEY_A)and(Shift = [ssCtrl])then
+ if (Key = KEY_A) and (Shift = [ssCtrl]) then
mmMensagem.SelectAll;
end;
diff --git a/Src/WaitingScreen/DelphiAIDev.WaitingScreen.View.pas b/Src/WaitingScreen/DelphiAIDev.WaitingScreen.View.pas
index 4657d7c..6faad8d 100644
--- a/Src/WaitingScreen/DelphiAIDev.WaitingScreen.View.pas
+++ b/Src/WaitingScreen/DelphiAIDev.WaitingScreen.View.pas
@@ -47,7 +47,7 @@ procedure TDelphiAIDevWaitingScreenView.FormCreate(Sender: TObject);
procedure TDelphiAIDevWaitingScreenView.FormShow(Sender: TObject);
begin
lbMsg.Caption := C_MSG_DEFAULT;
- if(not FMsg.Trim.IsEmpty)then
+ if not FMsg.Trim.IsEmpty then
lbMsg.Caption := FMsg;
Self.BringToFront;
@@ -55,7 +55,7 @@ procedure TDelphiAIDevWaitingScreenView.FormShow(Sender: TObject);
procedure TDelphiAIDevWaitingScreenView.FormKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState);
begin
- if(Key = VK_F4)and(ssAlt in Shift)then
+ if (Key = VK_F4) and (ssAlt in Shift) then
Key := 0;
end;
diff --git a/Src/WaitingScreen/DelphiAIDev.WaitingScreen.pas b/Src/WaitingScreen/DelphiAIDev.WaitingScreen.pas
index 0c5906f..82123a3 100644
--- a/Src/WaitingScreen/DelphiAIDev.WaitingScreen.pas
+++ b/Src/WaitingScreen/DelphiAIDev.WaitingScreen.pas
@@ -25,7 +25,7 @@ implementation
class function TDelphiAIDevWaitingScreen.GetInstance: TDelphiAIDevWaitingScreen;
begin
- if(not Assigned(Instance))then
+ if not Assigned(Instance) then
Instance := Self.Create;
Result := Instance;
end;
@@ -42,7 +42,7 @@ destructor TDelphiAIDevWaitingScreen.Destroy;
procedure TDelphiAIDevWaitingScreen.Show(const AMsg: string = '');
begin
- if(not Assigned(FDelphiAIDevWaitingScreenView))then
+ if not Assigned(FDelphiAIDevWaitingScreenView) then
FDelphiAIDevWaitingScreenView := TDelphiAIDevWaitingScreenView.Create(nil);
FDelphiAIDevWaitingScreenView.Msg := AMsg;
FDelphiAIDevWaitingScreenView.Show;
@@ -57,7 +57,7 @@ procedure TDelphiAIDevWaitingScreen.Close;
initialization
finalization
- if(Assigned(Instance))then
+ if Assigned(Instance) then
FreeAndNil(Instance);
end.