• R/O
  • SSH
  • HTTPS

akdf: Commit


Commit MetaInfo

Revision538 (tree)
Time2021-04-03 02:25:45
Authorderekwildstar

Log Message

Release temporária (não a baixe)

KRK.Vcl.Forms.pas
¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯

Adicionada seção finalization para desregistrar Style Hooks

KRK.ToolsApi.Components.Notifier.pas
¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯

Removida a propriedade NotifierIndex

Change Summary

Incremental Difference

--- trunk/dtp/Experts/prj/Delphi 26 (Delphi Rio)/KRKExpertsD.dproj (revision 537)
+++ trunk/dtp/Experts/prj/Delphi 26 (Delphi Rio)/KRKExpertsD.dproj (revision 538)
@@ -52,6 +52,7 @@
5252 <DCC_UsePackage>rtl;KRKCustomModulesR;KRKOTAComponentsR;PNGComponentsR;KRKLib;$(DCC_UsePackage)</DCC_UsePackage>
5353 <Debugger_HostApplication>C:\Program Files (x86)\Embarcadero\Studio\20.0\bin\bds.exe</Debugger_HostApplication>
5454 <Debugger_RunParams>-r KRKExperts</Debugger_RunParams>
55+ <Debugger_DebugSourcePath>D:\Desenvolvimento\Delphi\Componentes\PNGComponents\src\;$(Debugger_DebugSourcePath)</Debugger_DebugSourcePath>
5556 </PropertyGroup>
5657 <PropertyGroup Condition="'$(Base_Win64)'!=''">
5758 <DCC_UsePackage>rtl;$(DCC_UsePackage)</DCC_UsePackage>
--- trunk/dtp/Experts/src/D14+/KX.EditorSubViews.pas (revision 537)
+++ trunk/dtp/Experts/src/D14+/KX.EditorSubViews.pas (revision 538)
@@ -126,6 +126,9 @@
126126 // ser inconveniente
127127 Module.Show;
128128
129+// Continue aqui verificando a melhor forma de abrir/criar/salvar a documentação
130+// veja se consegue se livrar do Module.Show
131+
129132 // codigo original que não faz uso de tdocument
130133 // if FileExists(FileName) then
131134 // (AViewObject as TFRAMDocumentation).Load(FileName)
@@ -251,13 +254,13 @@
251254 end;
252255
253256 procedure TDAMOEditorSubviews.KEDSDocumentationHide(const AContext: IInterface; AViewObject: TObject);
254-var
255- EditorViewService: IOTAEditorViewServices;
256- Module: IOTAModule;
257- FileName: String;
257+//var
258+// EditorViewService: IOTAEditorViewServices;
259+// Module: IOTAModule;
260+// FileName: String;
258261 begin
259- if Assigned(AContext) and GetIOTAEditorViewServices(EditorViewService) and EditorViewService.ContextToModule(AContext, Module) then
260- begin
262+// if Assigned(AContext) and GetIOTAEditorViewServices(EditorViewService) and EditorViewService.ContextToModule(AContext, Module) then
263+// begin
261264 // Neste ponto do código é garantida a existência de um documento na lista
262265 // de documentos. No caso, o documento aberto atualmente está em
263266 // FCurrentDocument
@@ -275,7 +278,7 @@
275278 // IDYES: (AViewObject as TFRAMDocumentation).RIEDDocumentation.Lines.SaveToFile(FileName);
276279 // IDCANCEL: Abort; { Impede o ocultamento da aba }
277280 // end;
278- end;
281+// end;
279282 end;
280283
281284 // Não sei bem para que isso serve. Em ToolsAPI.pas existe um comentário a
--- trunk/dtp/Experts/src/D14+/KX.Notifiers.pas (revision 537)
+++ trunk/dtp/Experts/src/D14+/KX.Notifiers.pas (revision 538)
@@ -43,7 +43,7 @@
4343 procedure MNUISubItem1Click(Sender: TObject);
4444 procedure MNUISubItem2Click(Sender: TObject);
4545 procedure PUMEPopup(Sender: TObject);
46- procedure KMONAllowSave(out AAllowSave: Boolean);
46+ procedure KMONAllowSave(AModule: IOTAModule; out AAllowSave: Boolean);
4747 private
4848 { Private declarations }
4949 procedure CreateLanguagePanel(AStatusBar: TStatusBar);
@@ -272,6 +272,9 @@
272272 if Assigned(GetINTAEditorServices.TopEditWindow) and (GetINTAEditorServices.TopEditWindow.StatusBar.ComponentCount = 1) then
273273 UpdateLanguageInfo(GetINTAEditorServices.TopEditWindow.StatusBar,'');
274274
275+ OutputDebugString('======> FileNotification externo configurado pelo usuário');
276+
277+
275278 // o certo é criar uma nova instância de KMON para cada arquivo aberto e
276279 // manter uma lista que associa o modulo a seu notificador. Considerando que
277280 // mais de um modulo pode ser aberto, alguém deve manter a referencia para
@@ -302,10 +305,10 @@
302305 // end;
303306 end;
304307
305-procedure TDAMONotifiers.KMONAllowSave(out AAllowSave: Boolean);
308+procedure TDAMONotifiers.KMONAllowSave(AModule: IOTAModule; out AAllowSave: Boolean);
306309 begin
307-// AAllowSave := False;
308-// ShowMessage('Salvando um módulo, aqui verifica-se os arquivos que este módulo gerencia e faz alguma coisa');
310+ // VERIFIQUE SE O MODULO FOI MODIFICADO ANTES DE SALVAR, POIS ESTE EVENTO É CHAMADO ATÉ MESMO QUANDO SE FECHA UM MODULO QUE NÃO TEVE SEU BUFFER MODIFICADO
311+ // ShowMessage('Salve o arquivo ' + ChangeFileExt(AModule.FileName,'.rtf'));
309312 end;
310313
311314 procedure TDAMONotifiers.KPMNAddMenu(const AProject: IOTAProject; const AIdentList: TStrings; const AProjectManagerMenuList: IInterfaceList; const AIsMultiSelect: Boolean);
--- trunk/rtp/prj/Delphi 26 (Delphi Rio)/KRKLib.dproj (revision 537)
+++ trunk/rtp/prj/Delphi 26 (Delphi Rio)/KRKLib.dproj (revision 538)
@@ -21,10 +21,9 @@
2121 <PropertyGroup Condition="'$(Base)'!=''">
2222 <RuntimeOnlyPackage>true</RuntimeOnlyPackage>
2323 <DCC_OutputNeverBuildDcps>true</DCC_OutputNeverBuildDcps>
24- <DllPrefixDefined>true</DllPrefixDefined>
2524 <DllSuffix>260</DllSuffix>
2625 <DCC_Description>Anak Krakatoa Library</DCC_Description>
27- <DCC_UnitSearchPath>..\..\res;..\..\res\dfm;$(DCC_UnitSearchPath)</DCC_UnitSearchPath>
26+ <DCC_UnitSearchPath>..\..\res;..\..\res\dfm;C:\Program Files (x86)\Embarcadero\Studio\20.0\source\vcl;C:\Program Files (x86)\Embarcadero\Studio\20.0\source\rtl\win;C:\Program Files (x86)\Embarcadero\Studio\20.0\source\rtl\sys;$(DCC_UnitSearchPath)</DCC_UnitSearchPath>
2827 <DCC_Namespace>Data.Win;Datasnap.Win;Web.Win;Soap.Win;Xml.Win;Bde;Vcl;System;Xml;Data;Datasnap;Web;Soap;Vcl.Imaging;Vcl.Touch;Vcl.Samples;Vcl.Shell;Winapi;System.Win;$(DCC_Namespace)</DCC_Namespace>
2928 <GenPackage>true</GenPackage>
3029 <GenDLL>true</GenDLL>
@@ -38,6 +37,7 @@
3837 <VerInfo_IncludeVerInfo>true</VerInfo_IncludeVerInfo>
3938 <VerInfo_Keys>CompanyName=;FileDescription=$(MSBuildProjectName);FileVersion=1.0.0.0;InternalName=;LegalCopyright=;LegalTrademarks=;OriginalFilename=;ProductName=$(MSBuildProjectName);ProductVersion=1.0.0.0;Comments=;ProgramID=com.embarcadero.$(MSBuildProjectName)</VerInfo_Keys>
4039 <VerInfo_Locale>1033</VerInfo_Locale>
40+ <DllPrefixDefined>false</DllPrefixDefined>
4141 </PropertyGroup>
4242 <ItemGroup>
4343 <DelphiCompile Include="$(MainSource)">
--- trunk/rtp/src/ToolsAPI/Components/KRK.ToolsApi.Components.EditServicesNotifier.pas (revision 537)
+++ trunk/rtp/src/ToolsAPI/Components/KRK.ToolsApi.Components.EditServicesNotifier.pas (revision 538)
@@ -18,6 +18,16 @@
1818 TOnWindowNotification = procedure (const AEditWindow: INTAEditWindow; AOperation: TOperation) of object;
1919 TOnWindowShow = procedure (const AEditWindow: INTAEditWindow; AShow: Boolean; ALoadedFromDesktop: Boolean) of object;
2020
21+ // A observação abaixo é sobre o IOTAEditorNotifier. Não tem a ver com a
22+ // classe da unit atual, é apenas uma observação que fala que como existe mais
23+ // de um editor aberto, cada um deles precisa ter seu próprio notificador e
24+ // deve haver mais de uma instância de um componente que implemente
25+ // IOTAEditorNotifier (ainda não criado!) ou haver apenas um componente deste
26+ // tipo sendo compartilhado como notificador para vários editores diferentes.
27+ // Esta segunda forma deve ser a correta (um mesmo componente para vários
28+ // editores) e para que ela seja possível, o componente não pode gerenciar seu
29+ // próprio "NotifierIndex".
30+
2131 // Para que a interface IOTAEditorNotifier possa ser registrada, é necessária
2232 // uma instância de IOTAEditor, o qual possui um método AddNotifier
2333 // responsável pelo registro. IOTAEditor NÃO É uma interface global disponível
@@ -33,17 +43,21 @@
3343 // ModuleFileEditors) e assim, para cada um deles, executar o método
3444 // AddNotifier. Isso é apenas uma forma de fazer. Devem haver outros
3545 // notificadores que consigam, em algum ponto, fornecer um IOTAEditor um, no
36- // caso, uma lista deles. No futuro, caso seja útil um componente em cima de
37- // IOTAEditorNotifier, crie propriedades para conectá-lo a outros editores
38- // (como o TKRKOTAIDENotifier) de forma que tudo o que foi explicado aqui,
39- // ocorra automaticamente. A interface INTAEditServicesNotifier (abaixo)
46+ // caso, uma lista deles. A interface INTAEditServicesNotifier (abaixo)
4047 // funciona no Delphi 2006 e aparentemente ela substitui com vantagem a
4148 // interface IOTAEditorNotifier
4249
4350 //: Classe do componente que implementa a interface INTAEditServicesNotifier
51+ //: responsável por notificar a respeito de váris eventos relacionados a
52+ //: editores abertos na IDE
53+ //: ATENÇÃO: Este componente se autoregistra como notificador para
54+ //: IOTAEditorServices, por isso ele mesmo gerencia seu índice de notificador.
55+ //: Mais de um desse componente pode ser usado por projeto, mas isso é
56+ //: desnecessário, redundante e desaconselhável. Um só é suficiente!
4457 TKRKCustomNTAEditServicesNotifier = class(TKRKOTANotifier
4558 ,INTAEditServicesNotifier)
4659 private
60+ FNotifierIndex: Integer;
4761 FOnWindowNotification: TOnWindowNotification;
4862 FOnWindowActivated: TOnWindowActivated;
4963 FOnEditorViewModified: TOnEditorViewModified;
@@ -53,6 +67,9 @@
5367 FOnDockFormUpdated: TOnDockFormUpdated;
5468 FOnDockFormVisibleChanged: TOnDockFormVisibleChanged;
5569 FOnDockFormRefresh: TOnDockFormRefresh;
70+ // Manipulador do evento OnDestroyed, usado aqui para TAMBÉM desregistrar o
71+ // notificador
72+ procedure DoDestroyed(ASender: TObject);
5673
5774 { INTAEditServicesNotifier }
5875 procedure DockFormRefresh(const EditWindow: INTAEditWindow; DockForm: TDockableForm);
@@ -88,6 +105,7 @@
88105 property OnWindowNotification: TOnWindowNotification read FOnWindowNotification write FOnWindowNotification;
89106 property OnWindowShow: TOnWindowShow read FOnWindowShow write FOnWindowShow;
90107 public
108+ constructor Create(AOwner: TComponent); override;
91109 destructor Destroy; override;
92110 end;
93111
@@ -110,10 +128,16 @@
110128
111129 { TKRKOTAEditorNotifier }
112130
131+constructor TKRKCustomNTAEditServicesNotifier.Create(AOwner: TComponent);
132+begin
133+ inherited;
134+ OnDestroyed := DoDestroyed;
135+end;
136+
113137 destructor TKRKCustomNTAEditServicesNotifier.Destroy;
114138 begin
115139 if not (csDesigning in ComponentState) then
116- RemoveNTAEditServicesNotifier(NotifierIndex);
140+ RemoveNTAEditServicesNotifier(FNotifierIndex);
117141
118142 inherited;
119143 end;
@@ -135,6 +159,18 @@
135159 if Assigned(FOnDockFormVisibleChanged) then
136160 FOnDockFormVisibleChanged(EditWindow,DockForm);
137161 end;
162+// O evento OnDestroyed acontece antes da destruição da classe, portanto, caso
163+// este evento seja disparado, precisamos configurar NotifierIndex como -1, de
164+// forma que no destrutor regular da classe não seja feita a remoção novamente,
165+// o que invariavelmente levaria a uma exceção
166+procedure TKRKCustomNTAEditServicesNotifier.DoDestroyed(ASender: TObject);
167+begin
168+ if not (csDesigning in ComponentState) then
169+ begin
170+ RemoveNTAEditServicesNotifier(FNotifierIndex);
171+ FNotifierIndex := -1;
172+ end;
173+end;
138174
139175 procedure TKRKCustomNTAEditServicesNotifier.EditorViewActivated(const EditWindow: INTAEditWindow; const EditView: IOTAEditView);
140176 begin
@@ -153,7 +189,7 @@
153189 inherited;
154190
155191 if not (csDesigning in ComponentState) then
156- NotifierIndex := AddNTAEditServicesNotifier(Self);
192+ FNotifierIndex := AddNTAEditServicesNotifier(Self);
157193 end;
158194
159195 procedure TKRKCustomNTAEditServicesNotifier.WindowActivated(const EditWindow: INTAEditWindow);
--- trunk/rtp/src/ToolsAPI/Components/KRK.ToolsApi.Components.EditorSubView.pas (revision 537)
+++ trunk/rtp/src/ToolsAPI/Components/KRK.ToolsApi.Components.EditorSubView.pas (revision 538)
@@ -34,6 +34,7 @@
3434 FPriority: TPriority;
3535 FOnEditAction: TOnEditAction;
3636 FEditStates: TEditState;
37+
3738 FOnHandles: TOnHandles;
3839 FOnDisplay: TOnDisplay;
3940 FOnHide: TOnHide;
@@ -103,6 +104,7 @@
103104
104105 {$IF CompilerVersion >= 21} { Delphi 2010 }
105106 uses SysUtils
107+ , Windows
106108 , KRK.ToolsAPI;
107109
108110 { TKRKOTAEditorSubview }
@@ -117,11 +119,32 @@
117119
118120 destructor TKRKCustomOTAEditorSubview.Destroy;
119121 begin
122+ // Não é necessário verificar FActive ou se o componente está em runtime
123+ // porque FRegisteredEditorSubView faz o papel de seletor. Quando ele é
124+ // diferente de nil, o método abaixo atual, quando é igual a nil, nada
125+ // acontece
120126 UnRegisterNTACustomEditorSubView(FRegisteredEditorSubView);
121127
122128 inherited;
123129 end;
124130
131+procedure TKRKCustomOTAEditorSubview.Loaded;
132+begin
133+ inherited;
134+ // O código de registro só pode ficar no construtor da classe quando ele não
135+ // depende de propriedades que o usuário pode ou precisa alterar no componente
136+ // e que afetam tal registro, por exemplo, o registro da subvisão depende do
137+ // evento OnGetFrameClass que precisa ser definido pelo usuário para indicar a
138+ // classe do frame que vai aparecer na subvisão. O evento só estará sendo
139+ // manipulado pelo seu manipulador definido em designtime, APÓS o componente
140+ // carregar todas as suas propriedades, por este motivo o registro precisa ser
141+ // feito aqui, no método Loaded, após "inherited" e não no construtor, pois no
142+ // construtor os eventos ainda não foram ligados aos manipuladores definidos
143+ // em designtime
144+ if not (csDesigning in ComponentState) then
145+ FRegisteredEditorSubView := RegisterNTACustomEditorSubView(Self);
146+end;
147+
125148 procedure TKRKCustomOTAEditorSubview.Display(const AContext: IInterface; AViewObject: TObject);
126149 begin
127150 if Assigned(FOnDisplay) then
@@ -162,7 +185,7 @@
162185 if Assigned(FOnGetFrameClass) then
163186 Result := FOnGetFrameClass
164187 else
165- raise Exception.Create('A classe do frame da sub-visão não foi definida. Por favor implemente o evento OnGetFrameClass');
188+ raise Exception.Create('A classe do frame da sub-visão não foi definida. Por favor implemente o evento ' + Self.Name + '. OnGetFrameClass');
166189 end;
167190
168191 function TKRKCustomOTAEditorSubview.GetPriority: Integer;
@@ -199,14 +222,6 @@
199222 FOnHide(AContext,AViewObject);
200223 end;
201224
202-procedure TKRKCustomOTAEditorSubview.Loaded;
203-begin
204- inherited;
205-
206- if not (csDesigning in ComponentState) then
207- FRegisteredEditorSubView := RegisterNTACustomEditorSubView(Self);
208-end;
209-
210225 procedure TKRKCustomOTAEditorSubview.ViewClosed(const AContext: IInterface; AViewObject: TObject);
211226 begin
212227 if Assigned(FOnViewClosed) then
--- trunk/rtp/src/ToolsAPI/Components/KRK.ToolsApi.Components.IDENotifier.pas (revision 537)
+++ trunk/rtp/src/ToolsAPI/Components/KRK.ToolsApi.Components.IDENotifier.pas (revision 538)
@@ -12,32 +12,31 @@
1212 TOnAfterCompile = procedure (const AProject: IOTAProject; ASucceeded: Boolean; AIsCodeInsight: Boolean) of object;
1313
1414 //: Classe do componente que implementa a interface IOTAIDENotifier
15+ //: ATENÇÃO: Este componente se autoregistra como notificador para
16+ //: IOTAServices, por isso ele mesmo gerencia seu índice de notificador.
17+ //: Mais de um desse componente pode ser usado por projeto, mas isso é
18+ //: desnecessário, redundante e desaconselhável. Um só é suficiente!
1519 TKRKCustomOTAIDENotifier = class(TKRKOTANotifier
1620 ,IOTAIDENotifier
1721 ,IOTAIDENotifier50
1822 ,IOTAIDENotifier80)
1923 private
24+ FNotifierIndex: Integer;
2025 FOnBeforeCompile: TOnBeforeCompile;
2126 FOnFileNotification: TOnFileNotification;
2227 FOnAfterCompile: TOnAfterCompile;
23- // Manipulador do evento OnDestroyed, usado aqui para TAMBÉM desregistrar o
24- // notificador
25- procedure DoDestroyed(ASender: TObject);
26-
28+ { IOTANotifier }
29+ procedure Destroyed;
2730 { IOTAIDENotifier }
2831 procedure FileNotification(NotifyCode: TOTAFileNotification; const FileName: string; var Cancel: Boolean);
2932 procedure BeforeCompile(const Project: IOTAProject; var Cancel: Boolean); overload;
3033 procedure AfterCompile(Succeeded: Boolean); overload;
31-
3234 { IOTAIDENotifier50 }
3335 procedure BeforeCompile(const Project: IOTAProject; IsCodeInsight: Boolean; var Cancel: Boolean); overload;
3436 procedure AfterCompile(Succeeded: Boolean; IsCodeInsight: Boolean); overload;
35-
3637 { IOTAIDENotifier80 }
3738 procedure AfterCompile(const Project: IOTAProject; Succeeded: Boolean; IsCodeInsight: Boolean); overload;
3839 protected
39- procedure Loaded; override;
40-
4140 property OnFileNotification: TOnFileNotification read FOnFileNotification write FOnFileNotification;
4241 property OnBeforeCompile: TOnBeforeCompile read FOnBeforeCompile write FOnBeforeCompile;
4342 property OnAfterCompile: TOnAfterCompile read FOnAfterCompile write FOnAfterCompile;
@@ -89,42 +88,34 @@
8988 constructor TKRKCustomOTAIDENotifier.Create(AOwner: TComponent);
9089 begin
9190 inherited;
92- OnDestroyed := DoDestroyed;
91+ if not (csDesigning in ComponentState) then
92+ FNotifierIndex := AddOTAIDENotifier(Self);
9393 end;
9494
9595 destructor TKRKCustomOTAIDENotifier.Destroy;
9696 begin
9797 if not (csDesigning in ComponentState) then
98- RemoveOTAIDENotifier(NotifierIndex);
98+ RemoveOTAIDENotifier(FNotifierIndex);
9999
100100 inherited;
101101 end;
102-
103-procedure TKRKCustomOTAIDENotifier.FileNotification(NotifyCode: TOTAFileNotification; const FileName: string; var Cancel: Boolean);
104-begin
105- if Assigned(FOnFileNotification) then
106- FOnFileNotification(NotifyCode,FileName,Cancel);
107-end;
108-
109-procedure TKRKCustomOTAIDENotifier.Loaded;
110-begin
111- inherited;
112-
113- if not (csDesigning in ComponentState) then
114- NotifierIndex := AddOTAIDENotifier(Self);
115-end;
116-// O evento OnDestroyed acontece antes da destruição da classe, portanto, caso
117-// este evento seja disparado, precisamos configurar NotifierIndex como -1, de
102+// O método Destroyed é executado antes da destruição da classe, portanto, caso
103+// este método seja executado, precisamos configurar NotifierIndex como -1, de
118104 // forma que no destrutor regular da classe não seja feita a remoção novamente,
119105 // o que invariavelmente levaria a uma exceção
120-procedure TKRKCustomOTAIDENotifier.DoDestroyed(ASender: TObject);
106+procedure TKRKCustomOTAIDENotifier.Destroyed;
121107 begin
122108 if not (csDesigning in ComponentState) then
123109 begin
124- RemoveOTAIDENotifier(NotifierIndex);
125- NotifierIndex := -1;
110+ RemoveOTAIDENotifier(FNotifierIndex);
111+ FNotifierIndex := -1;
126112 end;
113+end;
127114
115+procedure TKRKCustomOTAIDENotifier.FileNotification(NotifyCode: TOTAFileNotification; const FileName: string; var Cancel: Boolean);
116+begin
117+ if Assigned(FOnFileNotification) then
118+ FOnFileNotification(NotifyCode,FileName,Cancel);
128119 end;
129120
130121 end.
--- trunk/rtp/src/ToolsAPI/Components/KRK.ToolsApi.Components.ModuleNotifier.pas (revision 537)
+++ trunk/rtp/src/ToolsAPI/Components/KRK.ToolsApi.Components.ModuleNotifier.pas (revision 538)
@@ -6,53 +6,21 @@
66 // https://www.davidghoyle.co.uk/WordPress/?page_id=1251
77 interface
88
9-uses KRK.ToolsApi.Components.Notifier
10- , ToolsApi
11- , Classes;
9+uses
10+ Classes, ToolsApi, KRK.ToolsApi.Components.IDENotifier;
1211
1312 type
14- TOnCheckOverwrite = procedure (out AAllowOverwrite: Boolean) of object;
15- TOnModuleRenamed = procedure (const ANewName: String) of object;
16- TOnSetSaveFileName = procedure (const AFileName: String) of object;
17- TOnAllowSave = procedure (out AAllowSave: Boolean) of object;
18- TOnAfterRename = procedure (const AOldFileName: String; const ANewFileName: String) of object;
19- TOnBeforeRename = TOnAfterRename;
13+ TOnCheckOverwrite = procedure (AModule: IOTAModule; out AAllowOverwrite: Boolean) of object;
14+ TOnModuleRenamed = procedure (AModule: IOTAModule; const ANewName: String) of object;
15+ TOnAllowSave = procedure (AModule: IOTAModule; out AAllowSave: Boolean) of object;
16+ TOnSetSaveFileName = procedure (AModule: IOTAModule; const AFileName: String) of object;
17+ TOnBeforeRename = procedure (AModule: IOTAModule; const AOldFileName: String; const ANewFileName: String) of object;
18+ TOnAfterRename = TOnBeforeRename;
2019
21- // A interface IOTAModuleNotifier80 possui duas propriedades, as quais estão
22- // associadas a dois métodos. As interfaces de notificação normalmente nos
23- // notificam algo, portanto, dados "saem" destas interfaces. Este é o
24- // funcionamento normal. Algumas interfaces, como IOTAModuleNotifier80 e
25- // INTACustomEditorSubView possuem propriedades somente leitura associadas a
26- // métodos. Isso significa que a IDE lê estas propriedades e é por isso que
27- // precisamos implementar seus métodos associados (métodos get). Estes métodos
28- // get não serão chamados pela IDE, eles existem na interface para nos obrigar
29- // a implementá-los, pois a IDE fará uso apenas das propriedades somente
30- // leitura, as quais obtém seus dados a partir dos métodos "get". Nós é quem
31- // precisamos, nestes métodos, retornar algo para a IDE, fazendo o caminho
32- // oposto de uma interface de notificação tradicional. Na classe abaixo
33- // FOverwriteFileNames é uma lista que pode ser modificada em tempo de projeto
34- // no componente. Ao preencher esta lista, os métodos GetOverwriteFileName e
35- // GetOverwriteFileNameCount retornarão para a IDE as informações que ela
36- // precisa quando a IDE acessar as propriedades OverwriteFileNameCount e
37- // OverwriteFileNames.
38-
39- // ATENÇÃO: Me parece estranho, nesta interface de notificação precisarmos
40- // informar nomes de arquivo e sua quantidade, sendo que isso o módulo em
41- // si já parece conhecer. Talvez isso seja algo para configurar corretamente o
42- // notificador. Se isso for verdade, a OverwriteFileNames não deve existir,
43- // pois seus dados devem ser pegos diretamente do modulo que registra esse
44- // notificador. Verifique isso depois, pois acho que há como saber os arquivos
45- // e quantidade de arquivos que um módulo manipula!
46-
47- //: Classe do componente que implementa a interface IOTAModuleNotifier
48- TKRKCustomOTAModuleNotifier = class(TKRKOTANotifier
49- ,IOTAModuleNotifier
50- ,IOTAModuleNotifier80
51- ,IOTAModuleNotifier90)
52-
20+ // todos os componentes notificadores instanciados gerenciam seu proprio indice de notificador
21+ // criará uma instância de notificador para cada módulo sendo aberto
22+ TKRKCustomOTAModuleNotifier = class(TComponent)
5323 private
54- FModule: IOTAMOdule;
55- FOverwriteFileNames: TStrings;
5624 FOnCheckOverwrite: TOnCheckOverwrite;
5725 FOnModuleRenamed: TOnModuleRenamed;
5826 FOnSetSaveFileName: TOnSetSaveFileName;
@@ -59,22 +27,22 @@
5927 FOnAllowSave: TOnAllowSave;
6028 FOnAfterRename: TOnAfterRename;
6129 FOnBeforeRename: TOnBeforeRename;
62- procedure DoDestroyed(ASender: TObject);
6330
64- { IOTAModuleNotifier }
65- function CheckOverwrite: Boolean;
66- procedure ModuleRenamed(const NewName: string);
67- { IOTAModuleNotifier80 }
68- procedure SetSaveFileName(const FileName: string);
69- function GetOverwriteFileName(Index: Integer): string;
70- function GetOverwriteFileNameCount: Integer;
71- function AllowSave: Boolean;
72- { IOTAModuleNotifier90 }
73- procedure AfterRename(const OldFileName: string; const NewFileName: string);
74- procedure BeforeRename(const OldFileName: string; const NewFileName: string);
75- { TKRKCustomOTAModuleNotifier }
76- procedure SetOverwriteFileNames(const Value: TStrings);
31+ FNotifiers: TInterfaceList;
32+ FIDENotifier: TKRKOTAIDENotifier;
33+ FUserDoFileNotification: TOnFileNotification;
34+ //: Este é o método manipulador do evento OnFileNotification. A classe atual
35+ //: usa um TKRKOTAIDENotifier interno porque precisa do evento
36+ //: OnFileNotification para adicionar um notificador para cada IOTAModule
37+ //: aberto. Este método chama internamente manipulador do evento
38+ //: OnFileNotification que porventura tenha sido configurado pelo usuário, o
39+ //: qual tem sua referência em FUserDoFileNotification
40+ procedure DoFileNotification(ANotifyCode: TOTAFileNotification; const AFileName: string; var ACancel: Boolean);
7741 protected
42+ procedure Loaded; override;
43+
44+ property IDENotifier: TKRKOTAIDENotifier read FIDENotifier;
45+
7846 property OnCheckOverwrite: TOnCheckOverwrite read FOnCheckOverwrite write FOnCheckOverwrite;
7947 property OnModuleRenamed: TOnModuleRenamed read FOnModuleRenamed write FOnModuleRenamed;
8048 property OnSetSaveFileName: TOnSetSaveFileName read FOnSetSaveFileName write FOnSetSaveFileName;
@@ -81,19 +49,15 @@
8149 property OnAllowSave: TOnAllowSave read FOnAllowSave write FOnAllowSave;
8250 property OnAfterRename: TOnAfterRename read FOnAfterRename write FOnAfterRename;
8351 property OnBeforeRename: TOnBeforeRename read FOnBeforeRename write FOnBeforeRename;
84- property OverwriteFileNames: TStrings read FOverwriteFileNames write SetOverwriteFileNames;
8552 public
8653 constructor Create(AOwner: TComponent); override;
8754 destructor Destroy; override;
88-
89- procedure RegisterNotifier; override;
90- procedure UnRegisterNotifier; override;
91-
92- property Module: IOTAModule write FModule;
9355 end;
9456
9557 TKRKOTAModuleNotifier = class(TKRKCustomOTAModuleNotifier)
9658 published
59+ property IDENotifier;
60+
9761 property OnCheckOverwrite;
9862 property OnModuleRenamed;
9963 property OnSetSaveFileName;
@@ -100,114 +64,488 @@
10064 property OnAllowSave;
10165 property OnAfterRename;
10266 property OnBeforeRename;
103- property OverwriteFileNames;
10467 end;
10568
10669 implementation
10770
108-{ TKRKCustomOTAModuleNotifier }
71+uses
72+ SysUtils, KRK.ToolsApi.Components.Notifier, KRK.ToolsApi;
10973
110-procedure TKRKCustomOTAModuleNotifier.AfterRename(const OldFileName: string; const NewFileName: string);
74+type
75+ TOTAModuleNotifier = class(TNotifierObject
76+ ,IOTAModuleNotifier
77+ ,IOTAModuleNotifier80
78+ ,IOTAModuleNotifier90)
79+ private
80+ FNotifierIndex: Integer;
81+ FMainComponent: TKRKCustomOTAModuleNotifier;
82+ FModule: IOTAModule;
83+ { IOTAModuleNotifier }
84+ function CheckOverwrite: Boolean;
85+ procedure ModuleRenamed(const NewName: string);
86+ { IOTAModuleNotifier80 }
87+ procedure SetSaveFileName(const FileName: string);
88+ function GetOverwriteFileName(Index: Integer): string;
89+ function GetOverwriteFileNameCount: Integer;
90+ function AllowSave: Boolean;
91+ { IOTAModuleNotifier90 }
92+ procedure AfterRename(const OldFileName: string; const NewFileName: string);
93+ procedure BeforeRename(const OldFileName: string; const NewFileName: string);
94+ public
95+ constructor Create(const AMainComponent: TKRKCustomOTAModuleNotifier; const AModule: IOTAModule);
96+ destructor Destroy; override;
97+ { IOTANotifier }
98+ procedure Destroyed;
99+ end;
100+
101+{ TOTAModuleNotifier }
102+
103+procedure TOTAModuleNotifier.AfterRename(const OldFileName, NewFileName: string);
111104 begin
112- if Assigned(FOnAfterRename) then
113- FOnAfterRename(OldFileName,NewFileName);
105+ if Assigned(FMainComponent.FOnAfterRename) then
106+ FMainComponent.FOnAfterRename(FModule,OldFileName,NewFileName);
114107 end;
115108
116-function TKRKCustomOTAModuleNotifier.AllowSave: Boolean;
109+function TOTAModuleNotifier.AllowSave: Boolean;
117110 begin
118111 Result := True;
119112
120- if Assigned(FOnAllowSave) then
121- FOnAllowSave(Result);
113+ if Assigned(FMainComponent.FOnAllowSave) then
114+ FMainComponent.FOnAllowSave(FModule,Result);
122115 end;
123116
124-procedure TKRKCustomOTAModuleNotifier.BeforeRename(const OldFileName: string; const NewFileName: string);
117+procedure TOTAModuleNotifier.BeforeRename(const OldFileName, NewFileName: string);
125118 begin
126- if Assigned(FOnBeforeRename) then
127- FOnBeforeRename(OldFileName,NewFileName);
119+ if Assigned(FMainComponent.FOnBeforeRename) then
120+ FMainComponent.FOnBeforeRename(FModule, OldFileName,NewFileName);
128121 end;
129122
130-function TKRKCustomOTAModuleNotifier.CheckOverwrite: Boolean;
123+function TOTAModuleNotifier.CheckOverwrite: Boolean;
131124 begin
132125 Result := True;
133126
134- if Assigned(FOnCheckOverwrite) then
135- FOnCheckOverwrite(Result);
127+ if Assigned(FMainComponent.FOnCheckOverwrite) then
128+ FMainComponent.FOnCheckOverwrite(FModule,Result);
136129 end;
137130
138-constructor TKRKCustomOTAModuleNotifier.Create(AOwner: TComponent);
131+constructor TOTAModuleNotifier.Create(const AMainComponent: TKRKCustomOTAModuleNotifier; const AModule: IOTAModule);
139132 begin
140- inherited;
141- FOverwriteFileNames := TStringList.Create;
142- OnDestroyed := DoDestroyed;
133+ FMainComponent := AMainComponent;
134+ FModule := AModule;
135+ // Registra automaticamente o notificador atual no módulo especificado
136+ FNotifierIndex := FModule.AddNotifier(Self);
143137 end;
144138
145-destructor TKRKCustomOTAModuleNotifier.Destroy;
139+destructor TOTAModuleNotifier.Destroy;
146140 begin
147- FOverwriteFileNames.Free;
148- UnRegisterNotifier;
149- inherited;
141+ // Apenas desregistra este notificador caso isso já não tenha sido feito no
142+ // método Destroyed mais adiante
143+ if FNotifierIndex > -1 then
144+ begin
145+ FModule.RemoveNotifier(FNotifierIndex);
146+ FMainComponent.FNotifiers.Remove(Self);
147+ end;
150148 end;
151-// É necessário usar NotifierIndex := -1 porque o evento OnDestroyed pode
152-// ocorrer antes da destruição da classe atual e sendo assim, no destrutor
153-// regular, não precisaremos mais desregistrar o notificador. Aqui também
154-// configuramos FModule como nil porque sendo FModule a referencia a uma
155-// interface, precisamos garantir que a contagem de referencias seja
156-// decrementada. Caso OnDestroyed seja disparado antes da classe atual ser
157-// destruída, ao configurmos FModule como nil, informamos ao sistema de contagem
158-// de referencias de interfaces que existe menos uma referencia e que portanto a
159-// memória pode ser liberada, caso a contagem de referencia seja zero. Não fazer
160-// isso poderia manter na memória uma instância de IOTAModule que não estaria
161-// sendo usada mais por ninguém. Note que no destrutor não é necessário
162-// confugurar FModule como nil, porque ao destruir a classe, todos os seus
163-// membros serão anulados automaticamente
164-procedure TKRKCustomOTAModuleNotifier.DoDestroyed(ASender: TObject);
149+
150+procedure TOTAModuleNotifier.Destroyed;
165151 begin
166- UnRegisterNotifier;
167- NotifierIndex := -1;
152+ // A interface que registrou este notificador está prestes a ser destruída,
153+ // neste caso, desregistra este notificador imediatamente
154+ if FNotifierIndex > -1 then
155+ begin
156+ FModule.RemoveNotifier(FNotifierIndex);
157+ FMainComponent.FNotifiers.Remove(Self);
158+ // Evita que o destrutor padrão da classe tente desregistrar novamente
159+ FNotifierIndex := -1;
160+ end;
161+ // Como a interface que registrou este notificador está sendo destruída,
162+ // configuramos o campo FModule como nil para reduzir imediatamente a contagem
163+ // de referências para garantir que a interface seja liberada da memória o
164+ // mais rápido possível
168165 FModule := nil;
169166 end;
170167
171-function TKRKCustomOTAModuleNotifier.GetOverwriteFileName(Index: Integer): string;
168+function TOTAModuleNotifier.GetOverwriteFileName(Index: Integer): string;
169+var
170+ FileList: TStringList;
172171 begin
173- Result := '';
172+ FileList := TStringList.Create;
173+ try
174+ FModule.GetAssociatedFilesFromModule(FileList);
175+ Result := FileList[Index];
176+ finally
177+ FileList.Free;
178+ end;
179+end;
174180
175- if FOverwriteFileNames.Count > 0 then
176- Result := FOverwriteFileNames[Index];
181+function TOTAModuleNotifier.GetOverwriteFileNameCount: Integer;
182+begin
183+ Result := FModule.ModuleFileCount;
177184 end;
178185
179-function TKRKCustomOTAModuleNotifier.GetOverwriteFileNameCount: Integer;
186+procedure TOTAModuleNotifier.ModuleRenamed(const NewName: string);
180187 begin
181- Result := FOverwriteFileNames.Count;
188+ if Assigned(FMainComponent.FOnModuleRenamed) then
189+ FMainComponent.FOnModuleRenamed(FModule,NewName);
182190 end;
183191
184-procedure TKRKCustomOTAModuleNotifier.ModuleRenamed(const NewName: string);
192+procedure TOTAModuleNotifier.SetSaveFileName(const FileName: string);
185193 begin
186- if Assigned(FOnModuleRenamed) then
187- FOnModuleRenamed(NewName);
194+ if Assigned(FMainComponent.FOnSetSaveFileName) then
195+ FMainComponent.FOnSetSaveFileName(FModule,FileName);
188196 end;
189197
190-procedure TKRKCustomOTAModuleNotifier.RegisterNotifier;
198+{ TKRKCustomOTAModuleNotifier }
199+
200+constructor TKRKCustomOTAModuleNotifier.Create(AOwner: TComponent);
191201 begin
192- if Assigned(FModule) then
193- NotifierIndex := FModule.AddNotifier(Self);
202+ inherited;
203+ FIDENotifier := TKRKOTAIDENotifier.Create(Self);
204+ FIDENotifier.Name := 'IDENotifier';
205+ // Método mágico que faz um componente regular ser usado como subcomponente
206+ FIDENotifier.SetSubComponent(True);
207+ FNotifiers := TInterfaceList.Create;
194208 end;
195209
196-procedure TKRKCustomOTAModuleNotifier.SetOverwriteFileNames(const Value: TStrings);
210+destructor TKRKCustomOTAModuleNotifier.Destroy;
211+var
212+ OMN: IOTAModuleNotifier;
213+ i: Word;
197214 begin
198- FOverwriteFileNames.Assign(Value);
215+ // Remove todos os notificadores que ainda estão na lista. No uso normal,
216+ // quando o destrutor desta classe atua a lista já estará vazia, porque ele só
217+ // é chamado quando o Delphi for fechado. Quando este expert está carregado
218+ // como pacote entretanto, ele pode ser descarregado enquanto a IDE está em
219+ // execução, neste caso, a lista conterá todos os notificadores, os quais
220+ // precisam ser destruídos
221+ if FNotifiers.Count > 0 then
222+ for i := Pred(FNotifiers.Count) downto 0 do
223+ if Supports(FNotifiers[i],IOTAModuleNotifier,OMN) then
224+ begin
225+ // Finge que a interface de módulo na qual o notificador foi adicionado
226+ // foi destruída. Isso faz com que o notificador se remova
227+ // automaticamente. Isso também remove o notificador da lista
228+ OMN.Destroyed;
229+ end;
230+
231+ FNotifiers.Free;
232+
233+ FIDENotifier.Free;
234+ inherited;
199235 end;
200236
201-procedure TKRKCustomOTAModuleNotifier.SetSaveFileName(const FileName: string);
237+procedure TKRKCustomOTAModuleNotifier.DoFileNotification(ANotifyCode: TOTAFileNotification; const AFileName: string; var ACancel: Boolean);
202238 begin
203- if Assigned(FOnSetSaveFileName) then
204- FOnSetSaveFileName(FileName);
239+ // Por padrão adiciona notificadores para módulos associados a arquivos .pas.
240+ // Talvez seja interessante colocar isso como uma propriedade do componente!
241+ if (ExtractFileExt(AFileName) = '.pas') and (ANotifyCode = ofnFileOpened) then
242+ FNotifiers.Add(TOTAModuleNotifier.Create(Self,GetIOTAModuleFromFileName(AFileName)));
243+
244+// faça um teste
245+// crie um arquivo no projeto e veja se ele criará seu proprio modulo (eu acho que vai)
246+// salve e verifique se o notificador ainda está associado com o modulo (eu acho que sim)
247+// renomeie algum arrquivo e veja se precisa fazer algo para manter o notificador (eu acho que não precisa!)
248+
249+
250+ // Não é necessário lidar com a remoção dos notificadores aqui porque ao
251+ // fechar uma aba na IDE o metodo destroyed do notificador se encarrega disso
252+
253+ if Assigned(FUserDoFileNotification) then
254+ FUserDoFileNotification(ANotifyCode,AFileName,ACancel);
205255 end;
206256
207-procedure TKRKCustomOTAModuleNotifier.UnRegisterNotifier;
257+procedure TKRKCustomOTAModuleNotifier.Loaded;
208258 begin
209- if Assigned(FModule) and (NotifierIndex > -1) then
210- FModule.RemoveNotifier(NotifierIndex);
259+ inherited;
260+ // A codificação abaixo faz um desvio, de forma que OnFileNotification sempre
261+ // seja usado internamente, mas ainda possa ser usado externamente pelo
262+ // usuário quando ele configura este evento no Object Inspector
263+ if not (csDesigning in ComponentState) then
264+ begin
265+ FUserDoFileNotification := FIDENotifier.OnFileNotification;
266+ FIDENotifier.OnFileNotification := DoFileNotification;
267+ end;
211268 end;
269+//
270+// // A interface IOTAModuleNotifier80 possui duas propriedades, as quais estão
271+// // associadas a dois métodos. As interfaces de notificação normalmente nos
272+// // notificam algo, portanto, dados "saem" destas interfaces. Este é o
273+// // funcionamento normal. Algumas interfaces, como IOTAModuleNotifier80 e
274+// // INTACustomEditorSubView possuem propriedades somente leitura associadas a
275+// // métodos. Isso significa que a IDE lê estas propriedades e é por isso que
276+// // precisamos implementar seus métodos associados (métodos get). Estes métodos
277+// // get não serão chamados pela IDE, eles existem na interface para nos obrigar
278+// // a implementá-los, pois a IDE fará uso apenas das propriedades somente
279+// // leitura, as quais obtém seus dados a partir dos métodos "get". Nós é quem
280+// // precisamos, nestes métodos, retornar algo para a IDE, fazendo o caminho
281+// // oposto de uma interface de notificação tradicional. Na classe abaixo
282+// // FOverwriteFileNames é uma lista que pode ser modificada em tempo de projeto
283+// // no componente. Ao preencher esta lista, os métodos GetOverwriteFileName e
284+// // GetOverwriteFileNameCount retornarão para a IDE as informações que ela
285+// // precisa quando a IDE acessar as propriedades OverwriteFileNameCount e
286+// // OverwriteFileNames.
287+//
288+// // ATENÇÃO: Me parece estranho, nesta interface de notificação precisarmos
289+// // informar nomes de arquivo e sua quantidade, sendo que isso o módulo em
290+// // si já parece conhecer. Talvez isso seja algo para configurar corretamente o
291+// // notificador. Se isso for verdade, a OverwriteFileNames não deve existir,
292+// // pois seus dados devem ser pegos diretamente do modulo que registra esse
293+// // notificador. Verifique isso depois, pois acho que há como saber os arquivos
294+// // e quantidade de arquivos que um módulo manipula!
295+//
296+// //: Classe do componente que implementa a interface IOTAModuleNotifier. Este
297+// //: componente já registra internamente um componente TKRKOTAIDENotifier, o
298+// //: que significa que ao usar este componente, você não precisa incluir um
299+// //: TKRKOTAIDENotifier separado
300+// //: ATENÇÃO: Este componente NÃO SE AUTOREGISTRA como notificador para
301+// //: IOTAModule. Ele não gerencia seu índice de notificador. Cabe classe que
302+// //: contém o método que registra este notificador manter uma lista de indices
303+// TKRKCustomOTAModuleNotifier = class(TKRKOTANotifier
304+// ,IOTAModuleNotifier
305+// ,IOTAModuleNotifier80
306+// ,IOTAModuleNotifier90)
307+//
308+// private
309+// FOnCheckOverwrite: TOnCheckOverwrite;
310+// FOnModuleRenamed: TOnModuleRenamed;
311+// FOnSetSaveFileName: TOnSetSaveFileName;
312+// FOnAllowSave: TOnAllowSave;
313+// FOnAfterRename: TOnAfterRename;
314+// FOnBeforeRename: TOnBeforeRename;
315+// FOverwriteFileNames: TStrings;
316+// FIDENotifier: TKRKOTAIDENotifier;
317+// FUserDoFileNotification: TOnFileNotification;
318+// FForAllModules: Boolean;
319+// FModules: TInterfaceList;
320+// procedure DoDestroyed(ASender: TObject);
321+// //: Este é o método manipulador do evento OnFileNotification. A classe atual
322+// //: usa um TKRKOTAIDENotifier interno porque precisa do evento
323+// //: OnFileNotification para adicionar um notificador para cada IOTAModule
324+// //: aberto. Este método chama internamente manipulador do evento
325+// //: OnFileNotification que porventura tenha sido configurado pelo usuário, o
326+// //: qual tem sua referência em FUserDoFileNotification
327+// procedure DoFileNotification(ANotifyCode: TOTAFileNotification; const AFileName: string; var ACancel: Boolean);
328+//
329+// procedure AddNotifier(AModule: IOTAModule);
330+//
331+//
332+// { IOTAModuleNotifier }
333+// function CheckOverwrite: Boolean;
334+// procedure ModuleRenamed(const NewName: string);
335+// { IOTAModuleNotifier80 }
336+// procedure SetSaveFileName(const FileName: string);
337+// function GetOverwriteFileName(Index: Integer): string;
338+// function GetOverwriteFileNameCount: Integer;
339+// function AllowSave: Boolean;
340+// { IOTAModuleNotifier90 }
341+// procedure AfterRename(const OldFileName: string; const NewFileName: string);
342+// procedure BeforeRename(const OldFileName: string; const NewFileName: string);
343+// { TKRKCustomOTAModuleNotifier }
344+// procedure SetOverwriteFileNames(const Value: TStrings);
345+// protected
346+// procedure Loaded; override;
347+//
348+// property OnCheckOverwrite: TOnCheckOverwrite read FOnCheckOverwrite write FOnCheckOverwrite;
349+// property OnModuleRenamed: TOnModuleRenamed read FOnModuleRenamed write FOnModuleRenamed;
350+// property OnSetSaveFileName: TOnSetSaveFileName read FOnSetSaveFileName write FOnSetSaveFileName;
351+// property OnAllowSave: TOnAllowSave read FOnAllowSave write FOnAllowSave;
352+// property OnAfterRename: TOnAfterRename read FOnAfterRename write FOnAfterRename;
353+// property OnBeforeRename: TOnBeforeRename read FOnBeforeRename write FOnBeforeRename;
354+// property OverwriteFileNames: TStrings read FOverwriteFileNames write SetOverwriteFileNames;
355+// public
356+// constructor Create(AOwner: TComponent); override;
357+// destructor Destroy; override;
358+//
359+//// function AddNotifier: Integer; override;
360+//// procedure RemoveNotifier(const AIndex: Integer); override;
361+// //: Quando ForAllModules = True, o notificador implementado neste componente
362+// //: será adicionado para cada novo módulo aberto e removido quando um módulo
363+// //: aberto for fechado. Quando FForAllModules = False, a classe desse
364+// //: componente poderá ser usada para registrar um noficador para um módulo
365+// //: específico
366+// property ForAllModules: Boolean read FForAllModules write FForAllModules default False;
367+// property IDENotifier: TKRKOTAIDENotifier read FIDENotifier;
368+// end;
369+//
370+// TKRKOTAModuleNotifier = class(TKRKCustomOTAModuleNotifier)
371+// published
372+// property OnCheckOverwrite;
373+// property OnModuleRenamed;
374+// property OnSetSaveFileName;
375+// property OnAllowSave;
376+// property OnAfterRename;
377+// property OnBeforeRename;
378+// property OverwriteFileNames;
379+//
380+// property ForAllModules;
381+// property IDENotifier;
382+// end;
383+//
384+//implementation
385+//
386+//uses KRK.ToolsApi;
387+//
388+//{ TKRKCustomOTAModuleNotifier }
389+//
390+//procedure TKRKCustomOTAModuleNotifier.AddNotifier(AModule: IOTAModule);
391+//begin
392+// AModule.AddNotifier(Self);
393+//end;
394+//
395+//procedure TKRKCustomOTAModuleNotifier.AfterRename(const OldFileName: string; const NewFileName: string);
396+//begin
397+// if Assigned(FOnAfterRename) then
398+// FOnAfterRename(OldFileName,NewFileName);
399+//end;
400+//
401+//function TKRKCustomOTAModuleNotifier.AllowSave: Boolean;
402+//begin
403+// Result := True;
404+//
405+// if Assigned(FOnAllowSave) then
406+// FOnAllowSave(Result);
407+//end;
408+//
409+//procedure TKRKCustomOTAModuleNotifier.BeforeRename(const OldFileName: string; const NewFileName: string);
410+//begin
411+// if Assigned(FOnBeforeRename) then
412+// FOnBeforeRename(OldFileName,NewFileName);
413+//end;
414+//
415+//function TKRKCustomOTAModuleNotifier.CheckOverwrite: Boolean;
416+//begin
417+// Result := True;
418+//
419+// if Assigned(FOnCheckOverwrite) then
420+// FOnCheckOverwrite(Result);
421+//end;
422+//
423+//constructor TKRKCustomOTAModuleNotifier.Create(AOwner: TComponent);
424+//begin
425+// inherited;
426+// FOverwriteFileNames := TStringList.Create;
427+// FForAllModules := False;
428+// OnDestroyed := DoDestroyed;
429+// FIDENotifier := TKRKOTAIDENotifier.Create(Self);
430+// FIDENotifier.Name := 'IDENotifier';
431+// // Método mágico que faz um componente regular ser usado como subcomponente
432+// FIDENotifier.SetSubComponent(True);
433+// FModules := TInterfaceList.Create;
434+//end;
435+//
436+//destructor TKRKCustomOTAModuleNotifier.Destroy;
437+//begin
438+// FModules.Free;
439+// FIDENotifier.Free;
440+// FOverwriteFileNames.Free;
441+// inherited;
442+//end;
443+//// É necessário usar NotifierIndex := -1 porque o evento OnDestroyed pode
444+//// ocorrer antes da destruição da classe atual e sendo assim, no destrutor
445+//// regular, não precisaremos mais desregistrar o notificador. Aqui também
446+//// configuramos FModule como nil porque sendo FModule a referencia a uma
447+//// interface, precisamos garantir que a contagem de referencias seja
448+//// decrementada. Caso OnDestroyed seja disparado antes da classe atual ser
449+//// destruída, ao configurmos FModule como nil, informamos ao sistema de contagem
450+//// de referencias de interfaces que existe menos uma referencia e que portanto a
451+//// memória pode ser liberada, caso a contagem de referencia seja zero. Não fazer
452+//// isso poderia manter na memória uma instância de IOTAModule que não estaria
453+//// sendo usada mais por ninguém. Note que no destrutor não é necessário
454+//// confugurar FModule como nil, porque ao destruir a classe, todos os seus
455+//// membros serão anulados automaticamente
456+//procedure TKRKCustomOTAModuleNotifier.DoDestroyed(ASender: TObject);
457+//begin
458+//// RemoveNotifier;
459+//// NotifierIndex := -1;
460+//// FModule := nil;
461+//end;
462+//
463+//// provavelmente será necessário lidar com os eventos de renomeamento para
464+//// garantir que o módulo aponte para o arquivo aberto na ide, mesmo que ele
465+//// tenha sido renomeado
466+//
467+//procedure TKRKCustomOTAModuleNotifier.DoFileNotification(ANotifyCode: TOTAFileNotification; const AFileName: string; var ACancel: Boolean);
468+//begin
469+// // Apenas quando o componente está configurado para ser adicionado como
470+// // notificador em todos os módulos é que precisamos executar o bloco de código
471+// // a seguir
472+// if FForAllModules then
473+// case ANotifyCode of
474+// ofnFileOpened: begin
475+//// crie uma função que adicione e remova o notificador e nela já use
476+//// diretamente uma lista de interfaces de forma que se possa acessar o
477+//// IOTAModule correto a partir do nome do qrquivo. Algo precisará ser feito
478+//// nos eventos de renomeação
479+// //GetIOTAModuleFromFileName(AFileName).AddNotifier(Self);
480+// end;
481+// ofnFileClosing: begin
482+// //GetIOTAModuleFromFileName(AFileName).RemoveNotifier();
483+// end;
484+// end;
485+//
486+//
487+//// fileopened
488+//// fileclosing
489+//
490+// if Assigned(FUserDoFileNotification) then
491+// FUserDoFileNotification(ANotifyCode,AFileName,ACancel);
492+//end;
493+//
494+//function TKRKCustomOTAModuleNotifier.GetOverwriteFileName(Index: Integer): string;
495+//begin
496+// Result := '';
497+//
498+// if FOverwriteFileNames.Count > 0 then
499+// Result := FOverwriteFileNames[Index];
500+//end;
501+//
502+//function TKRKCustomOTAModuleNotifier.GetOverwriteFileNameCount: Integer;
503+//begin
504+// Result := FOverwriteFileNames.Count;
505+//end;
506+//
507+//procedure TKRKCustomOTAModuleNotifier.Loaded;
508+//begin
509+// inherited;
510+// // A codificação abaixo faz um desvio, de forma que OnFileNotification sempre
511+// // seja usado internamente, mas ainda possa ser usado externamente pelo
512+// // usuário quando ele configura este evento no Object Inspector
513+// if not (csDesigning in ComponentState) then
514+// begin
515+// FUserDoFileNotification := FIDENotifier.OnFileNotification;
516+// FIDENotifier.OnFileNotification := DoFileNotification;
517+// end;
518+//end;
519+//
520+//procedure TKRKCustomOTAModuleNotifier.ModuleRenamed(const NewName: string);
521+//begin
522+// if Assigned(FOnModuleRenamed) then
523+// FOnModuleRenamed(NewName);
524+//end;
525+//
526+////function TKRKCustomOTAModuleNotifier.AddNotifier: Integer;
527+////begin
528+//// Result := -1;
529+////
530+//// if Assigned(FModule) then
531+//// Result := FModule.AddNotifier(Self);
532+////end;
533+//
534+//procedure TKRKCustomOTAModuleNotifier.SetOverwriteFileNames(const Value: TStrings);
535+//begin
536+// FOverwriteFileNames.Assign(Value);
537+//end;
538+//
539+//procedure TKRKCustomOTAModuleNotifier.SetSaveFileName(const FileName: string);
540+//begin
541+// if Assigned(FOnSetSaveFileName) then
542+// FOnSetSaveFileName(FileName);
543+//end;
544+//
545+////procedure TKRKCustomOTAModuleNotifier.RemoveNotifier;
546+////begin
547+//// if Assigned(FModule) and (NotifierIndex > -1) then
548+//// FModule.RemoveNotifier(NotifierIndex);
549+////end;
212550
213551 end.
--- trunk/rtp/src/ToolsAPI/Components/KRK.ToolsApi.Components.Notifier.pas (revision 537)
+++ trunk/rtp/src/ToolsAPI/Components/KRK.ToolsApi.Components.Notifier.pas (revision 538)
@@ -6,9 +6,40 @@
66 Classes, ToolsAPI;
77
88 type
9+ //: Define uma classe ancestral básica a partir da qual todos os componentes
10+ //: notificadores descendem. Esta classe implementa os métodos básicos
11+ //: existentes em IOTANotifier e expõe para cada um deles um evento.
12+ //: Notificadores podem ser aplicados em várias interfaces específicas.
13+ //: Algumas destas interfaces são únicas (existe apenas uma instância durante
14+ //: a execução da IDE), por exemplo, IOTAEditorServices. Esta interface tem
15+ //: métodos de registro e desregistro de notificadores
16+ //: (INTAEditServicesNotifier). Notificadores registrados nesta interface só
17+ //: vão precisam ser destruídos quando a IDE for fechada. IOTAEditorServices
18+ //: representa "Serviço aplicados aos editores" e não cada editor em si
19+ //: (IOTAEditor). TKRKNTAEditServicesNotifier, que implementa
20+ //: INTAEditServicesNotifier, portanto, pode manter um campo privado para
21+ //: guardar seu próprio índice de notificador, o qual é retornado por
22+ //: IOTAEditorServices.AddNotifier ao se registrar automaticamente em seu
23+ //: próprio método "Loaded" sobrescrito. Se você incluir num projeto mais de
24+ //: um componente TKRKNTAEditServicesNotifier vc receberá notificações em
25+ //: todos estes componentes, e cada um deles será responsável por desregistrar
26+ //: a si próprio. Outras interfaces, como IOTAModule, são criadas e
27+ //: destruídaas por demanda durante o tempo de vida da IDE. Ao se abrir um
28+ //: arquivo na IDE um módulo é carregado, logo, é criada uma nova instância de
29+ //: IOTAModule. Caso precisemos registrar um notificador para cada módulo que
30+ //: se abre, precisamos, dinamicamente, adicionar o notificador ao IOTAModule
31+ //: e remover o notificador quando o módulo for fechado. Como cada arquivo
32+ //: está contido em um módulo e se quer usar um mesmo componente para todos os
33+ //: módulos, não é possível que o notificador cuide de seu próprio indice,
34+ //: pois ao abrir um segundo módulo, TKRKOTAModuleNotifier seria adicionado
35+ //: como notificador deste segundo módulo e seu índice interno seria
36+ //: sobrescrito, perdendo assim a referência ao primeiro notificador, que
37+ //: jamais poderia ser liberado da memória! Para este tipo de notificador, não
38+ //: se pode usar um índice interno. Aquele que registra o notificador é quem é
39+ //: o responsável por liberar este notificador em momento oportuno e, por
40+ //: isso, é ele o responsável por manter a lista de notificadores adicionados
941 TKRKOTANotifier = class(TComponent)
1042 private
11- FNotifierIndex: Integer;
1243 FOnAfterSave: TNotifyEvent;
1344 FOnBeforeSave: TNotifyEvent;
1445 FOnDestroyed: TNotifyEvent;
@@ -19,29 +50,22 @@
1950 // public porque eu não tenho certeza se tais eventos são disparados
2051 // normalmente. Caso algum destes eventos precise ser usado em designtime,
2152 // considere movê-los para a seção published de classes filhas a fim de
22- // expô-los. O eveto OnDestroyed é o único que parece ser disparado sempre
23- // que o notificador for destruído pela IDE e pode ser usado para
24- // desregistrar tal noficador em adição a um desregistro feito no destrutor
25- // regular da classe
53+ // expô-los.
54+ // O método Destroyed é executado quando a interface que registrou este
55+ // notificador for destruída! Neste método ou no seu evento associado inclua
56+ // código que desregistra o notificador. O método Destroyed acontece sempre
57+ // antes do destrutor padrão da classe, portanto tome cuidado para que o
58+ // destrutor padrão não tente desregistrar novamente o notificador. A boa
59+ // prática é proteger o código do destrutor padrão verificando se o índice
60+ // do notificador é > -1 e no método Destroyed, após o desregistro bem
61+ // sucedido, configurar o índice do notificador como -1. Fazendo isso é
62+ // grantido que no destrutor regular não seja tentado um desregistro
63+ // novamente
2664 procedure AfterSave;
2765 procedure BeforeSave;
2866 procedure Destroyed;
2967 procedure Modified;
30-
31- // Os métodos virtuais abaixo servem para o registro e desregistro do
32- // notificador. Como existem notificadores que são registrados por
33- // interfaces diferentes, precisamos deixar isso a cargo do programador. Ao
34- // implementar estes metodos em classes de notificação filhas o programador
35- // deve usar o método de registro/desregistro a partir da interface correta.
36- procedure RegisterNotifier; virtual;
37- procedure UnRegisterNotifier; virtual;
38- // ATENÇÃO: NOTIFICADORES NÃO DEVEM TER ESSA PROPRIEDADE, PORQUE AQUELES QUE
39- // OS REGISTRAM É QUE PRECISAM MANTER ESSE NUMERO! ESSA ALTERAÇÃO VAI SER DRÁSTICA
40- // PROCURE TODOS OS NOTIFICADORES NO EXPERT E VEJA COMO ELES TÃO SENDO CRIADOS.
41- // EM SEGUIDA DESVINCULE-OS, FAZENDO COM QUE LISTAS DE INDICES SEJAM MANTIDAS NOS OBJETOS QUE OS REGISTRAM
42- property NotifierIndex: Integer read FNotifierIndex write FNotifierIndex;
4368 public
44- constructor Create(AOwner: TComponent); override;
4569 property OnAfterSave: TNotifyEvent read FOnAfterSave write FOnAfterSave;
4670 property OnBeforeSave: TNotifyEvent read FOnBeforeSave write FOnBeforeSave;
4771 property OnModified: TNotifyEvent read FOnModified write FOnModified;
@@ -66,12 +90,6 @@
6690 FOnBeforeSave(Self);
6791 end;
6892
69-constructor TKRKOTANotifier.Create(AOwner: TComponent);
70-begin
71- inherited;
72- FNotifierIndex := -1;
73-end;
74-
7593 procedure TKRKOTANotifier.Destroyed;
7694 begin
7795 if Assigned(FOnDestroyed) then
@@ -84,14 +102,4 @@
84102 FOnModified(Self);
85103 end;
86104
87-procedure TKRKOTANotifier.RegisterNotifier;
88-begin
89- raise Exception.Create('Este método precisa ser implementado na classe "' + ClassName + '" antes de ser usado!'#13#10'Ao implementá-lo não use a palavra chave inherited!');
90-end;
91-
92-procedure TKRKOTANotifier.UnRegisterNotifier;
93-begin
94- raise Exception.Create('Este método precisa ser implementado na classe "' + ClassName + '" antes de ser usado!'#13#10'Ao implementá-lo não use a palavra chave inherited!');
95-end;
96-
97105 end.
--- trunk/rtp/src/ToolsAPI/Components/KRK.ToolsApi.Components.ProjectMenuCreatorNotifier.pas (revision 537)
+++ trunk/rtp/src/ToolsAPI/Components/KRK.ToolsApi.Components.ProjectMenuCreatorNotifier.pas (revision 538)
@@ -12,7 +12,9 @@
1212 type
1313 TOnAddMenu = procedure (const AProject: IOTAProject; const AIdent: string; const ARootMenu: TMenuItem) of object;
1414 TOnCanHandle = function (const AIdent: String): Boolean of object;
15-
15+ essa classe só atua no delphi 2006
16+ voce ainda não arrumou ela para a nova
17+ realidade dos notificadores. Faça isso agora!
1618 //: Classe do componente que implementa a interface
1719 //: INTAProjectMenuCreatorNotifier responsável por notificar a respeito da
1820 //: criação (exibição) do menu de contexto do Project Manager. O evento
--- trunk/rtp/src/ToolsAPI/Components/KRK.ToolsApi.Components.ProjectMenuItemCreatorNotifier.pas (revision 537)
+++ trunk/rtp/src/ToolsAPI/Components/KRK.ToolsApi.Components.ProjectMenuItemCreatorNotifier.pas (revision 538)
@@ -26,9 +26,14 @@
2626 //: indica o parentesco entre menus. Todos os itens serão replicados e
2727 //: colocados no menu de contexto exatamente como eles estão representados no
2828 //: TMainMenu.
29+ //: ATENÇÃO: Este componente se autoregistra como notificador para
30+ //: IOTAProjectManager, por isso ele mesmo gerencia seu índice de notificador.
31+ //: Mais de um desse componente pode ser usado por projeto para definir mais
32+ //: de um menu a ser adicionado no menu de contexto do Project Manager
2933 TKRKCustomOTAProjectMenuItemCreatorNotifier = class(TKRKOTANotifier
3034 ,IOTAProjectMenuItemCreatorNotifier)
3135 private
36+ FNotifierIndex: Integer;
3237 //: Campo privado que contém a última posição que foi incrementada a partir
3338 //: de FPosition. Quando se usa a propriedade FMenu, cada item do menu
3439 //: informado nessa propriedade será adicionado ao menu de contexto do
@@ -46,6 +51,9 @@
4651 //: será renderizado
4752 FMenu: TMainMenu;
4853 FAdditionalMenuItemsList: TMenuItemList;
54+ // Manipulador do evento OnDestroyed, usado aqui para TAMBÉM desregistrar o
55+ // notificador
56+ procedure DoDestroyed(ASender: TObject);
4957
5058 { IOTAProjectMenuItemCreatorNotifier }
5159
@@ -253,6 +261,7 @@
253261 inherited;
254262 FPosition := 0;
255263 FAdditionalMenuItemsList := TMenuItemList.Create;
264+ OnDestroyed := DoDestroyed;
256265 end;
257266
258267 destructor TKRKCustomOTAProjectMenuItemCreatorNotifier.Destroy;
@@ -260,17 +269,30 @@
260269 FAdditionalMenuItemsList.Free;
261270
262271 if not (csDesigning in ComponentState) then
263- RemoveOTAProjectMenuItemCreatorNotifier(NotifierIndex);
272+ RemoveOTAProjectMenuItemCreatorNotifier(FNotifierIndex);
264273
265274 inherited;
266275 end;
276+// O evento OnDestroyed acontece antes da destruição da classe, portanto, caso
277+// este evento seja disparado, precisamos configurar NotifierIndex como -1, de
278+// forma que no destrutor regular da classe não seja feita a remoção novamente,
279+// o que invariavelmente levaria a uma exceção
280+procedure TKRKCustomOTAProjectMenuItemCreatorNotifier.DoDestroyed(ASender: TObject);
281+begin
282+ if not (csDesigning in ComponentState) then
283+ begin
284+ RemoveOTAProjectMenuItemCreatorNotifier(FNotifierIndex);
285+ FNotifierIndex := -1;
286+ end;
287+end;
267288
289+
268290 procedure TKRKCustomOTAProjectMenuItemCreatorNotifier.Loaded;
269291 begin
270292 inherited;
271293
272294 if not (csDesigning in ComponentState) then
273- NotifierIndex := AddOTAProjectMenuItemCreatorNotifier(Self);
295+ FNotifierIndex := AddOTAProjectMenuItemCreatorNotifier(Self);
274296 end;
275297
276298 { TOTAProjectManagerMenuItem }
--- trunk/rtp/src/Vcl/KRK.Vcl.Forms.pas (revision 537)
+++ trunk/rtp/src/Vcl/KRK.Vcl.Forms.pas (revision 538)
@@ -538,5 +538,9 @@
538538 // the only two classes we need to register for.
539539 TCustomStyleEngine.RegisterStyleHook(TForm,TFixedFormStyleHook);
540540 TCustomStyleEngine.RegisterStyleHook(TCustomForm,TFixedFormStyleHook);
541+
542+finalization
543+ TCustomStyleEngine.UnRegisterStyleHook(TCustomForm,TFixedFormStyleHook);
544+ TCustomStyleEngine.UnRegisterStyleHook(TForm,TFixedFormStyleHook);
541545 {$IFEND}
542546 end.
Show on old repository browser