├── .gitignore ├── Delphi ├── DelphiCtrlTab_D$(DV).hhdproj ├── DelphiCtrlTab_D23.dpk ├── DelphiCtrlTab_D23.dproj ├── DelphiCtrlTab_D26.dpk ├── DelphiCtrlTab_D26.dproj ├── DelphiCtrlTab_D27.dpk ├── DelphiCtrlTab_D27.dproj ├── DelphiCtrlTab_D28.dpk ├── DelphiCtrlTab_D28.dproj └── DelphiCtrlTab_Extensions.xml ├── DelphiCtrlTab_D$(DV).hhgroupproj ├── DelphiCtrlTab_D23.groupproj ├── DelphiCtrlTab_D26.groupproj ├── DelphiCtrlTab_D27.groupproj ├── DelphiCtrlTab_D28.groupproj ├── LICENSE ├── README.md ├── Source ├── CtrlTab.Consts.pas ├── CtrlTab.DesignNotification.pas ├── CtrlTab.EditorNotifierBase.pas ├── CtrlTab.EditorServicesNotifier.pas ├── CtrlTab.FileLogger.pas ├── CtrlTab.FormEditorNotifier.pas ├── CtrlTab.FrmOpenDocs.dfm ├── CtrlTab.FrmOpenDocs.pas ├── CtrlTab.IdeNotifier.pas ├── CtrlTab.IdePlugin.pas ├── CtrlTab.Interfaces.pas ├── CtrlTab.Main.pas ├── CtrlTab.Settings.pas ├── CtrlTab.SettingsManager.pas ├── CtrlTab.SourceEditorNotifier.pas └── CtrlTab.ViewManager.pas ├── binaries └── Release │ ├── DelphiCtrlTab_D23.bpl │ ├── DelphiCtrlTab_D26.bpl │ ├── DelphiCtrlTab_D27.bpl │ └── DelphiCtrlTab_D28.bpl ├── docs └── images │ └── DelphiCtrlTab.jpg └── msbuild ├── .targets └── DelphiCtrlTab.Compile.targets ├── DelphiCtrlTab.proj └── buildAll.bat /.gitignore: -------------------------------------------------------------------------------- 1 | # Uncomment these types if you want even more clean repository. But be careful. 2 | # It can make harm to an existing project source. Read explanations below. 3 | # 4 | # Resource files are binaries containing manifest, project icon and version info. 5 | # They can not be viewed as text or compared by diff-tools. Consider replacing them with .rc files. 6 | #*.res 7 | # 8 | # Type library file (binary). In old Delphi versions it should be stored. 9 | # Since Delphi 2009 it is produced from .ridl file and can safely be ignored. 10 | #*.tlb 11 | # 12 | # Diagram Portfolio file. Used by the diagram editor up to Delphi 7. 13 | # Uncomment this if you are not using diagrams or use newer Delphi version. 14 | #*.ddp 15 | # 16 | # Visual LiveBindings file. Added in Delphi XE2. 17 | # Uncomment this if you are not using LiveBindings Designer. 18 | #*.vlb 19 | # 20 | # Deployment Manager configuration file for your project. Added in Delphi XE2. 21 | # Uncomment this if it is not mobile development and you do not use remote debug feature. 22 | #*.deployproj 23 | # 24 | # C++ object files produced when C/C++ Output file generation is configured. 25 | # Uncomment this if you are not using external objects (zlib library for example). 26 | #*.obj 27 | # 28 | 29 | # Delphi compiler-generated binaries (safe to delete) 30 | *.exe 31 | *.dll 32 | *.bpi 33 | *.dcp 34 | *.so 35 | *.apk 36 | *.drc 37 | *.map 38 | *.dres 39 | *.rsm 40 | *.tds 41 | *.dcu 42 | *.lib 43 | *.a 44 | *.o 45 | *.ocx 46 | 47 | # Delphi autogenerated files (duplicated info) 48 | *.cfg 49 | *.hpp 50 | *Resource.rc 51 | 52 | # Delphi local files (user-specific info) 53 | *.local 54 | *.identcache 55 | *.projdata 56 | *.tvsconfig 57 | *.dsk 58 | 59 | # Delphi history and backups 60 | __history/ 61 | __recovery/ 62 | *.~* 63 | 64 | # Castalia statistics file (since XE7 Castalia is distributed with Delphi) 65 | *.stat 66 | 67 | # Boss dependency manager vendor folder https://github.com/HashLoad/boss 68 | modules/ 69 | Delphi/*.res 70 | binaries/Debug/ 71 | build/ 72 | -------------------------------------------------------------------------------- /Delphi/DelphiCtrlTab_D$(DV).hhdproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | rtl.dcp 4 | designide.dcp 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | false 26 | ..\build\bin\$(Config)\ 27 | System;Xml;Data;Datasnap;Web;Soap;$(DCC_Namespace) 28 | true 29 | All 30 | true 31 | .\$(Platform)\$(Config) 32 | ..\binaries\$(Config)\ 33 | false 34 | false 35 | false 36 | false 37 | false 38 | c:\Program Files (x86)\Embarcadero\Studio\20.0\bin\ 39 | 40 | 41 | 42 | rtl;$(DCC_UsePackage) 43 | 1033 44 | Winapi;System.Win;Data.Win;Datasnap.Win;Web.Win;Soap.Win;Xml.Win;Bde;$(DCC_Namespace) 45 | CompanyName=;FileVersion=1.0.0.0;InternalName=;LegalCopyright=;LegalTrademarks=;OriginalFilename=;ProductVersion=1.0.0.0;Comments=;ProgramID=com.embarcadero.$(MSBuildProjectName);FileDescription=$(MSBuildProjectName);ProductName=$(MSBuildProjectName) 46 | true 47 | 48 | 49 | 53 | 54 | rtl;$(DCC_UsePackage) 55 | 56 | 57 | 58 | -------------------------------------------------------------------------------- /Delphi/DelphiCtrlTab_D23.dpk: -------------------------------------------------------------------------------- 1 | {* ***************************************************************** 2 | 3 | IMPORTANT !!!! WARNING !!!! 4 | 5 | This file is automatically generated by HHProjectMaker 6 | any changes made to this file will be lost !!!!! 7 | Edit this files instead: 8 | c:\Source\DelphiCtrlTab\Delphi\DelphiCtrlTab_D$(DV).hhdproj 9 | respectively the suitable of the related *.hhlibrary files. 10 | 11 | ***************************************************************** *} 12 | 13 | package DelphiCtrlTab_D23; 14 | 15 | {$R *.res} 16 | {$IFDEF IMPLICITBUILDING This IFDEF should not be used by users} 17 | {$ENDIF IMPLICITBUILDING} 18 | {$IMPLICITBUILD OFF} 19 | 20 | requires 21 | rtl, 22 | designide; 23 | 24 | contains 25 | CtrlTab.Main in '..\Source\CtrlTab.Main.pas', 26 | CtrlTab.FrmOpenDocs in '..\Source\CtrlTab.FrmOpenDocs.pas' {FormOpenDocs}, 27 | CtrlTab.ViewManager in '..\Source\CtrlTab.ViewManager.pas', 28 | CtrlTab.SourceEditorNotifier in '..\Source\CtrlTab.SourceEditorNotifier.pas', 29 | CtrlTab.FormEditorNotifier in '..\Source\CtrlTab.FormEditorNotifier.pas', 30 | CtrlTab.IdeNotifier in '..\Source\CtrlTab.IdeNotifier.pas', 31 | CtrlTab.IdePlugin in '..\Source\CtrlTab.IdePlugin.pas', 32 | CtrlTab.Interfaces in '..\Source\CtrlTab.Interfaces.pas', 33 | CtrlTab.DesignNotification in '..\Source\CtrlTab.DesignNotification.pas', 34 | CtrlTab.FileLogger in '..\Source\CtrlTab.FileLogger.pas', 35 | CtrlTab.EditorNotifierBase in '..\Source\CtrlTab.EditorNotifierBase.pas', 36 | CtrlTab.SettingsManager in '..\Source\CtrlTab.SettingsManager.pas', 37 | CtrlTab.Settings in '..\Source\CtrlTab.Settings.pas', 38 | CtrlTab.Consts in '..\Source\CtrlTab.Consts.pas', 39 | CtrlTab.EditorServicesNotifier in '..\Source\CtrlTab.EditorServicesNotifier.pas'; 40 | 41 | end. 42 | -------------------------------------------------------------------------------- /Delphi/DelphiCtrlTab_D23.dproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | {798f78b3-a8df-4c8b-9d81-7e0544414330} 4 | DelphiCtrlTab_D23.dpk 5 | True 6 | Debug 7 | 3 8 | Package 9 | VCL 10 | 18.1 11 | Win32 12 | ..\ 13 | 14 | 15 | true 16 | 17 | 18 | true 19 | Base 20 | true 21 | 22 | 23 | true 24 | Base 25 | true 26 | 27 | 28 | true 29 | Base 30 | true 31 | 32 | 33 | true 34 | Base 35 | true 36 | 37 | 38 | true 39 | Cfg_2 40 | true 41 | true 42 | 43 | 44 | true 45 | Cfg_2 46 | true 47 | true 48 | 49 | 50 | false 51 | DelphiCtrlTab_D23 52 | 00400000 53 | true 54 | 3 55 | CompanyName=;FileDescription=;FileVersion=1.0.0.0;InternalName=;LegalCopyright=;LegalTrademarks=;OriginalFilename=;ProductName=;ProductVersion=1.0.0.0 56 | false 57 | true 58 | false 59 | 1031 60 | DelphiCtrlTab_D23 61 | ..\binaries\$(Config)\ 62 | true 63 | false 64 | false 65 | System;Xml;Data;Datasnap;Web;Soap;$(DCC_Namespace) 66 | false 67 | false 68 | false 69 | true 70 | $(OutDir)$(RelPath)dcp\ 71 | false 72 | true 73 | 4 74 | false 75 | false 76 | .\$(Platform)\$(Config) 77 | $(OutDir)$(RelPath)obj\ 78 | $(OutDir)$(RelPath)dcp\;$(DCC_UnitSearchPath) 79 | 2 80 | 2 81 | true 82 | false 83 | true 84 | true 85 | c:\Program Files (x86)\Embarcadero\Studio\20.0\bin\ 86 | All 87 | 88 | 89 | Winapi;System.Win;Data.Win;Datasnap.Win;Web.Win;Soap.Win;Xml.Win;Bde;$(DCC_Namespace) 90 | rtl;$(DCC_UsePackage) 91 | 1033 92 | CompanyName=;FileVersion=1.0.0.0;InternalName=;LegalCopyright=;LegalTrademarks=;OriginalFilename=;ProductVersion=1.0.0.0;Comments=;ProgramID=com.embarcadero.$(MSBuildProjectName);FileDescription=$(MSBuildProjectName);ProductName=$(MSBuildProjectName) 93 | true 94 | 95 | 96 | Winapi;System.Win;Data.Win;Datasnap.Win;Web.Win;Soap.Win;Xml.Win;$(DCC_Namespace) 97 | true 98 | rtl;$(DCC_UsePackage) 99 | 100 | 101 | true 102 | _HH_StaticallyLinkLibraries;RELEASE;$(DCC_Define) 103 | 104 | 105 | _HH_StaticallyLinkLibraries;DEBUG;$(DCC_Define) 106 | 107 | 108 | true 109 | true 110 | true 111 | true 112 | 113 | 114 | true 115 | true 116 | 117 | 118 | 119 | MainSource 120 | 121 | 122 | 123 | 124 | 125 |
FormOpenDocs
126 |
127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | Base 142 | 143 | 144 | Cfg_1 145 | Base 146 | 147 | 148 | Cfg_2 149 | Base 150 | 151 | 152 | Cfg_3 153 | Cfg_2 154 | 155 | 156 | Cfg_4 157 | Cfg_2 158 | 159 |
160 | Delphi.Personality.12 161 | Package 162 | 163 | 164 | 165 | DelphiCtrlTab_D23.dpk 166 | 167 | 168 | True 169 | False 170 | 1 171 | 0 172 | 0 173 | 0 174 | False 175 | False 176 | False 177 | False 178 | False 179 | 1031 180 | 1252 181 | 182 | 183 | 184 | Ide Plugin 185 | 1.0.0.0 186 | 187 | 188 | 189 | 190 | DelphiCtrlTab 191 | 1.0.0.0 192 | 193 | 194 | 195 | 196 | 197 | True 198 | True 199 | 200 | 201 | 12 202 |
-------------------------------------------------------------------------------- /Delphi/DelphiCtrlTab_D26.dpk: -------------------------------------------------------------------------------- 1 | {* ***************************************************************** 2 | 3 | IMPORTANT !!!! WARNING !!!! 4 | 5 | This file is automatically generated by HHProjectMaker 6 | any changes made to this file will be lost !!!!! 7 | Edit this files instead: 8 | c:\Source\DelphiCtrlTab\Delphi\DelphiCtrlTab_D$(DV).hhdproj 9 | respectively the suitable of the related *.hhlibrary files. 10 | 11 | ***************************************************************** *} 12 | 13 | package DelphiCtrlTab_D26; 14 | 15 | {$R *.res} 16 | {$IFDEF IMPLICITBUILDING This IFDEF should not be used by users} 17 | {$ENDIF IMPLICITBUILDING} 18 | {$IMPLICITBUILD OFF} 19 | 20 | requires 21 | rtl, 22 | designide; 23 | 24 | contains 25 | CtrlTab.Main in '..\Source\CtrlTab.Main.pas', 26 | CtrlTab.FrmOpenDocs in '..\Source\CtrlTab.FrmOpenDocs.pas' {FormOpenDocs}, 27 | CtrlTab.ViewManager in '..\Source\CtrlTab.ViewManager.pas', 28 | CtrlTab.SourceEditorNotifier in '..\Source\CtrlTab.SourceEditorNotifier.pas', 29 | CtrlTab.FormEditorNotifier in '..\Source\CtrlTab.FormEditorNotifier.pas', 30 | CtrlTab.IdeNotifier in '..\Source\CtrlTab.IdeNotifier.pas', 31 | CtrlTab.IdePlugin in '..\Source\CtrlTab.IdePlugin.pas', 32 | CtrlTab.Interfaces in '..\Source\CtrlTab.Interfaces.pas', 33 | CtrlTab.DesignNotification in '..\Source\CtrlTab.DesignNotification.pas', 34 | CtrlTab.FileLogger in '..\Source\CtrlTab.FileLogger.pas', 35 | CtrlTab.EditorNotifierBase in '..\Source\CtrlTab.EditorNotifierBase.pas', 36 | CtrlTab.SettingsManager in '..\Source\CtrlTab.SettingsManager.pas', 37 | CtrlTab.Settings in '..\Source\CtrlTab.Settings.pas', 38 | CtrlTab.Consts in '..\Source\CtrlTab.Consts.pas', 39 | CtrlTab.EditorServicesNotifier in '..\Source\CtrlTab.EditorServicesNotifier.pas'; 40 | 41 | end. 42 | -------------------------------------------------------------------------------- /Delphi/DelphiCtrlTab_D26.dproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | {798f78b3-a8df-4c8b-9d81-7e0544414330} 4 | DelphiCtrlTab_D26.dpk 5 | True 6 | Debug 7 | 3 8 | Package 9 | VCL 10 | 18.8 11 | Win32 12 | ..\ 13 | 14 | 15 | true 16 | 17 | 18 | true 19 | Base 20 | true 21 | 22 | 23 | true 24 | Base 25 | true 26 | 27 | 28 | true 29 | Base 30 | true 31 | 32 | 33 | true 34 | Base 35 | true 36 | 37 | 38 | true 39 | Cfg_2 40 | true 41 | true 42 | 43 | 44 | true 45 | Cfg_2 46 | true 47 | true 48 | 49 | 50 | false 51 | DelphiCtrlTab_D26 52 | 00400000 53 | true 54 | 3 55 | CompanyName=;FileDescription=;FileVersion=1.0.0.0;InternalName=;LegalCopyright=;LegalTrademarks=;OriginalFilename=;ProductName=;ProductVersion=1.0.0.0 56 | false 57 | true 58 | false 59 | 1031 60 | DelphiCtrlTab_D26 61 | ..\binaries\$(Config)\ 62 | true 63 | false 64 | false 65 | System;Xml;Data;Datasnap;Web;Soap;$(DCC_Namespace) 66 | false 67 | false 68 | false 69 | true 70 | $(OutDir)$(RelPath)dcp\ 71 | false 72 | true 73 | 4 74 | false 75 | false 76 | .\$(Platform)\$(Config) 77 | $(OutDir)$(RelPath)obj\ 78 | $(OutDir)$(RelPath)dcp\;$(DCC_UnitSearchPath) 79 | 2 80 | 2 81 | true 82 | false 83 | true 84 | c:\Program Files (x86)\Embarcadero\Studio\20.0\bin\ 85 | true 86 | All 87 | 88 | 89 | Winapi;System.Win;Data.Win;Datasnap.Win;Web.Win;Soap.Win;Xml.Win;Bde;$(DCC_Namespace) 90 | rtl;$(DCC_UsePackage) 91 | 1033 92 | CompanyName=;FileVersion=1.0.0.0;InternalName=;LegalCopyright=;LegalTrademarks=;OriginalFilename=;ProductVersion=1.0.0.0;Comments=;ProgramID=com.embarcadero.$(MSBuildProjectName);FileDescription=$(MSBuildProjectName);ProductName=$(MSBuildProjectName) 93 | true 94 | 95 | 96 | Data.Win;Datasnap.Win;Web.Win;Soap.Win;Xml.Win;$(DCC_Namespace) 97 | true 98 | rtl;$(DCC_UsePackage) 99 | 100 | 101 | true 102 | _HH_StaticallyLinkLibraries;RELEASE;$(DCC_Define) 103 | 104 | 105 | _HH_StaticallyLinkLibraries;DEBUG;$(DCC_Define) 106 | 107 | 108 | true 109 | true 110 | true 111 | true 112 | 113 | 114 | true 115 | true 116 | 117 | 118 | 119 | MainSource 120 | 121 | 122 | 123 | 124 | 125 |
FormOpenDocs
126 |
127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | Base 142 | 143 | 144 | Cfg_1 145 | Base 146 | 147 | 148 | Cfg_2 149 | Base 150 | 151 | 152 | Cfg_3 153 | Cfg_2 154 | 155 | 156 | Cfg_4 157 | Cfg_2 158 | 159 |
160 | Delphi.Personality.12 161 | Package 162 | 163 | 164 | 165 | DelphiCtrlTab_D26.dpk 166 | 167 | 168 | True 169 | False 170 | 1 171 | 0 172 | 0 173 | 0 174 | False 175 | False 176 | False 177 | False 178 | False 179 | 1031 180 | 1252 181 | 182 | 183 | 184 | Ide Plugin 185 | 1.0.0.0 186 | 187 | 188 | 189 | 190 | DelphiCtrlTab 191 | 1.0.0.0 192 | 193 | 194 | 195 | 196 | 197 | True 198 | True 199 | 200 | 201 | 12 202 |
-------------------------------------------------------------------------------- /Delphi/DelphiCtrlTab_D27.dpk: -------------------------------------------------------------------------------- 1 | {* ***************************************************************** 2 | 3 | IMPORTANT !!!! WARNING !!!! 4 | 5 | This file is automatically generated by HHProjectMaker 6 | any changes made to this file will be lost !!!!! 7 | Edit this files instead: 8 | c:\Source\DelphiCtrlTab\Delphi\DelphiCtrlTab_D$(DV).hhdproj 9 | respectively the suitable of the related *.hhlibrary files. 10 | 11 | ***************************************************************** *} 12 | 13 | package DelphiCtrlTab_D27; 14 | 15 | {$R *.res} 16 | {$IFDEF IMPLICITBUILDING This IFDEF should not be used by users} 17 | {$ENDIF IMPLICITBUILDING} 18 | {$IMPLICITBUILD OFF} 19 | 20 | requires 21 | rtl, 22 | designide; 23 | 24 | contains 25 | CtrlTab.Main in '..\Source\CtrlTab.Main.pas', 26 | CtrlTab.FrmOpenDocs in '..\Source\CtrlTab.FrmOpenDocs.pas' {FormOpenDocs}, 27 | CtrlTab.ViewManager in '..\Source\CtrlTab.ViewManager.pas', 28 | CtrlTab.SourceEditorNotifier in '..\Source\CtrlTab.SourceEditorNotifier.pas', 29 | CtrlTab.FormEditorNotifier in '..\Source\CtrlTab.FormEditorNotifier.pas', 30 | CtrlTab.IdeNotifier in '..\Source\CtrlTab.IdeNotifier.pas', 31 | CtrlTab.IdePlugin in '..\Source\CtrlTab.IdePlugin.pas', 32 | CtrlTab.Interfaces in '..\Source\CtrlTab.Interfaces.pas', 33 | CtrlTab.DesignNotification in '..\Source\CtrlTab.DesignNotification.pas', 34 | CtrlTab.FileLogger in '..\Source\CtrlTab.FileLogger.pas', 35 | CtrlTab.EditorNotifierBase in '..\Source\CtrlTab.EditorNotifierBase.pas', 36 | CtrlTab.SettingsManager in '..\Source\CtrlTab.SettingsManager.pas', 37 | CtrlTab.Settings in '..\Source\CtrlTab.Settings.pas', 38 | CtrlTab.Consts in '..\Source\CtrlTab.Consts.pas', 39 | CtrlTab.EditorServicesNotifier in '..\Source\CtrlTab.EditorServicesNotifier.pas'; 40 | 41 | end. 42 | -------------------------------------------------------------------------------- /Delphi/DelphiCtrlTab_D27.dproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | {798f78b3-a8df-4c8b-9d81-7e0544414330} 4 | DelphiCtrlTab_D27.dpk 5 | True 6 | Debug 7 | 3 8 | Package 9 | VCL 10 | 19 11 | Win32 12 | ..\ 13 | 14 | 15 | true 16 | 17 | 18 | true 19 | Base 20 | true 21 | 22 | 23 | true 24 | Base 25 | true 26 | 27 | 28 | true 29 | Base 30 | true 31 | 32 | 33 | true 34 | Base 35 | true 36 | 37 | 38 | true 39 | Cfg_2 40 | true 41 | true 42 | 43 | 44 | true 45 | Cfg_2 46 | true 47 | true 48 | 49 | 50 | false 51 | DelphiCtrlTab_D27 52 | 00400000 53 | true 54 | 3 55 | CompanyName=;FileDescription=;FileVersion=1.0.0.0;InternalName=;LegalCopyright=;LegalTrademarks=;OriginalFilename=;ProductName=;ProductVersion=1.0.0.0 56 | false 57 | true 58 | false 59 | 1031 60 | DelphiCtrlTab_D27 61 | ..\binaries\$(Config)\ 62 | true 63 | false 64 | false 65 | System;Xml;Data;Datasnap;Web;Soap;$(DCC_Namespace) 66 | false 67 | false 68 | false 69 | true 70 | $(OutDir)$(RelPath)dcp\ 71 | false 72 | true 73 | 4 74 | false 75 | false 76 | .\$(Platform)\$(Config) 77 | $(OutDir)$(RelPath)obj\ 78 | $(OutDir)$(RelPath)dcp\;$(DCC_UnitSearchPath) 79 | 2 80 | 2 81 | true 82 | false 83 | true 84 | c:\Program Files (x86)\Embarcadero\Studio\20.0\bin\ 85 | true 86 | All 87 | 88 | 89 | Winapi;System.Win;Data.Win;Datasnap.Win;Web.Win;Soap.Win;Xml.Win;Bde;$(DCC_Namespace) 90 | rtl;$(DCC_UsePackage) 91 | 1033 92 | CompanyName=;FileVersion=1.0.0.0;InternalName=;LegalCopyright=;LegalTrademarks=;OriginalFilename=;ProductVersion=1.0.0.0;Comments=;ProgramID=com.embarcadero.$(MSBuildProjectName);FileDescription=$(MSBuildProjectName);ProductName=$(MSBuildProjectName) 93 | true 94 | 95 | 96 | Data.Win;Datasnap.Win;Web.Win;Soap.Win;Xml.Win;$(DCC_Namespace) 97 | true 98 | rtl;$(DCC_UsePackage) 99 | 100 | 101 | true 102 | _HH_StaticallyLinkLibraries;RELEASE;$(DCC_Define) 103 | 104 | 105 | _HH_StaticallyLinkLibraries;DEBUG;$(DCC_Define) 106 | 107 | 108 | true 109 | true 110 | true 111 | true 112 | 113 | 114 | true 115 | true 116 | 117 | 118 | 119 | MainSource 120 | 121 | 122 | 123 | 124 | 125 |
FormOpenDocs
126 |
127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | Base 142 | 143 | 144 | Cfg_1 145 | Base 146 | 147 | 148 | Cfg_2 149 | Base 150 | 151 | 152 | Cfg_3 153 | Cfg_2 154 | 155 | 156 | Cfg_4 157 | Cfg_2 158 | 159 |
160 | Delphi.Personality.12 161 | Package 162 | 163 | 164 | 165 | DelphiCtrlTab_D27.dpk 166 | 167 | 168 | True 169 | False 170 | 1 171 | 0 172 | 0 173 | 0 174 | False 175 | False 176 | False 177 | False 178 | False 179 | 1031 180 | 1252 181 | 182 | 183 | 184 | Ide Plugin 185 | 1.0.0.0 186 | 187 | 188 | 189 | 190 | DelphiCtrlTab 191 | 1.0.0.0 192 | 193 | 194 | 195 | 196 | 197 | True 198 | True 199 | 200 | 201 | 12 202 |
-------------------------------------------------------------------------------- /Delphi/DelphiCtrlTab_D28.dpk: -------------------------------------------------------------------------------- 1 | {* ***************************************************************** 2 | 3 | IMPORTANT !!!! WARNING !!!! 4 | 5 | This file is automatically generated by HHProjectMaker 6 | any changes made to this file will be lost !!!!! 7 | Edit this files instead: 8 | c:\Source\DelphiCtrlTab\Delphi\DelphiCtrlTab_D$(DV).hhdproj 9 | respectively the suitable of the related *.hhlibrary files. 10 | 11 | ***************************************************************** *} 12 | 13 | package DelphiCtrlTab_D28; 14 | 15 | {$R *.res} 16 | {$IFDEF IMPLICITBUILDING This IFDEF should not be used by users} 17 | {$ENDIF IMPLICITBUILDING} 18 | {$IMPLICITBUILD OFF} 19 | 20 | requires 21 | rtl, 22 | designide; 23 | 24 | contains 25 | CtrlTab.Main in '..\Source\CtrlTab.Main.pas', 26 | CtrlTab.FrmOpenDocs in '..\Source\CtrlTab.FrmOpenDocs.pas' {FormOpenDocs}, 27 | CtrlTab.ViewManager in '..\Source\CtrlTab.ViewManager.pas', 28 | CtrlTab.SourceEditorNotifier in '..\Source\CtrlTab.SourceEditorNotifier.pas', 29 | CtrlTab.FormEditorNotifier in '..\Source\CtrlTab.FormEditorNotifier.pas', 30 | CtrlTab.IdeNotifier in '..\Source\CtrlTab.IdeNotifier.pas', 31 | CtrlTab.IdePlugin in '..\Source\CtrlTab.IdePlugin.pas', 32 | CtrlTab.Interfaces in '..\Source\CtrlTab.Interfaces.pas', 33 | CtrlTab.DesignNotification in '..\Source\CtrlTab.DesignNotification.pas', 34 | CtrlTab.FileLogger in '..\Source\CtrlTab.FileLogger.pas', 35 | CtrlTab.EditorNotifierBase in '..\Source\CtrlTab.EditorNotifierBase.pas', 36 | CtrlTab.SettingsManager in '..\Source\CtrlTab.SettingsManager.pas', 37 | CtrlTab.Settings in '..\Source\CtrlTab.Settings.pas', 38 | CtrlTab.Consts in '..\Source\CtrlTab.Consts.pas', 39 | CtrlTab.EditorServicesNotifier in '..\Source\CtrlTab.EditorServicesNotifier.pas'; 40 | 41 | end. 42 | -------------------------------------------------------------------------------- /Delphi/DelphiCtrlTab_D28.dproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | {798f78b3-a8df-4c8b-9d81-7e0544414330} 4 | DelphiCtrlTab_D28.dpk 5 | True 6 | Debug 7 | 3 8 | Package 9 | VCL 10 | 20 11 | Win32 12 | ..\ 13 | 14 | 15 | true 16 | 17 | 18 | true 19 | Base 20 | true 21 | 22 | 23 | true 24 | Base 25 | true 26 | 27 | 28 | true 29 | Base 30 | true 31 | 32 | 33 | true 34 | Base 35 | true 36 | 37 | 38 | true 39 | Cfg_2 40 | true 41 | true 42 | 43 | 44 | true 45 | Cfg_2 46 | true 47 | true 48 | 49 | 50 | false 51 | DelphiCtrlTab_D28 52 | 00400000 53 | true 54 | 3 55 | CompanyName=;FileDescription=;FileVersion=1.0.0.0;InternalName=;LegalCopyright=;LegalTrademarks=;OriginalFilename=;ProductName=;ProductVersion=1.0.0.0 56 | false 57 | true 58 | false 59 | 1031 60 | DelphiCtrlTab_D28 61 | ..\binaries\$(Config)\ 62 | true 63 | false 64 | false 65 | System;Xml;Data;Datasnap;Web;Soap;$(DCC_Namespace) 66 | false 67 | false 68 | false 69 | true 70 | $(OutDir)$(RelPath)dcp\ 71 | false 72 | true 73 | 4 74 | false 75 | false 76 | .\$(Platform)\$(Config) 77 | $(OutDir)$(RelPath)obj\ 78 | $(OutDir)$(RelPath)dcp\;$(DCC_UnitSearchPath) 79 | 2 80 | 2 81 | true 82 | false 83 | true 84 | c:\Program Files (x86)\Embarcadero\Studio\20.0\bin\ 85 | true 86 | All 87 | 88 | 89 | Winapi;System.Win;Data.Win;Datasnap.Win;Web.Win;Soap.Win;Xml.Win;Bde;$(DCC_Namespace) 90 | rtl;$(DCC_UsePackage) 91 | 1033 92 | CompanyName=;FileVersion=1.0.0.0;InternalName=;LegalCopyright=;LegalTrademarks=;OriginalFilename=;ProductVersion=1.0.0.0;Comments=;ProgramID=com.embarcadero.$(MSBuildProjectName);FileDescription=$(MSBuildProjectName);ProductName=$(MSBuildProjectName) 93 | true 94 | 95 | 96 | Data.Win;Datasnap.Win;Web.Win;Soap.Win;Xml.Win;$(DCC_Namespace) 97 | true 98 | rtl;$(DCC_UsePackage) 99 | 100 | 101 | true 102 | _HH_StaticallyLinkLibraries;RELEASE;$(DCC_Define) 103 | 104 | 105 | _HH_StaticallyLinkLibraries;DEBUG;$(DCC_Define) 106 | 107 | 108 | true 109 | true 110 | true 111 | true 112 | 113 | 114 | true 115 | true 116 | 117 | 118 | 119 | MainSource 120 | 121 | 122 | 123 | 124 | 125 |
FormOpenDocs
126 |
127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | Base 142 | 143 | 144 | Cfg_1 145 | Base 146 | 147 | 148 | Cfg_2 149 | Base 150 | 151 | 152 | Cfg_3 153 | Cfg_2 154 | 155 | 156 | Cfg_4 157 | Cfg_2 158 | 159 |
160 | Delphi.Personality.12 161 | Package 162 | 163 | 164 | 165 | DelphiCtrlTab_D28.dpk 166 | 167 | 168 | True 169 | False 170 | 1 171 | 0 172 | 0 173 | 0 174 | False 175 | False 176 | False 177 | False 178 | False 179 | 1031 180 | 1252 181 | 182 | 183 | 184 | Ide Plugin 185 | 1.0.0.0 186 | 187 | 188 | 189 | 190 | DelphiCtrlTab 191 | 1.0.0.0 192 | 193 | 194 | 195 | 196 | 197 | True 198 | True 199 | 200 | 201 | 12 202 |
-------------------------------------------------------------------------------- /Delphi/DelphiCtrlTab_Extensions.xml: -------------------------------------------------------------------------------- 1 |  2 | Delphi.Personality.12 3 | $(ProjectType) 4 | 5 | 6 | 7 | $(MainSource) 8 | 9 | 10 | True 11 | False 12 | 1 13 | 0 14 | 0 15 | 0 16 | False 17 | False 18 | False 19 | False 20 | False 21 | 1031 22 | 1252 23 | 24 | 25 | 26 | Ide Plugin 27 | 1.0.0.0 28 | 29 | 30 | 31 | 32 | DelphiCtrlTab 33 | 1.0.0.0 34 | 35 | 36 | 37 | 38 | 39 | True 40 | True 41 | $${UnitTesting) 42 | 43 | 12 44 | -------------------------------------------------------------------------------- /DelphiCtrlTab_D$(DV).hhgroupproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /DelphiCtrlTab_D23.groupproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | {b2d95930-33d5-11e9-95d4-8c85906055c0} 4 | 5 | 6 | 7 | 8 | 9 | Default.Personality.12 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | -------------------------------------------------------------------------------- /DelphiCtrlTab_D26.groupproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | {b2d95930-33d5-11e9-95d4-8c85906055c0} 4 | 5 | 6 | 7 | 8 | 9 | Default.Personality.12 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | -------------------------------------------------------------------------------- /DelphiCtrlTab_D27.groupproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | {b2d95930-33d5-11e9-95d4-8c85906055c0} 4 | 5 | 6 | 7 | 8 | 9 | Default.Personality.12 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | -------------------------------------------------------------------------------- /DelphiCtrlTab_D28.groupproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | {b2d95930-33d5-11e9-95d4-8c85906055c0} 4 | 5 | 6 | 7 | 8 | 9 | Default.Personality.12 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 santiagoIT 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # DelphiCtrlTab 2 | Plugin for Delphi IDE. Allows open tab navigation based on activity instead of tab oder. 3 | 4 | I am a heavy user of the Ctrl+Tab shortcut. I always found the way the Ctrl+Tab behaves in the Delphi IDE to be very inconvenient. 5 | In all other IDE's I am familiar with, hitting Ctrl+Tab will take you back to the previously active tab, but in Delphi navigation order depends on the order in which the tabs are arranged in the editor. 6 | 7 | Whenever Ctrl+Tab or Ctrl+Shift+Tab is pressed a dialog displaying all open files is displayed. 8 | Files are listed in the order in which they have been activated. 9 | 10 | To navigate between files simply keep the Ctrl key pressed down and hit the tab key. Holding the shift key down naviagtes in the opposite direction. 11 | 12 | Refer to wiki on instructions how to install the plugin. 13 | 14 | ![alt text](https://github.com/santiagoIT/DelphiCtrlTab/blob/master/docs/images/DelphiCtrlTab.jpg) 15 | 16 | -------------------------------------------------------------------------------- /Source/CtrlTab.Consts.pas: -------------------------------------------------------------------------------- 1 | {=============================================================================== 2 | Project : DelphiCtrlTab_D27 3 | 4 | Name : CtrlTab.Consts 5 | 6 | Info : This Unit contains constant definitions 7 | 8 | Copyright (c) 2020 - Santiago Burbano 9 | ===============================================================================} 10 | unit CtrlTab.Consts; 11 | 12 | interface 13 | 14 | const 15 | // modules such as the Welcome Page carry this prefix before the fileName. 16 | c_BdsSpecialPrefix = 'bds:/'; 17 | 18 | // welcome page 19 | c_WelcomePage = 'default.htm'; 20 | c_WelcomePageDisplayName = 'Welcome Page'; 21 | 22 | implementation 23 | 24 | end. -------------------------------------------------------------------------------- /Source/CtrlTab.DesignNotification.pas: -------------------------------------------------------------------------------- 1 | {=============================================================================== 2 | Project : DelphiCtrlTab_D27 3 | 4 | Name : CtrlTab.DesignNotification 5 | 6 | Info : This Unit contains the class TDesignNotification. 7 | This class is notified of various designer events. 8 | 9 | Copyright (c) 2020 Santiago Burbano 10 | ===============================================================================} 11 | unit CtrlTab.DesignNotification; 12 | 13 | interface 14 | 15 | uses 16 | Classes, SysUtils, ToolsAPI, CtrlTab.Interfaces, DesignIntf; 17 | 18 | type 19 | TDesignNotification = class(TInterfacedObject, IDesignNotification) 20 | procedure DesignerClosed(const ADesigner: IDesigner; AGoingDormant: Boolean); 21 | procedure DesignerOpened(const ADesigner: IDesigner; AResurrecting: Boolean); 22 | procedure ItemDeleted(const ADesigner: IDesigner; AItem: TPersistent); 23 | procedure ItemInserted(const ADesigner: IDesigner; AItem: TPersistent); 24 | procedure ItemsModified(const ADesigner: IDesigner); 25 | procedure SelectionChanged(const ADesigner: IDesigner; const ASelection: IDesignerSelections); 26 | end; 27 | 28 | implementation 29 | 30 | uses 31 | CtrlTab.IdePlugin; 32 | 33 | {------------------------------------------------------------------------------- 34 | Name : DesignerClosed 35 | Info : This method is called when a form designer is closed. 36 | Input : ADesigner = 37 | AGoingDormant = 38 | Output : 39 | Result : None 40 | -------------------------------------------------------------------------------} 41 | procedure TDesignNotification.DesignerClosed(const ADesigner: IDesigner; AGoingDormant: Boolean); 42 | var 43 | FormFileName: string; 44 | ImplFileName: string; 45 | IntfFileName: string; 46 | begin 47 | // ideally we could have used IOTAFormNotifier to know when a designer is closed. But no notifications 48 | // were triggered :-( 49 | // So ended up using this is a workaround. 50 | ADesigner.ModuleFileNames(ImplFileName, IntfFileName, FormFileName); 51 | Plugin.DesignerClosed(FormFileName); 52 | end; 53 | 54 | {------------------------------------------------------------------------------- 55 | Name : DesignerOpened 56 | Info : 57 | Input : ADesigner = 58 | AResurrecting = 59 | Output : 60 | Result : None 61 | -------------------------------------------------------------------------------} 62 | procedure TDesignNotification.DesignerOpened(const ADesigner: IDesigner; AResurrecting: Boolean); 63 | begin 64 | end; 65 | 66 | {------------------------------------------------------------------------------- 67 | Name : ItemDeleted 68 | Info : 69 | Input : ADesigner = 70 | AItem = 71 | Output : 72 | Result : None 73 | -------------------------------------------------------------------------------} 74 | procedure TDesignNotification.ItemDeleted(const ADesigner: IDesigner; AItem: TPersistent); 75 | begin 76 | 77 | end; 78 | 79 | {------------------------------------------------------------------------------- 80 | Name : ItemInserted 81 | Info : 82 | Input : ADesigner = 83 | AItem = 84 | Output : 85 | Result : None 86 | -------------------------------------------------------------------------------} 87 | procedure TDesignNotification.ItemInserted(const ADesigner: IDesigner; AItem: TPersistent); 88 | begin 89 | 90 | end; 91 | 92 | {------------------------------------------------------------------------------- 93 | Name : ItemsModified 94 | Info : 95 | Input : ADesigner = 96 | Output : 97 | Result : None 98 | -------------------------------------------------------------------------------} 99 | procedure TDesignNotification.ItemsModified(const ADesigner: IDesigner); 100 | begin 101 | 102 | end; 103 | 104 | {------------------------------------------------------------------------------- 105 | Name : SelectionChanged 106 | Info : 107 | Input : ADesigner = 108 | ASelection = 109 | Output : 110 | Result : None 111 | -------------------------------------------------------------------------------} 112 | procedure TDesignNotification.SelectionChanged(const ADesigner: IDesigner; const ASelection: IDesignerSelections); 113 | begin 114 | end; 115 | 116 | end. 117 | 118 | -------------------------------------------------------------------------------- /Source/CtrlTab.EditorNotifierBase.pas: -------------------------------------------------------------------------------- 1 | {=============================================================================== 2 | Project : DelphiCtrlTab_D27 3 | 4 | Name : CtrlTab.EditorNotifierBase 5 | 6 | Info : This Unit contains the class TEditorBase. 7 | This class contains the base functionallity for Source and Form 8 | EditorNotifiers. 9 | 10 | Copyright (c) 2020 - Santiago Burbano 11 | ===============================================================================} 12 | unit CtrlTab.EditorNotifierBase; 13 | 14 | interface 15 | 16 | uses 17 | ToolsAPI, CtrlTab.Interfaces; 18 | 19 | type 20 | TEditorNotifierBase = class(TNotifierObject, IOTANotifier, IEditorNotifier) 21 | private 22 | function GetFileName: string; 23 | protected 24 | FEditor: IOTAEditor; 25 | FIndex: Integer; 26 | FFileName: string; 27 | procedure CleanUp; 28 | procedure Destroyed; 29 | public 30 | constructor Create(aEditor: IOTAEditor); reintroduce; 31 | destructor Destroy; override; 32 | end; 33 | 34 | implementation 35 | 36 | uses 37 | CtrlTab.IdePlugin, System.SysUtils; 38 | 39 | {------------------------------------------------------------------------------- 40 | Name : Create 41 | Info : Constructor 42 | Input : aEditor = Editor 43 | 44 | Output : 45 | Result : None 46 | -------------------------------------------------------------------------------} 47 | constructor TEditorNotifierBase.Create(aEditor: IOTAEditor); 48 | begin 49 | inherited Create; 50 | FEditor := aEditor; 51 | FFileName := FEditor.FileName; 52 | end; 53 | 54 | {------------------------------------------------------------------------------- 55 | Name : Destroy 56 | Info : 57 | Input : 58 | Output : 59 | Result : None 60 | -------------------------------------------------------------------------------} 61 | destructor TEditorNotifierBase.Destroy; 62 | begin 63 | Plugin.EditorNotifierAboutToBeDestroyed(Self); 64 | Cleanup; 65 | inherited; 66 | end; 67 | 68 | {------------------------------------------------------------------------------- 69 | Name : CleanUp 70 | Info : Performs clean up once the notifier is about to be released. 71 | Input : 72 | Output : 73 | Result : None 74 | -------------------------------------------------------------------------------} 75 | procedure TEditorNotifierBase.CleanUp; 76 | begin 77 | if FIndex >= 0 then 78 | begin 79 | if Assigned(FEditor) then 80 | begin 81 | Plugin.Logger.LogMessage(Format('TEditorNotifierBase. notifier removed. [%s]', [FFileName])); 82 | FEditor.RemoveNotifier(FIndex); 83 | end; 84 | FIndex := -1; 85 | end; 86 | FEditor := nil; 87 | end; 88 | 89 | {------------------------------------------------------------------------------- 90 | Name : Destroyed 91 | Info : The associated item is being destroyed so all references should be dropped. 92 | Exceptions are ignored. 93 | Input : 94 | Output : 95 | Result : None 96 | -------------------------------------------------------------------------------} 97 | procedure TEditorNotifierBase.Destroyed; 98 | begin 99 | Plugin.Logger.LogMessage(Format('TEditorNotifierBase.Destroyed. [%s]', [FFileName])); 100 | CleanUp; 101 | end; 102 | 103 | 104 | {------------------------------------------------------------------------------- 105 | Name : GetFileName 106 | Info : 107 | Input : 108 | Output : 109 | Result : string 110 | -------------------------------------------------------------------------------} 111 | function TEditorNotifierBase.GetFileName: string; 112 | begin 113 | Result := FFileName; 114 | end; 115 | 116 | 117 | end. 118 | 119 | -------------------------------------------------------------------------------- /Source/CtrlTab.EditorServicesNotifier.pas: -------------------------------------------------------------------------------- 1 | {=============================================================================== 2 | Project : DelphiCtrlTab_D27 3 | 4 | Name : CtrlTab.EditorServicesNotifier 5 | 6 | Info : This Unit contains the class TCtrlTabEditorServicesNotifier. 7 | DockFormUpdated is called whenever a Tab is activated. 8 | This is the only way I have to know when special modules such 9 | as the Welcome Page are activated. 10 | 11 | Copyright (c) 2020 - Santiago Burbano 12 | ===============================================================================} 13 | unit CtrlTab.EditorServicesNotifier; 14 | 15 | interface 16 | 17 | uses 18 | ToolsApi, System.Classes, DockForm; 19 | 20 | type 21 | TCtrlTabEditorServicesNotifier = Class(TNotifierObject, INTAEditServicesNotifier) 22 | public 23 | // INTAEditorServicesNotifier 24 | procedure DockFormRefresh(Const EditWindow: INTAEditWindow; DockForm: TDockableForm); 25 | procedure DockFormUpdated(Const EditWindow: INTAEditWindow; DockForm: TDockableForm); 26 | procedure DockFormVisibleChanged(Const EditWindow: INTAEditWindow; DockForm: TDockableForm); 27 | procedure EditorViewActivated(Const EditWindow: INTAEditWindow; Const EditView: IOTAEditView); 28 | procedure EditorViewModified(Const EditWindow: INTAEditWindow; Const EditView: IOTAEditView); 29 | procedure WindowActivated(Const EditWindow: INTAEditWindow); 30 | procedure WindowCommand(Const EditWindow: INTAEditWindow; Command: Integer; Param: Integer; Var Handled: Boolean); 31 | procedure WindowNotification(Const EditWindow: INTAEditWindow; Operation: TOperation); 32 | procedure WindowShow(Const EditWindow: INTAEditWindow; Show: Boolean; LoadedFromDesktop: Boolean); 33 | end; 34 | 35 | implementation 36 | 37 | uses 38 | CtrlTab.IdePlugin, System.SysUtils, CtrlTab.Consts; 39 | 40 | procedure TCtrlTabEditorServicesNotifier.DockFormRefresh(Const EditWindow: INTAEditWindow; DockForm: TDockableForm); 41 | begin 42 | end; 43 | 44 | {------------------------------------------------------------------------------- 45 | Name : DockFormUpdated 46 | Info : This method is called whenever a tab is activated. 47 | It is the only way I have found to be able to detect that the Welcome Page 48 | has been activated. 49 | Input : EditWindow = 50 | DockForm = 51 | 52 | Output : 53 | Result : None 54 | -------------------------------------------------------------------------------} 55 | procedure TCtrlTabEditorServicesNotifier.DockFormUpdated(Const EditWindow: INTAEditWindow; DockForm: TDockableForm); 56 | var 57 | Caption: string; 58 | begin 59 | if Assigned(EditWindow.Form) then 60 | begin 61 | Caption := EditWindow.Form.Caption; 62 | // only interested in special pages such as Welcome Page 63 | if Caption.StartsWith(c_BdsSpecialPrefix) then 64 | begin 65 | // register view without bds prefix 66 | Plugin.ViewManager.ViewActivated(Caption.Substring(5)); 67 | end; 68 | end; 69 | end; 70 | 71 | procedure TCtrlTabEditorServicesNotifier.DockFormVisibleChanged(Const EditWindow: INTAEditWindow; DockForm: TDockableForm); 72 | begin 73 | end; 74 | 75 | procedure TCtrlTabEditorServicesNotifier.EditorViewActivated(Const EditWindow: INTAEditWindow; Const EditView: IOTAEditView); 76 | begin 77 | end; 78 | 79 | procedure TCtrlTabEditorServicesNotifier.EditorViewModified(Const EditWindow: INTAEditWindow; Const EditView: IOTAEditView); 80 | begin 81 | end; 82 | 83 | procedure TCtrlTabEditorServicesNotifier.WindowActivated(Const EditWindow: INTAEditWindow); 84 | begin 85 | end; 86 | 87 | procedure TCtrlTabEditorServicesNotifier.WindowCommand(Const EditWindow: INTAEditWindow; Command: Integer; Param: Integer; Var Handled: Boolean); 88 | begin 89 | end; 90 | 91 | procedure TCtrlTabEditorServicesNotifier.WindowNotification(Const EditWindow: INTAEditWindow; Operation: TOperation); 92 | begin 93 | end; 94 | 95 | procedure TCtrlTabEditorServicesNotifier.WindowShow(Const EditWindow: INTAEditWindow; Show: Boolean; LoadedFromDesktop: Boolean); 96 | begin 97 | end; 98 | 99 | end. -------------------------------------------------------------------------------- /Source/CtrlTab.FileLogger.pas: -------------------------------------------------------------------------------- 1 | {=============================================================================== 2 | Project : DelphiCtrlTab_D27 3 | 4 | Name : CtrlTab.FileLogger 5 | 6 | Info : This Unit contains the class TFileLogger. 7 | This class is used for debugging purposes only. 8 | It writes output to: 9 | \Appdata\Roaming\ControlTab\log.txt 10 | 11 | Copyright (c) 2020 Santiago Burbano 12 | ===============================================================================} 13 | unit CtrlTab.FileLogger; 14 | 15 | interface 16 | 17 | uses 18 | CtrlTab.Interfaces; 19 | 20 | type 21 | TFileLogger = class(TInterfacedObject, ILogger) 22 | procedure ClearLog; 23 | procedure LogMessage(aMessage: string); 24 | private 25 | FLogFile: string; 26 | procedure OpenLogLocation; 27 | public 28 | constructor Create; 29 | end; 30 | 31 | implementation 32 | 33 | uses 34 | System.IOUtils, System.SysUtils, CtrlTab.IdePlugin, ShellApi, Winapi.Windows; 35 | 36 | {------------------------------------------------------------------------------- 37 | Name : Create 38 | Info : 39 | Input : 40 | Output : 41 | Result : None 42 | -------------------------------------------------------------------------------} 43 | constructor TFileLogger.Create; 44 | var 45 | LogDirectory: string; 46 | begin 47 | inherited; 48 | LogDirectory := System.SysUtils.GetHomePath; 49 | LogDirectory := TPath.Combine(LogDirectory, 'ControlTab'); 50 | FLogFile := TPath.Combine(LogDirectory, 'log.txt'); 51 | 52 | Plugin.PrintMessage(Format('Log file: %s', [FLogFile])); 53 | 54 | // ensure directory exists 55 | if not TDirectory.Exists(LogDirectory) then 56 | TDirectory.CreateDirectory(LogDirectory); 57 | end; 58 | 59 | {------------------------------------------------------------------------------- 60 | Name : ClearLog 61 | Info : Deletes the log file, if it exists 62 | Input : 63 | Output : 64 | Result : None 65 | -------------------------------------------------------------------------------} 66 | procedure TFileLogger.ClearLog; 67 | begin 68 | if TFile.Exists(FLogFile) then 69 | TFile.Delete(FLogFile); 70 | end; 71 | 72 | {------------------------------------------------------------------------------- 73 | Name : LogMessage 74 | Info : Appends a message to the log file 75 | Input : aMessage = 76 | 77 | Output : 78 | Result : None 79 | -------------------------------------------------------------------------------} 80 | procedure TFileLogger.LogMessage(aMessage: string); 81 | begin 82 | TFile.AppendAllText(FLogFile, aMessage + sLineBreak, TEncoding.UTF8); 83 | end; 84 | 85 | {------------------------------------------------------------------------------- 86 | Name : OpenLogLocation 87 | Info : Spwans the windows explorer to open the log file directory 88 | Input : 89 | Output : 90 | Result : None 91 | -------------------------------------------------------------------------------} 92 | procedure TFileLogger.OpenLogLocation; 93 | begin 94 | ShellExecute(0,'open', PChar(ExtractFilePath(FLogFile)), nil, nil, SW_SHOWNORMAL) ; 95 | end; 96 | 97 | end. 98 | 99 | -------------------------------------------------------------------------------- /Source/CtrlTab.FormEditorNotifier.pas: -------------------------------------------------------------------------------- 1 | {=============================================================================== 2 | Project : DelphiCtrlTab_D27 3 | 4 | Name : CtrlTab.FormEditorNotifier 5 | 6 | Info : This Unit contains the class TFormEditorNotifier. 7 | 8 | Copyright (c) 2020 Santiago Burbano 9 | ===============================================================================} 10 | unit CtrlTab.FormEditorNotifier; 11 | 12 | interface 13 | 14 | uses 15 | Classes, SysUtils, ToolsAPI, CtrlTab.Interfaces, CtrlTab.EditorNotifierBase; 16 | 17 | type 18 | TFormEditorNotifier = class(TEditorNotifierBase, IOTANotifier, IOTAFormNotifier, IEditorNotifier) 19 | private 20 | { Called when a component on this form was renamed } 21 | procedure ComponentRenamed(ComponentHandle: TOTAHandle; const OldName, NewName: string); 22 | { IOTAEditorNotifier } 23 | procedure FormActivated; 24 | { This is called immediately prior to the form being streamed out. This 25 | may be called without first getting a BeforeSave as in the case of 26 | the project being compiled. } 27 | procedure FormSaving; 28 | protected 29 | public 30 | constructor Create(aEditor: IOTAFormEditor); 31 | end; 32 | 33 | implementation 34 | 35 | uses 36 | CtrlTab.IdePlugin; 37 | 38 | {------------------------------------------------------------------------------- 39 | Name : Create 40 | Info : Constructor. Register myself as a notifier for AEditor 41 | Input : aEditor = form editor 42 | Output : 43 | Result : None 44 | -------------------------------------------------------------------------------} 45 | constructor TFormEditorNotifier.Create(aEditor: IOTAFormEditor); 46 | begin 47 | inherited Create(aEditor); 48 | FIndex := FEditor.AddNotifier(Self); 49 | end; 50 | 51 | {------------------------------------------------------------------------------- 52 | Name : ComponentRenamed 53 | Info : 54 | Input : ComponentHandle = 55 | OldName = 56 | NewName = 57 | 58 | Output : 59 | Result : None 60 | -------------------------------------------------------------------------------} 61 | procedure TFormEditorNotifier.ComponentRenamed(ComponentHandle: TOTAHandle; const OldName, NewName: string); 62 | begin 63 | end; 64 | 65 | {------------------------------------------------------------------------------- 66 | Name : FormActivated 67 | Info : This method is called when a form is activated. 68 | Input : 69 | Output : 70 | Result : None 71 | -------------------------------------------------------------------------------} 72 | procedure TFormEditorNotifier.FormActivated; 73 | begin 74 | // notify view manager 75 | Plugin.ViewManager.ViewActivated(FFileName); 76 | end; 77 | 78 | {------------------------------------------------------------------------------- 79 | Name : FormSaving 80 | Info : 81 | Input : 82 | Output : 83 | Result : None 84 | -------------------------------------------------------------------------------} 85 | procedure TFormEditorNotifier.FormSaving; 86 | begin 87 | end; 88 | 89 | end. 90 | 91 | -------------------------------------------------------------------------------- /Source/CtrlTab.FrmOpenDocs.dfm: -------------------------------------------------------------------------------- 1 | object FormOpenDocs: TFormOpenDocs 2 | Left = 0 3 | Top = 0 4 | BorderIcons = [biSystemMenu] 5 | BorderStyle = bsSizeToolWin 6 | Caption = 'Go to...' 7 | ClientHeight = 361 8 | ClientWidth = 678 9 | Color = clBtnFace 10 | Constraints.MinHeight = 250 11 | Constraints.MinWidth = 300 12 | Font.Charset = DEFAULT_CHARSET 13 | Font.Color = clWindowText 14 | Font.Height = -11 15 | Font.Name = 'Tahoma' 16 | Font.Style = [] 17 | KeyPreview = True 18 | OldCreateOrder = False 19 | Position = poMainFormCenter 20 | OnClose = FormClose 21 | OnCreate = FormCreate 22 | OnDeactivate = FormDeactivate 23 | OnKeyUp = FormKeyUp 24 | PixelsPerInch = 96 25 | TextHeight = 13 26 | object GroupBoxOpenUnits: TGroupBox 27 | AlignWithMargins = True 28 | Left = 5 29 | Top = 3 30 | Width = 668 31 | Height = 353 32 | Margins.Left = 5 33 | Margins.Right = 5 34 | Margins.Bottom = 5 35 | Align = alClient 36 | Caption = 'Open Files' 37 | TabOrder = 0 38 | object Label_SelectedFile: TLabel 39 | AlignWithMargins = True 40 | Left = 5 41 | Top = 18 42 | Width = 658 43 | Height = 19 44 | Align = alTop 45 | Caption = 'Label_SelectedFile' 46 | Font.Charset = DEFAULT_CHARSET 47 | Font.Color = clWindowText 48 | Font.Height = -16 49 | Font.Name = 'Tahoma' 50 | Font.Style = [fsBold] 51 | ParentFont = False 52 | ExplicitWidth = 153 53 | end 54 | object Label_FullPath: TLabel 55 | Left = 2 56 | Top = 338 57 | Width = 664 58 | Height = 13 59 | Align = alBottom 60 | Caption = 'Label_FullPath' 61 | ExplicitWidth = 69 62 | end 63 | object ListViewOpenFiles: TListView 64 | AlignWithMargins = True 65 | Left = 5 66 | Top = 43 67 | Width = 658 68 | Height = 292 69 | Align = alClient 70 | Columns = < 71 | item 72 | AutoSize = True 73 | end> 74 | ColumnClick = False 75 | ReadOnly = True 76 | RowSelect = True 77 | ShowColumnHeaders = False 78 | TabOrder = 0 79 | ViewStyle = vsReport 80 | OnChange = ListViewOpenFilesChange 81 | OnDblClick = ListViewOpenFilesDblClick 82 | end 83 | end 84 | end 85 | -------------------------------------------------------------------------------- /Source/CtrlTab.FrmOpenDocs.pas: -------------------------------------------------------------------------------- 1 | {=============================================================================== 2 | Project : DelphiCtrlTab_D27 3 | 4 | Name : CtrlTab.FrmOpenDocs 5 | 6 | Info : This Unit contains the class TFormOpenDocs. 7 | 8 | Copyright (c) 2020 Santiago Burbano 9 | ===============================================================================} 10 | unit CtrlTab.FrmOpenDocs; 11 | 12 | interface 13 | 14 | uses 15 | Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics, 16 | Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls, Vcl.ComCtrls; 17 | 18 | type 19 | TFormOpenDocs = class(TForm) 20 | GroupBoxOpenUnits: TGroupBox; 21 | Label_SelectedFile: TLabel; 22 | Label_FullPath: TLabel; 23 | ListViewOpenFiles: TListView; 24 | procedure FormClose(Sender: TObject; var Action: TCloseAction); 25 | procedure FormCreate(Sender: TObject); 26 | procedure FormDeactivate(Sender: TObject); 27 | procedure FormKeyUp(Sender: TObject; var Key: Word; Shift: TShiftState); 28 | function GetDisplayNameFor(const aModuleFileName: string): string; 29 | procedure ListViewOpenFilesChange(Sender: TObject; Item: TListItem; Change: TItemChange); 30 | procedure ListViewOpenFilesDblClick(Sender: TObject); 31 | private 32 | class var 33 | FIsShowing: Boolean; 34 | var 35 | FClosing: Boolean; 36 | // keep track of whether KeyUp was detected to the Tab-Key 37 | FTabKeyUpCalled: Boolean; 38 | procedure RefreshLabels; 39 | public 40 | class property IsShowing: Boolean read FIsShowing; 41 | end; 42 | 43 | var 44 | Form1: TFormOpenDocs; 45 | 46 | implementation 47 | 48 | {$R *.dfm} 49 | 50 | uses 51 | CtrlTab.IdePlugin, ToolsApi, CtrlTab.ViewManager, CtrlTab.Consts, 52 | System.Generics.Collections; 53 | 54 | 55 | {------------------------------------------------------------------------------- 56 | Name : FormClose 57 | Info : 58 | Input : Sender = 59 | Action = 60 | 61 | Output : 62 | Result : None 63 | -------------------------------------------------------------------------------} 64 | procedure TFormOpenDocs.FormClose(Sender: TObject; var Action: TCloseAction); 65 | var 66 | FileToActivateIndex: Integer; 67 | begin 68 | FClosing := True; 69 | if ModalResult = mrOk then 70 | begin 71 | // if Ctrl+Tab was pressed and released very quickly, then no KeyUp event for the Tab is registered 72 | // in this case we will set the item index to 1. 73 | if not FTabKeyUpCalled then 74 | begin 75 | if Plugin.ViewManager.ViewCount > 1 then 76 | FileToActivateIndex := 1 77 | else 78 | FileToActivateIndex := 0; 79 | end 80 | else 81 | FileToActivateIndex := ListViewOpenFiles.ItemIndex; 82 | 83 | if FileToActivateIndex > 0 then 84 | Plugin.ViewManager.ShowSourceView(FileToActivateIndex); 85 | end; 86 | Action := caFree; 87 | FIsShowing := False; 88 | 89 | // enable keyboard hook 90 | Plugin.ActivateKeyboardHook; 91 | 92 | // store size 93 | Plugin.Settings.DialogWidth := Self.Width; 94 | Plugin.Settings.DialogHeight := Self.Height; 95 | end; 96 | 97 | {------------------------------------------------------------------------------- 98 | Name : FormCreate 99 | Info : 100 | Input : Sender = 101 | 102 | Output : 103 | Result : None 104 | -------------------------------------------------------------------------------} 105 | procedure TFormOpenDocs.FormCreate(Sender: TObject); 106 | var 107 | FileDisplayName: string; 108 | i: Integer; 109 | EditorModified: Boolean; 110 | FileNameOnly: string; 111 | j: Integer; 112 | ModifiedEditorMap: TDictionary; 113 | ModuleEditor: IOTAEditor; 114 | ModuleServices: IOTAModuleServices; 115 | OpenModule: IOTAModule; 116 | View: string; 117 | begin 118 | AlphaBlend := True; 119 | AlphaBlendValue := 0; 120 | FIsShowing := True; 121 | FTabKeyUpCalled := False; 122 | 123 | // apply size 124 | if Plugin.Settings.DialogWidth > 0 then 125 | Width := Plugin.Settings.DialogWidth; 126 | if Plugin.Settings.DialogHeight > 0 then 127 | Height := Plugin.Settings.DialogHeight; 128 | 129 | 130 | ModifiedEditorMap := TDictionary.Create; 131 | try 132 | // list of all modified modules 133 | ModuleServices := BorlandIDEServices as IOTAModuleServices; 134 | for i := 0 to ModuleServices.ModuleCount - 1 do 135 | begin 136 | OpenModule := ModuleServices.Modules[i]; 137 | for j := 0 to OpenModule.ModuleFileCount - 1 do 138 | begin 139 | ModuleEditor := OpenModule.ModuleFileEditors[j]; 140 | if ModuleEditor.Modified then 141 | ModifiedEditorMap.AddOrSetValue(ModuleEditor.FileName, 1); 142 | end; 143 | end; 144 | 145 | // add files to ListView 146 | for i := 0 to Plugin.ViewManager.ViewCount -1 do 147 | begin 148 | View := Plugin.ViewManager.GetViewAt(i); 149 | EditorModified := ModifiedEditorMap.ContainsKey(View); 150 | FileDisplayName := GetDisplayNameFor(Plugin.ViewManager.GetViewAt(i)); 151 | FileNameOnly := ExtractFileName(FileDisplayName); 152 | 153 | // append an asterisk to file name if file is marked as modified. 154 | if EditorModified then 155 | FileNameOnly := FileNameOnly + ' *'; 156 | 157 | ListViewOpenFiles.AddItem(FileNameOnly, nil); 158 | end; 159 | 160 | if ListViewOpenFiles.Items.Count > 0 then 161 | ListViewOpenFiles.ItemIndex := 0; 162 | 163 | finally 164 | FreeAndNil(ModifiedEditorMap); 165 | end; 166 | end; 167 | 168 | 169 | 170 | {------------------------------------------------------------------------------- 171 | Name : FormDeactivate 172 | Info : 173 | Input : Sender = 174 | 175 | Output : 176 | Result : None 177 | -------------------------------------------------------------------------------} 178 | procedure TFormOpenDocs.FormDeactivate(Sender: TObject); 179 | begin 180 | if not FClosing then Close; 181 | end; 182 | 183 | {------------------------------------------------------------------------------- 184 | Name : FormKeyUp 185 | Info : 186 | Input : Sender = 187 | Key = 188 | Shift = 189 | 190 | Output : 191 | Result : None 192 | -------------------------------------------------------------------------------} 193 | procedure TFormOpenDocs.FormKeyUp(Sender: TObject; var Key: Word; Shift: TShiftState); 194 | var 195 | Index: Integer; 196 | begin 197 | if Key = VK_CONTROL then 198 | begin 199 | ModalResult := mrOk; 200 | Close; 201 | end 202 | else if (Key = VK_TAB) or (Key = VK_SPACE) then 203 | begin 204 | AlphaBlend := False; 205 | FTabKeyUpCalled := True; 206 | 207 | // if shift is pressed move the opposite direction 208 | if GetKeyState(VK_SHIFT) < 0 then 209 | begin 210 | Index := ListViewOpenFiles.ItemIndex - 1; 211 | if Index< 0 then 212 | Index := ListViewOpenFiles.Items.Count - 1; 213 | end 214 | else 215 | begin 216 | Index := ListViewOpenFiles.ItemIndex + 1; 217 | if Index >= ListViewOpenFiles.Items.Count then 218 | Index := 0; 219 | end; 220 | ListViewOpenFiles.ItemIndex := Index; 221 | end 222 | 223 | else if Key = VK_ESCAPE then 224 | begin 225 | ListViewOpenFiles.ItemIndex := 0; // no action 226 | ModalResult := mrCancel; 227 | Close; 228 | end; 229 | end; 230 | 231 | {------------------------------------------------------------------------------- 232 | Name : GetDisplayNameFor 233 | Info : Returns proper display name for BDS special pages such as the welcome page. 234 | Input : aFileName = Module File Name 235 | Output : 236 | Result : string 237 | -------------------------------------------------------------------------------} 238 | function TFormOpenDocs.GetDisplayNameFor(const aModuleFileName: string): string; 239 | begin 240 | if aModuleFileName = c_WelcomePage then 241 | Result := c_WelcomePageDisplayName 242 | else 243 | Result := aModuleFileName; 244 | end; 245 | 246 | {------------------------------------------------------------------------------- 247 | Name : ListViewOpenFilesChange 248 | Info : 249 | Input : Sender = 250 | Item = 251 | Change = 252 | 253 | Output : 254 | Result : None 255 | -------------------------------------------------------------------------------} 256 | procedure TFormOpenDocs.ListViewOpenFilesChange(Sender: TObject; Item: TListItem; Change: TItemChange); 257 | begin 258 | RefreshLabels; 259 | end; 260 | 261 | {------------------------------------------------------------------------------- 262 | Name : ListViewOpenFilesDblClick 263 | Info : 264 | Input : Sender = 265 | 266 | Output : 267 | Result : None 268 | -------------------------------------------------------------------------------} 269 | procedure TFormOpenDocs.ListViewOpenFilesDblClick(Sender: TObject); 270 | begin 271 | ModalResult := mrOk; 272 | Close; 273 | end; 274 | 275 | {------------------------------------------------------------------------------- 276 | Name : RefreshLabels 277 | Info : 278 | Input : 279 | Output : 280 | Result : None 281 | -------------------------------------------------------------------------------} 282 | procedure TFormOpenDocs.RefreshLabels; 283 | var 284 | FileName: string; 285 | begin 286 | if ListViewOpenFiles.ItemIndex >= 0 then 287 | begin 288 | FileName := GetDisplayNameFor(Plugin.ViewManager.GetViewAt(ListViewOpenFiles.ItemIndex)); 289 | Label_FullPath.Caption := FileName; 290 | Label_SelectedFile.Caption := ExtractFileName(FileName); 291 | end 292 | else 293 | begin 294 | Label_FullPath.Caption := '--'; 295 | Label_SelectedFile.Caption := '--'; 296 | end; 297 | 298 | // make sure selected item is always visible 299 | if Assigned(ListViewOpenFiles.Selected) then 300 | ListViewOpenFiles.Selected.MakeVisible(False); 301 | end; 302 | 303 | end. 304 | -------------------------------------------------------------------------------- /Source/CtrlTab.IdeNotifier.pas: -------------------------------------------------------------------------------- 1 | {=============================================================================== 2 | Project : DelphiCtrlTab_D27 3 | 4 | Name : CtrlTab.IdeNotifier 5 | 6 | Info : This Unit contains the class TIDENotifier. 7 | This class receives notifications whenever a file is opened/closed. 8 | When a file is opened we attach a editor notifier to it. The editor 9 | notifier is removed once the file is closed. 10 | 11 | Copyright (c) 2020 Santiago Burbano 12 | ===============================================================================} 13 | unit CtrlTab.IdeNotifier; 14 | 15 | interface 16 | 17 | uses 18 | ToolsAPI; 19 | 20 | type 21 | TIDENotifier = class(TNotifierObject, IOTANotifier, IOTAIDENotifier) 22 | private 23 | { IOTAIDENotifier } 24 | procedure FileNotification(NotifyCode: TOTAFileNotification; const FileName: string; var Cancel: Boolean); 25 | procedure BeforeCompile(const Project: IOTAProject; var Cancel: Boolean); overload; 26 | procedure AfterCompile(Succeeded: Boolean); overload; 27 | end; 28 | 29 | implementation 30 | 31 | uses 32 | CtrlTab.IdePlugin, SysUtils, System.Rtti; 33 | 34 | 35 | {------------------------------------------------------------------------------- 36 | Name : AfterCompile 37 | Info : 38 | Input : Succeeded = 39 | Output : 40 | Result : None 41 | -------------------------------------------------------------------------------} 42 | procedure TIDENotifier.AfterCompile(Succeeded: Boolean); 43 | begin 44 | // do nothing 45 | end; 46 | 47 | 48 | {------------------------------------------------------------------------------- 49 | Name : BeforeCompile 50 | Info : 51 | Input : Project = 52 | Cancel = 53 | 54 | Output : 55 | Result : None 56 | -------------------------------------------------------------------------------} 57 | procedure TIDENotifier.BeforeCompile(const Project: IOTAProject; var Cancel: Boolean); 58 | begin 59 | // do nothing 60 | end; 61 | 62 | 63 | {------------------------------------------------------------------------------- 64 | Name : FileNotification 65 | Info : 66 | Input : NotifyCode = 67 | FileName = 68 | Cancel = 69 | 70 | Output : 71 | Result : None 72 | -------------------------------------------------------------------------------} 73 | procedure TIDENotifier.FileNotification(NotifyCode: TOTAFileNotification; const FileName: string; var Cancel: Boolean); 74 | var 75 | ModuleServices: IOTAModuleServices; 76 | Module: IOTAModule; 77 | begin 78 | case NotifyCode of 79 | ofnFileOpened: 80 | begin 81 | ModuleServices := BorlandIDEServices as IOTAModuleServices; 82 | Module := ModuleServices.FindModule(FileName); 83 | if Assigned(Module) then 84 | Plugin.InstallSourceEditorNotifiers(Module); 85 | end; 86 | 87 | ofnFileClosing: 88 | begin 89 | Plugin.FileClosing(FileName); 90 | end; 91 | end; 92 | end; 93 | 94 | end. 95 | 96 | -------------------------------------------------------------------------------- /Source/CtrlTab.IdePlugin.pas: -------------------------------------------------------------------------------- 1 | {=============================================================================== 2 | Project : DelphiCtrlTab_D27 3 | 4 | Name : CtrlTab.IdePlugin 5 | 6 | Info : This Unit contains the class TIdePlugin. 7 | This class manages all relevant services for this plugin. 8 | It is a singleton. 9 | It is also responsible to hooking/unhooking the keyboard. 10 | 11 | Copyright (c) 2020 Santiago Burbano 12 | ===============================================================================} 13 | unit CtrlTab.IdePlugin; 14 | 15 | interface 16 | 17 | uses 18 | CtrlTab.Interfaces; 19 | 20 | function Plugin: IIdePlugin; 21 | 22 | implementation 23 | 24 | uses 25 | System.Generics.Defaults, Classes, SysUtils, ToolsAPI, CtrlTab.FormEditorNotifier, 26 | CtrlTab.ViewManager, CtrlTab.SourceEditorNotifier, CtrlTab.IdeNotifier, DesignIntf, 27 | CtrlTab.DesignNotification, Vcl.Forms, windows, messages, CtrlTab.FrmOpenDocs, System.IOUtils, CtrlTab.FileLogger, CtrlTab.SettingsManager, 28 | CtrlTab.EditorServicesNotifier; 29 | 30 | type 31 | TIdePlugin = class(TSingletonImplementation, IIdePlugin) 32 | procedure ActivateKeyboardHook; 33 | procedure BootUp; 34 | procedure ClearSourceEditorNotifiers; 35 | procedure DesignerClosed(aFormFile: string); 36 | procedure DisableKeyBoardHook; 37 | procedure EditorNotifierAboutToBeDestroyed(aNotifier: IEditorNotifier); 38 | procedure FileClosing(aUnitFile: string); 39 | function GetLogger: ILogger; 40 | function GetSettings: ISettings; 41 | function GetViewManager: IViewManager; 42 | procedure InstallSourceEditorNotifiers(Module: IOTAModule); 43 | procedure PrintMessage(const aMsg: string); 44 | procedure RemoveIDENotifier; 45 | procedure ShutDown; 46 | private 47 | FDesignNotification: IDesignNotification; 48 | FEditorNotifierId: Integer; 49 | FEditorNotifiers: IInterfaceList; 50 | FIDENotifierIndex: Integer; 51 | FLogger: ILogger; 52 | FViewManager: IViewManager; 53 | FSettingsManager: ISettingsManager; 54 | class function KeyboardHookProc(Code: Integer; WordParam: Word; LongParam: LongInt): LongInt; static; stdcall; 55 | public 56 | class var 57 | KBHook: HHook; 58 | constructor Create; 59 | property Logger: ILogger read GetLogger; 60 | end; 61 | 62 | // the singleton instance 63 | var 64 | PluginSingleton : TIdePlugin; 65 | 66 | {------------------------------------------------------------------------------- 67 | Name : Create 68 | Info : 69 | Input : 70 | Output : 71 | Result : None 72 | -------------------------------------------------------------------------------} 73 | constructor TIdePlugin.Create; 74 | begin 75 | inherited; 76 | FEditorNotifiers := TInterfaceList.Create; 77 | FViewManager := TViewManager.Create; 78 | FDesignNotification := TDesignNotification.Create; 79 | FSettingsManager := TSettingsManager.Create; 80 | FIDENotifierIndex := -1; 81 | KBHook := 0; 82 | end; 83 | 84 | {------------------------------------------------------------------------------- 85 | Name : ActivateKeyboardHook 86 | Info : 87 | Input : 88 | Output : 89 | Result : None 90 | -------------------------------------------------------------------------------} 91 | procedure TIdePlugin.ActivateKeyboardHook; 92 | begin 93 | // test if already active 94 | if KBHook <> 0 then Exit; 95 | 96 | // set hook 97 | KBHook :=SetWindowsHookEx(WH_KEYBOARD, 98 | {callback >} @KeyboardHookProc, 99 | HInstance, 100 | GetCurrentThreadId()) ; 101 | end; 102 | 103 | {------------------------------------------------------------------------------- 104 | Name : BootUp 105 | Info : Initializes the plugin. 106 | Input : 107 | Output : 108 | Result : None 109 | -------------------------------------------------------------------------------} 110 | procedure TIdePlugin.BootUp; 111 | var 112 | Services: IOTAServices; 113 | ModuleServices: IOTAModuleServices; 114 | i: Integer; 115 | OpenModule: IOTAModule; 116 | begin 117 | {$IFDEF DEBUG} 118 | // clear logs 119 | // Logger.ClearLog; 120 | // Logger.OpenLogLocation; 121 | {$ENDIF} 122 | 123 | // install IDE notifier so that we can install editor notifiers for any newly opened module 124 | Services := BorlandIDEServices as IOTAServices; 125 | FIDENotifierIndex := Services.AddNotifier(TIDENotifier.Create); 126 | 127 | // install editor notifiers for all currently open modules 128 | ModuleServices := BorlandIDEServices as IOTAModuleServices; 129 | for i := 0 to ModuleServices.ModuleCount - 1 do 130 | begin 131 | OpenModule := ModuleServices.Modules[i]; 132 | InstallSourceEditorNotifiers(OpenModule); 133 | end; 134 | 135 | // install editor services notifier. This is the only way to know when special windows have 136 | // been activated 137 | FEditorNotifierId := (BorlandIDEServices As IOTAEditorServices).AddNotifier(TCtrlTabEditorServicesNotifier.Create); 138 | 139 | RegisterDesignNotification(FDesignNotification); 140 | 141 | ActivateKeyboardHook; 142 | 143 | FSettingsManager.BootUp; 144 | end; 145 | 146 | {------------------------------------------------------------------------------- 147 | Name : ClearSourceEditorNotifiers 148 | Info : 149 | Input : 150 | Output : 151 | Result : None 152 | -------------------------------------------------------------------------------} 153 | procedure TIdePlugin.ClearSourceEditorNotifiers; 154 | var 155 | I: Integer; 156 | Notifier: IEditorNotifier; 157 | begin 158 | if Assigned(FEditorNotifiers) then 159 | begin 160 | for I := FEditorNotifiers.Count - 1 downto 0 do 161 | begin 162 | // Destroyed calls RemoveNotifier which in turn releases the instance 163 | if Supports(FEditorNotifiers[i], IEditorNotifier, Notifier) then 164 | Notifier.CleanUp; 165 | end; 166 | FEditorNotifiers.Clear; 167 | end; 168 | end; 169 | 170 | {------------------------------------------------------------------------------- 171 | Name : DesignerClosed 172 | Info : 173 | Input : aFormFile = 174 | 175 | Output : 176 | Result : None 177 | -------------------------------------------------------------------------------} 178 | procedure TIdePlugin.DesignerClosed(aFormFile: string); 179 | var 180 | EditorNotifier: IEditorNotifier; 181 | FormNotifier: IOTAFormNotifier; 182 | i: Integer; 183 | begin 184 | FViewManager.ViewClosed(aFormFile); 185 | 186 | for i := 0 to FEditorNotifiers.Count -1 do 187 | begin 188 | if Supports(FEditorNotifiers[i], IOTAFormNotifier, FormNotifier) then 189 | begin 190 | if Supports(FEditorNotifiers[i], IEditorNotifier, EditorNotifier) and (EditorNotifier.FileName = aFormFile) then 191 | begin 192 | 193 | FEditorNotifiers.Delete(i); 194 | EditorNotifier.CleanUp; 195 | break; 196 | end; 197 | end; 198 | end; 199 | end; 200 | 201 | {------------------------------------------------------------------------------- 202 | Name : DisableKeyBoardHook 203 | Info : 204 | Input : 205 | Output : 206 | Result : None 207 | -------------------------------------------------------------------------------} 208 | procedure TIdePlugin.DisableKeyBoardHook; 209 | begin 210 | {unhook the keyboard interception} 211 | if KBHook <> 0 then 212 | begin 213 | UnHookWindowsHookEx(KBHook); 214 | KBHook := 0; 215 | end; 216 | end; 217 | 218 | {------------------------------------------------------------------------------- 219 | Name : EditorNotifierAboutToBeDestroyed 220 | Info : 221 | Input : aNotifier = 222 | 223 | Output : 224 | Result : None 225 | -------------------------------------------------------------------------------} 226 | procedure TIdePlugin.EditorNotifierAboutToBeDestroyed(aNotifier: IEditorNotifier); 227 | var 228 | Index: Integer; 229 | begin 230 | Index := FEditorNotifiers.IndexOf(aNotifier as IInterface); 231 | if Index >= 0 then 232 | FEditorNotifiers.Delete(Index); 233 | end; 234 | 235 | {------------------------------------------------------------------------------- 236 | Name : FileClosing 237 | Info : 238 | Input : aUnitFile = 239 | 240 | Output : 241 | Result : None 242 | -------------------------------------------------------------------------------} 243 | procedure TIdePlugin.FileClosing(aUnitFile: string); 244 | var 245 | EditorNotifier: IEditorNotifier; 246 | FormNotifier: IOTAEditorNotifier; 247 | i: Integer; 248 | begin 249 | FViewManager.ViewClosed(aUnitFile); 250 | 251 | for i := 0 to FEditorNotifiers.Count -1 do 252 | begin 253 | if Supports(FEditorNotifiers[i], IOTAEditorNotifier, FormNotifier) then 254 | begin 255 | if Supports(FEditorNotifiers[i], IEditorNotifier, EditorNotifier) and (EditorNotifier.FileName = aUnitFile) then 256 | begin 257 | FEditorNotifiers.Delete(i); 258 | EditorNotifier.CleanUp; 259 | break; 260 | end; 261 | end; 262 | end; 263 | end; 264 | 265 | {------------------------------------------------------------------------------- 266 | Name : GetLogger 267 | Info : 268 | Input : 269 | Output : 270 | Result : ILogger 271 | -------------------------------------------------------------------------------} 272 | function TIdePlugin.GetLogger: ILogger; 273 | begin 274 | if not Assigned(FLogger) then 275 | FLogger := TFileLogger.Create; 276 | Result := FLogger; 277 | end; 278 | 279 | {------------------------------------------------------------------------------- 280 | Name : GetSettings 281 | Info : 282 | Input : 283 | Output : 284 | Result : ISettings 285 | -------------------------------------------------------------------------------} 286 | function TIdePlugin.GetSettings: ISettings; 287 | begin 288 | Result := FSettingsManager.Settings; 289 | end; 290 | 291 | {------------------------------------------------------------------------------- 292 | Name : GetViewManager 293 | Info : 294 | Input : 295 | Output : 296 | Result : IViewManager 297 | -------------------------------------------------------------------------------} 298 | function TIdePlugin.GetViewManager: IViewManager; 299 | begin 300 | Result := FViewManager; 301 | end; 302 | 303 | {------------------------------------------------------------------------------- 304 | Name : InstallSourceEditorNotifiers 305 | Info : 306 | Input : Module = 307 | 308 | Output : 309 | Result : None 310 | -------------------------------------------------------------------------------} 311 | procedure TIdePlugin.InstallSourceEditorNotifiers(Module: IOTAModule); 312 | var 313 | FormEditor: IOTAFormEditor; 314 | i: Integer; 315 | ModuleEditor: IOTAEditor; 316 | OtaServices: IOTAServices; 317 | SourceEditor: IOTASourceEditor; 318 | begin 319 | OtaServices := BorlandIDEServices as IOTAServices; 320 | 321 | // if module has no module files, it is a special module such as the welcome page. 322 | if Module.ModuleFileCount = 0 then 323 | begin 324 | // exclude .groupproj 325 | // register open file 326 | if not OtaServices.IsProjectGroup(Module.FileName) then 327 | Plugin.ViewManager.ViewActivated(Module.FileName); 328 | Exit; 329 | end; 330 | 331 | // attach a notifier 332 | for i := 0 to Module.ModuleFileCount - 1 do 333 | begin 334 | ModuleEditor := Module.ModuleFileEditors[i]; 335 | 336 | if Supports(ModuleEditor, IOTASourceEditor, SourceEditor) then 337 | begin 338 | // add notifier 339 | // view manager will be notified only once a view is inserted. 340 | // otherwise we would end up with several entries for open modules 341 | // that do not have a file tab associated with them (dpk, dpr files). 342 | FEditorNotifiers.Add(TSourceEditorNotifier.Create(SourceEditor) as IInterface); 343 | end 344 | else if Supports(ModuleEditor, IOTAFormEditor, FormEditor) then 345 | begin 346 | // add notifier 347 | FEditorNotifiers.Add(TFormEditorNotifier.Create(FormEditor) as IInterface); 348 | // do not register file with view manager. File must be registered only when 349 | // IEditorNotifier.ViewNotification = opInsert 350 | // otherwise modules which have been implicetely opened in the background will be 351 | // listed (visual form inheritance) 352 | end; 353 | end; 354 | end; 355 | 356 | {------------------------------------------------------------------------------- 357 | Name : KeyboardHookProc 358 | Info : Keyboard hook callback. This method is called whenever a key is pressed in the IDE. 359 | Input : Code = 360 | WordParam = 361 | LongParam = 362 | 363 | Output : 364 | Result : LongInt 365 | -------------------------------------------------------------------------------} 366 | class function TIdePlugin.KeyboardHookProc(Code: Integer; WordParam: Word; LongParam: LongInt): LongInt; 367 | var 368 | Form: TFormOpenDocs; 369 | begin 370 | // Code = HC_ACTION -> The wParam and lParam parameters contain information about a keystroke message. 371 | if (Code = HC_ACTION) then 372 | begin 373 | case WordParam of 374 | VK_TAB: 375 | begin 376 | if GetKeyState(VK_CONTROL) < 0 then 377 | begin 378 | // make sure only one instance can be displayed 379 | if not TFormOpenDocs.IsShowing and (Plugin.ViewManager.ViewCount > 1) then 380 | begin 381 | // create form 382 | Application.CreateForm(TFormOpenDocs, Form); 383 | Form.Show; 384 | 385 | // If the hook procedure processed the message, it may return a nonzero value to prevent the system from 386 | // passing the message to the rest of the hook chain or the target window procedure. 387 | Result := 1; 388 | 389 | // disable keyboard hook 390 | Plugin.DisableKeyBoardHook; 391 | Exit; 392 | end; 393 | end; 394 | end; 395 | end; 396 | end; 397 | 398 | // be a good citizen, if procedure did not process the message, it is highly recommended 399 | // that you call CallNextHookEx and return the value it returns 400 | Result := CallNextHookEx(KBHook, Code, WordParam, LongParam);; 401 | end; 402 | 403 | {------------------------------------------------------------------------------- 404 | Name : PrintMessage 405 | Info : Prints a message to the Messages View. 406 | Input : aMsg = 407 | 408 | Output : 409 | Result : None 410 | -------------------------------------------------------------------------------} 411 | procedure TIdePlugin.PrintMessage(const aMsg: string); 412 | begin 413 | (BorlandIDEServices as IOTAMessageServices).AddTitleMessage(aMsg); 414 | end; 415 | 416 | {------------------------------------------------------------------------------- 417 | Name : RemoveIDENotifier 418 | Info : 419 | Input : 420 | Output : 421 | Result : None 422 | -------------------------------------------------------------------------------} 423 | procedure TIdePlugin.RemoveIDENotifier; 424 | var 425 | Services: IOTAServices; 426 | begin 427 | Services := BorlandIDEServices as IOTAServices; 428 | if Assigned(Services) then 429 | Services.RemoveNotifier(FIDENotifierIndex); 430 | end; 431 | 432 | {------------------------------------------------------------------------------- 433 | Name : ShutDown 434 | Info : 435 | Input : 436 | Output : 437 | Result : None 438 | -------------------------------------------------------------------------------} 439 | procedure TIdePlugin.ShutDown; 440 | begin 441 | DisableKeyBoardHook; 442 | 443 | FSettingsManager.ShutDown; 444 | FViewManager.ShutDown; 445 | ClearSourceEditorNotifiers; 446 | RemoveIDENotifier; 447 | 448 | // remove editor services notifier 449 | if FEditorNotifierId > -1 then 450 | (BorlandIDEServices As IOTAEditorServices).RemoveNotifier(FEditorNotifierId); 451 | 452 | UnRegisterDesignNotification(FDesignNotification); 453 | 454 | FreeAndNil(PluginSingleton); 455 | end; 456 | 457 | {------------------------------------------------------------------------------- 458 | Name : Plugin 459 | Info : 460 | Input : 461 | Output : 462 | Result : IIdePlugin 463 | -------------------------------------------------------------------------------} 464 | function Plugin: IIdePlugin; 465 | begin 466 | Result := PluginSingleton; 467 | end; 468 | 469 | initialization 470 | PluginSingleton := TIdePlugin.Create; 471 | end. 472 | 473 | -------------------------------------------------------------------------------- /Source/CtrlTab.Interfaces.pas: -------------------------------------------------------------------------------- 1 | {=============================================================================== 2 | Project : DelphiCtrlTab_D27 3 | 4 | Name : CtrlTab.Interfaces 5 | 6 | Info : This Unit contains the class None. 7 | 8 | Copyright (c) 2020 Santiago Burbano 9 | ===============================================================================} 10 | unit CtrlTab.Interfaces; 11 | 12 | interface 13 | 14 | uses 15 | ToolsApi; 16 | 17 | type 18 | IEditorNotifier = interface; 19 | ILogger = interface; 20 | ISettings = interface; 21 | 22 | IViewManager = interface 23 | ['{53A0592B-86F9-42AF-9ABF-00A1B47E3081}'] 24 | function GetViewAt(aIndex: Integer): string; 25 | function GetViewCount: Integer; 26 | procedure ShowSourceView(aIndex: Integer); 27 | procedure ShutDown; 28 | procedure ViewActivated(const aFileName: string); 29 | procedure ViewClosed(const aViewName: string); 30 | property ViewCount: Integer read GetViewCount; 31 | end; 32 | 33 | IIdePlugin = interface 34 | ['{1DFF971B-BE77-48D2-90E8-5F507ADA128C}'] 35 | procedure ActivateKeyboardHook; 36 | procedure BootUp; 37 | procedure DesignerClosed(aFormFile: string); 38 | procedure DisableKeyBoardHook; 39 | procedure FileClosing(aFormFile: string); 40 | function GetLogger: ILogger; 41 | function GetViewManager: IViewManager; 42 | procedure InstallSourceEditorNotifiers(Module: IOTAModule); 43 | procedure PrintMessage(const aMsg: string); 44 | procedure ShutDown; 45 | procedure EditorNotifierAboutToBeDestroyed(aNotifier: IEditorNotifier); 46 | function GetSettings: ISettings; 47 | property Logger: ILogger read GetLogger; 48 | property Settings: ISettings read GetSettings; 49 | property ViewManager: IViewManager read GetViewManager; 50 | end; 51 | 52 | IEditorNotifier = interface 53 | ['{3F5EBCA8-162C-467F-A21D-4EB5800F450B}'] 54 | procedure CleanUp; 55 | function GetFileName: string; 56 | property FileName: string read GetFileName; 57 | end; 58 | 59 | ILogger = interface 60 | ['{B4510A5D-AD1F-4E08-A85B-D1CE1A115D50}'] 61 | procedure ClearLog; 62 | procedure LogMessage(aMessage: string); 63 | procedure OpenLogLocation; 64 | end; 65 | 66 | ISettings = interface 67 | ['{FCC89212-18AC-4B9A-BC86-41FF2845061E}'] 68 | function GetDialogHeight: Integer; 69 | function GetDialogWidth: Integer; 70 | procedure SetDialogHeight(const Value: Integer); 71 | procedure SetDialogWidth(const Value: Integer); 72 | property DialogHeight: Integer read GetDialogHeight write SetDialogHeight; 73 | property DialogWidth: Integer read GetDialogWidth write SetDialogWidth; 74 | 75 | end; 76 | 77 | ISettingsManager = interface 78 | ['{DB19CACB-AD8A-4A9E-9CFA-986E77B62BD8}'] 79 | procedure BootUp; 80 | function GetSettings: ISettings; 81 | procedure ShutDown; 82 | property Settings: ISettings read GetSettings; 83 | end; 84 | 85 | implementation 86 | 87 | end. 88 | 89 | -------------------------------------------------------------------------------- /Source/CtrlTab.Main.pas: -------------------------------------------------------------------------------- 1 | {=============================================================================== 2 | Project : DelphiCtrlTab_D27 3 | 4 | Name : CtrlTab.Main 5 | 6 | Info : This Unit contains the Register function. It is the entry point for 7 | this plugin. 8 | 9 | Copyright (c) 2020 Santiago Burbano 10 | ===============================================================================} 11 | unit CtrlTab.Main; 12 | 13 | interface 14 | 15 | procedure Register; 16 | 17 | implementation 18 | 19 | uses 20 | CtrlTab.IdePlugin, ToolsAPI; 21 | 22 | {------------------------------------------------------------------------------- 23 | Name : Register 24 | Info : Entry point for design time component 25 | Input : 26 | Output : 27 | Result : 28 | -------------------------------------------------------------------------------} 29 | procedure Register; 30 | begin 31 | Plugin.BootUp; 32 | end; 33 | 34 | initialization 35 | 36 | finalization 37 | Plugin.ShutDown; 38 | end. 39 | 40 | -------------------------------------------------------------------------------- /Source/CtrlTab.Settings.pas: -------------------------------------------------------------------------------- 1 | {=============================================================================== 2 | Project : DelphiCtrlTab_D27 3 | 4 | Name : CtrlTab.Settings 5 | 6 | Info : This Unit contains the class TViewManager. 7 | 8 | Copyright (c) 2020 - Santiago Burbano 9 | ===============================================================================} 10 | unit CtrlTab.Settings; 11 | 12 | interface 13 | 14 | uses 15 | CtrlTab.Interfaces, System.Classes; 16 | 17 | type 18 | TPluginSettings = class(TInterfacedObject, ISettings) 19 | private 20 | FDialogHeight: Integer; 21 | FDialogWidth: Integer; 22 | function GetDialogHeight: Integer; 23 | function GetDialogWidth: Integer; 24 | procedure SetDialogHeight(const Value: Integer); 25 | procedure SetDialogWidth(const Value: Integer); 26 | public 27 | constructor Create; 28 | end; 29 | 30 | implementation 31 | 32 | uses 33 | System.SysUtils; 34 | 35 | constructor TPluginSettings.Create; 36 | begin 37 | inherited; 38 | FDialogHeight := 0; 39 | FDialogWidth := 0; 40 | end; 41 | 42 | function TPluginSettings.GetDialogHeight: Integer; 43 | begin 44 | Result := FDialogHeight; 45 | end; 46 | 47 | function TPluginSettings.GetDialogWidth: Integer; 48 | begin 49 | Result := FDialogWidth; 50 | end; 51 | 52 | procedure TPluginSettings.SetDialogHeight(const Value: Integer); 53 | begin 54 | FDialogHeight := Value; 55 | end; 56 | 57 | procedure TPluginSettings.SetDialogWidth(const Value: Integer); 58 | begin 59 | FDialogWidth := Value; 60 | end; 61 | 62 | 63 | end. 64 | -------------------------------------------------------------------------------- /Source/CtrlTab.SettingsManager.pas: -------------------------------------------------------------------------------- 1 | {=============================================================================== 2 | Project : DelphiCtrlTab 3 | 4 | Name : CtrlTab.SettingsManager 5 | 6 | Info : This Unit contains the class TSettingsManager. Handles storage of 7 | plugin settings. 8 | 9 | Copyright (c) 2020 - Santiago Burbano 10 | ===============================================================================} 11 | unit CtrlTab.SettingsManager; 12 | 13 | interface 14 | 15 | uses 16 | CtrlTab.Interfaces, System.Classes, ToolsApi; 17 | 18 | type 19 | TSettingsManager = class(TInterfacedObject, ISettingsManager) 20 | private 21 | FSettings: ISettings; 22 | procedure BootUp; 23 | function GetSettings: ISettings; 24 | procedure LoadSettings; 25 | procedure PersistSettings; 26 | procedure ShutDown; 27 | public 28 | constructor Create; 29 | destructor Destroy; override; 30 | end; 31 | 32 | implementation 33 | 34 | uses 35 | System.SysUtils, CtrlTab.Settings, System.Win.Registry, WinApi.Windows, CtrlTab.IdePlugin; 36 | 37 | const 38 | c_CtrlTabRegistryKey = 'Software\CtrlTab'; 39 | c_Value_Height = 'height'; 40 | c_Value_Width = 'width'; 41 | 42 | constructor TSettingsManager.Create; 43 | begin 44 | inherited; 45 | FSettings := TPluginSettings.Create; 46 | end; 47 | 48 | destructor TSettingsManager.Destroy; 49 | begin 50 | inherited; 51 | end; 52 | 53 | {------------------------------------------------------------------------------- 54 | Name : BootUp 55 | Info : Called when Plugin is loading 56 | Input : 57 | Output : 58 | Result : None 59 | -------------------------------------------------------------------------------} 60 | procedure TSettingsManager.BootUp; 61 | begin 62 | LoadSettings; 63 | end; 64 | 65 | function TSettingsManager.GetSettings: ISettings; 66 | begin 67 | Result := FSettings; 68 | end; 69 | 70 | {------------------------------------------------------------------------------- 71 | Name : ShutDown 72 | Info : Called when Ide is shutting down 73 | Input : 74 | Output : 75 | Result : None 76 | -------------------------------------------------------------------------------} 77 | procedure TSettingsManager.ShutDown; 78 | begin 79 | PersistSettings; 80 | end; 81 | 82 | {------------------------------------------------------------------------------- 83 | Name : LoadSettings 84 | Info : 85 | Input : 86 | Output : 87 | Result : None 88 | -------------------------------------------------------------------------------} 89 | procedure TSettingsManager.LoadSettings; 90 | var 91 | Registry: TRegistry; 92 | begin 93 | Registry := TRegistry.Create(KEY_READ); 94 | try 95 | try 96 | Registry.RootKey := HKEY_CURRENT_USER; 97 | 98 | // do not want to create it if it doesn't exist 99 | if not Registry.OpenKey(c_CtrlTabRegistryKey, False) then Exit; 100 | 101 | if Registry.ValueExists(c_Value_Height) then 102 | FSettings.DialogHeight := Registry.ReadInteger(c_Value_Height); 103 | 104 | if Registry.ValueExists(c_Value_Height) then 105 | FSettings.DialogWidth := Registry.ReadInteger(c_Value_Width); 106 | finally 107 | Registry.Free; 108 | end; 109 | except 110 | on E:Exception do 111 | Plugin.PrintMessage(Format('Failed to restore settings: %s', [E.Message])); 112 | end; 113 | end; 114 | 115 | 116 | procedure TSettingsManager.PersistSettings; 117 | var 118 | Registry: TRegistry; 119 | begin 120 | Registry := TRegistry.Create(KEY_WRITE); 121 | try 122 | try 123 | Registry.RootKey := HKEY_CURRENT_USER; 124 | 125 | // create it if it doesn't exist 126 | if not Registry.OpenKey(c_CtrlTabRegistryKey, True) then 127 | begin 128 | Plugin.PrintMessage('Failed to persist settings.'); 129 | Exit; 130 | end; 131 | 132 | Registry.WriteInteger(c_Value_Height, FSettings.DialogHeight); 133 | Registry.WriteInteger(c_Value_Width, FSettings.DialogWidth); 134 | finally 135 | Registry.Free; 136 | end; 137 | except 138 | on E:Exception do 139 | Plugin.PrintMessage(Format('Failed to persist settings: %s', [E.Message])); 140 | end; 141 | end; 142 | 143 | 144 | end. 145 | -------------------------------------------------------------------------------- /Source/CtrlTab.SourceEditorNotifier.pas: -------------------------------------------------------------------------------- 1 | {=============================================================================== 2 | Project : DelphiCtrlTab_D27 3 | 4 | Name : CtrlTab.SourceEditorNotifier 5 | 6 | Info : This Unit contains the class TSourceEditorNotifier. 7 | 8 | Copyright (c) 2020 Santiago Burbano 9 | ===============================================================================} 10 | unit CtrlTab.SourceEditorNotifier; 11 | 12 | interface 13 | 14 | uses 15 | Classes, SysUtils, ToolsAPI, CtrlTab.Interfaces, CtrlTab.EditorNotifierBase; 16 | 17 | type 18 | TSourceEditorNotifier = class(TEditorNotifierBase, IOTANotifier, IOTAEditorNotifier, IEditorNotifier) 19 | private 20 | procedure ViewActivated(const View: IOTAEditView); 21 | procedure ViewNotification(const View: IOTAEditView; Operation: TOperation); 22 | protected 23 | public 24 | constructor Create(AEditor: IOTAEditor); reintroduce; 25 | end; 26 | 27 | implementation 28 | 29 | uses 30 | CtrlTab.IdePlugin; 31 | 32 | {------------------------------------------------------------------------------- 33 | Name : Create 34 | Info : Constructor. Register myself as a notifier for AEditor 35 | Input : AEditor = source editor 36 | Output : 37 | Result : None 38 | -------------------------------------------------------------------------------} 39 | constructor TSourceEditorNotifier.Create(AEditor: IOTAEditor); 40 | begin 41 | inherited; 42 | FIndex := FEditor.AddNotifier(Self); 43 | end; 44 | 45 | 46 | {------------------------------------------------------------------------------- 47 | Name : ViewActivated 48 | Info : This is called when the associated view is activated in the editor. 49 | Input : View = view which was activated. 50 | Output : 51 | Result : None 52 | -------------------------------------------------------------------------------} 53 | procedure TSourceEditorNotifier.ViewActivated(const View: IOTAEditView); 54 | begin 55 | // notify view manager that a view was activated. 56 | Plugin.ViewManager.ViewActivated(View.Buffer.FileName); 57 | end; 58 | 59 | {------------------------------------------------------------------------------- 60 | Name : ViewNotification 61 | Info : Called when a new edit view is created(opInsert) or destroyed(opRemove) 62 | Input : View = 63 | Operation = remove of insert 64 | Output : 65 | Result : None 66 | -------------------------------------------------------------------------------} 67 | procedure TSourceEditorNotifier.ViewNotification(const View: IOTAEditView; Operation: TOperation); 68 | begin 69 | if Operation = opRemove then 70 | begin 71 | // notify unit manager that a view has been closed. 72 | Plugin.FileClosing(View.Buffer.FileName); 73 | end 74 | else if Operation = opInsert then 75 | begin 76 | // register open file 77 | Plugin.ViewManager.ViewActivated(View.Buffer.FileName); 78 | end; 79 | end; 80 | 81 | end. 82 | 83 | -------------------------------------------------------------------------------- /Source/CtrlTab.ViewManager.pas: -------------------------------------------------------------------------------- 1 | {=============================================================================== 2 | Project : DelphiCtrlTab_D27 3 | 4 | Name : CtrlTab.ViewManager 5 | 6 | Info : This Unit contains the class TViewManager. 7 | 8 | Copyright (c) 2020 - Santiago Burbano 9 | ===============================================================================} 10 | unit CtrlTab.ViewManager; 11 | 12 | interface 13 | 14 | uses 15 | CtrlTab.Interfaces, System.Classes, ToolsApi; 16 | 17 | type 18 | TViewManager = class(TInterfacedObject, IViewManager) 19 | function GetViewAt(aIndex: Integer): string; 20 | function GetViewCount: Integer; 21 | procedure ShutDown; 22 | procedure ViewActivated(const aFileName: string); 23 | procedure ViewClosed(const aViewName: string); 24 | private 25 | FUnits: TStringList; 26 | procedure ShowSourceView(aIndex: Integer); 27 | public 28 | constructor Create; 29 | destructor Destroy; override; 30 | end; 31 | 32 | implementation 33 | 34 | uses 35 | System.SysUtils; 36 | 37 | constructor TViewManager.Create; 38 | begin 39 | inherited; 40 | FUnits := TStringList.Create; 41 | end; 42 | 43 | destructor TViewManager.Destroy; 44 | begin 45 | inherited; 46 | FreeAndNil(FUnits); 47 | end; 48 | 49 | function TViewManager.GetViewAt(aIndex: Integer): string; 50 | begin 51 | Result := FUnits[aIndex]; 52 | end; 53 | 54 | function TViewManager.GetViewCount: Integer; 55 | begin 56 | Result := FUnits.Count; 57 | end; 58 | 59 | procedure TViewManager.ShowSourceView(aIndex: Integer); 60 | var 61 | FileToShow: string; 62 | i: Integer; 63 | j: Integer; 64 | ModuleEditor: IOTAEditor; 65 | ModuleServices: IOTAModuleServices; 66 | OpenModule: IOTAModule; 67 | SpecialModule: IOTAModule; 68 | begin 69 | FileToShow := FUnits[aIndex]; 70 | SpecialModule := nil; 71 | 72 | // find open module and show it 73 | ModuleServices := BorlandIDEServices as IOTAModuleServices; 74 | for i := 0 to ModuleServices.ModuleCount - 1 do 75 | begin 76 | OpenModule := ModuleServices.Modules[i]; 77 | 78 | // loop editors 79 | for j := 0 to OpenModule.ModuleFileCount - 1 do 80 | begin 81 | ModuleEditor := OpenModule.ModuleFileEditors[j]; 82 | if ModuleEditor.FileName = FileToShow then 83 | begin 84 | ModuleEditor.Show; 85 | Exit; 86 | end; 87 | end; 88 | 89 | // Could be a special module (Welcome Page) 90 | if OpenModule.FileName = FileToShow then 91 | begin 92 | SpecialModule := OpenModule; 93 | end; 94 | end; 95 | 96 | // Could be a special module (Welcome Page) 97 | if Assigned(SpecialModule) then 98 | SpecialModule.Show; 99 | end; 100 | 101 | procedure TViewManager.ShutDown; 102 | begin 103 | FUnits.Clear; 104 | end; 105 | 106 | 107 | procedure TViewManager.ViewActivated(const aFileName: string); 108 | var 109 | Index: Integer; 110 | begin 111 | Index := FUnits.IndexOf(aFileName); 112 | if Index = 0 then Exit; 113 | // remove if already in list 114 | if Index >= 0 then 115 | FUnits.Delete(Index); 116 | // add to top 117 | FUnits.Insert(0, aFileName); 118 | end; 119 | 120 | procedure TViewManager.ViewClosed(const aViewName: string); 121 | var 122 | Index: Integer; 123 | begin 124 | Index := FUnits.IndexOf(aViewName); 125 | if Index >= 0 then 126 | FUnits.Delete(Index); 127 | end; 128 | 129 | end. 130 | -------------------------------------------------------------------------------- /binaries/Release/DelphiCtrlTab_D23.bpl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/santiagoIT/DelphiCtrlTab/f9f547b810af70e22c9009a7d36da79b38145f6f/binaries/Release/DelphiCtrlTab_D23.bpl -------------------------------------------------------------------------------- /binaries/Release/DelphiCtrlTab_D26.bpl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/santiagoIT/DelphiCtrlTab/f9f547b810af70e22c9009a7d36da79b38145f6f/binaries/Release/DelphiCtrlTab_D26.bpl -------------------------------------------------------------------------------- /binaries/Release/DelphiCtrlTab_D27.bpl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/santiagoIT/DelphiCtrlTab/f9f547b810af70e22c9009a7d36da79b38145f6f/binaries/Release/DelphiCtrlTab_D27.bpl -------------------------------------------------------------------------------- /binaries/Release/DelphiCtrlTab_D28.bpl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/santiagoIT/DelphiCtrlTab/f9f547b810af70e22c9009a7d36da79b38145f6f/binaries/Release/DelphiCtrlTab_D28.bpl -------------------------------------------------------------------------------- /docs/images/DelphiCtrlTab.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/santiagoIT/DelphiCtrlTab/f9f547b810af70e22c9009a7d36da79b38145f6f/docs/images/DelphiCtrlTab.jpg -------------------------------------------------------------------------------- /msbuild/.targets/DelphiCtrlTab.Compile.targets: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | -------------------------------------------------------------------------------- /msbuild/DelphiCtrlTab.proj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /msbuild/buildAll.bat: -------------------------------------------------------------------------------- 1 | @echo off 2 | 3 | SET batPath=%~dp0.. 4 | 5 | echo BATPATH: %batPath% 6 | 7 | 8 | 9 | 10 | REM MS BUILD 11 | SET MSB=C:\Program Files (x86)\Microsoft Visual Studio\2017\Professional\MSBuild\15.0\Bin 12 | IF NOT EXIST "%MSB%" SET MSB=C:\Program Files (x86)\Microsoft Visual Studio\2017\Enterprise\MSBuild\15.0\Bin 13 | IF NOT EXIST "%MSB%" SET MSB=C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\MSBuild\15.0\Bin 14 | 15 | REM Delphi 11 - Alexandria 16 | SET BDSVERSION=22.0 17 | SET BDS=C:\Program Files (x86)\Embarcadero\Studio\%BDSVERSION% 18 | IF NOT EXIST "%BDS%" SET BDS=C:\Program Files (x86)\Embarcadero\Studio\%BDSVERSION% 19 | 20 | SET BDSCOMMONDIR=C:\Users\Public\Documents\Embarcadero\Studio\%BDSVERSION% 21 | "%MSB%\MSBuild.exe" DelphiCtrlTab.proj /t:CompileD28 /p:OutDir=%batPath%\build\bin\ 22 | 23 | REM Delphi Sydney 24 | SET BDSVERSION=21.0 25 | SET BDS=C:\Program Files (x86)\Embarcadero\Studio\%BDSVERSION% 26 | IF NOT EXIST "%BDS%" SET BDS=C:\Program Files (x86)\Embarcadero\Studio\%BDSVERSION% 27 | 28 | SET BDSCOMMONDIR=C:\Users\Public\Documents\Embarcadero\Studio\%BDSVERSION% 29 | "%MSB%\MSBuild.exe" DelphiCtrlTab.proj /t:CompileD27 /p:OutDir=%batPath%\build\bin\ 30 | 31 | REM Delphi Rio 32 | SET BDSVERSION=20.0 33 | SET BDS=C:\Program Files (x86)\Embarcadero\Studio\%BDSVERSION% 34 | IF NOT EXIST "%BDS%" SET BDS=C:\Program Files (x86)\Embarcadero\Studio\%BDSVERSION% 35 | 36 | SET BDSCOMMONDIR=C:\Users\Public\Documents\Embarcadero\Studio\%BDSVERSION% 37 | "%MSB%\MSBuild.exe" DelphiCtrlTab.proj /t:CompileD26 /p:OutDir=%batPath%\build\bin\ 38 | 39 | REM Delphi Seattle 40 | SET BDSVERSION=17.0 41 | SET BDS=C:\Program Files (x86)\Embarcadero\Studio\%BDSVERSION% 42 | IF NOT EXIST "%BDS%" SET BDS=C:\Program Files (x86)\Embarcadero\Studio\%BDSVERSION% 43 | 44 | SET BDSCOMMONDIR=C:\Users\Public\Documents\Embarcadero\Studio\%BDSVERSION% 45 | "%MSB%\MSBuild.exe" DelphiCtrlTab.proj /t:CompileD23 /p:OutDir=%batPath%\build\bin\ 46 | 47 | 48 | IF "%4" NEQ "NOPAUSE" pause --------------------------------------------------------------------------------