Revision | 70 (tree) |
---|---|
Time | 2021-12-18 07:12:52 |
Author | ![]() |
Folhas de estilo atualizadas
Consideração de comentários sem texto (comentários de anexos)
Função ReplaceSpecialElementsFromComment criada para lidar com a substituição de tags especiais incluídos em comentários
Lidando com a abertura da tela de tarefas quando há um id de comentário informado
Tela de gerenciamento de notas concluída com a lista de uploads e drag and drop habilitado
Na tela de tarefa o método DoNavigationStarting está sendo compartilhado por todos os TEdgeBrowser no evento OnNavigationStarting
@@ -117,7 +117,7 @@ | ||
117 | 117 | <VerInfo_MinorVer>0</VerInfo_MinorVer> |
118 | 118 | <VerInfo_Release>0</VerInfo_Release> |
119 | 119 | <VerInfo_Locale>1033</VerInfo_Locale> |
120 | - <VerInfo_Keys>CompanyName=;FileDescription=$(MSBuildProjectName);FileVersion=1.0.0.419;InternalName=;LegalCopyright=;LegalTrademarks=;OriginalFilename=;ProductName=$(MSBuildProjectName);ProductVersion=1.0.0.0;Comments=;ProgramID=com.embarcadero.$(MSBuildProjectName)</VerInfo_Keys> | |
120 | + <VerInfo_Keys>CompanyName=;FileDescription=$(MSBuildProjectName);FileVersion=1.0.0.493;InternalName=;LegalCopyright=;LegalTrademarks=;OriginalFilename=;ProductName=$(MSBuildProjectName);ProductVersion=1.0.0.0;Comments=;ProgramID=com.embarcadero.$(MSBuildProjectName)</VerInfo_Keys> | |
121 | 121 | <Debugger_RunParams>/desenvolvimento</Debugger_RunParams> |
122 | 122 | <VerInfo_AutoGenVersion>false</VerInfo_AutoGenVersion> |
123 | 123 | <VerInfo_AutoIncVersion>true</VerInfo_AutoIncVersion> |
@@ -124,7 +124,7 @@ | ||
124 | 124 | <DCC_DebugInformation>2</DCC_DebugInformation> |
125 | 125 | <DCC_SymbolReferenceInfo>2</DCC_SymbolReferenceInfo> |
126 | 126 | <DCC_DebugInfoInExe>true</DCC_DebugInfoInExe> |
127 | - <VerInfo_Build>419</VerInfo_Build> | |
127 | + <VerInfo_Build>493</VerInfo_Build> | |
128 | 128 | <DCC_MapFile>3</DCC_MapFile> |
129 | 129 | </PropertyGroup> |
130 | 130 | <ItemGroup> |
@@ -829,11 +829,17 @@ | ||
829 | 829 | ' </div>'#13#10 + |
830 | 830 | ' </div>'#13#10; |
831 | 831 | |
832 | + const HEADER1_TEMPLATE = | |
833 | + ' <div class="widget-header widget-header-small" id="%u">(%s) <b>%s</b> escreveu em <b>%s</b></div>'; | |
834 | + | |
835 | + const HEADER2_TEMPLATE = | |
836 | + ' <div class="widget-header widget-header-small"><b>%s</b> anexou este(s) arquivo(s) em <b>%s</b></div>'; | |
837 | + | |
832 | 838 | const COMMENT_TEMPLATE = |
833 | 839 | '<tr class="bugnote">'#13#10 + |
834 | 840 | ' <td class="bugnote-note bugnote-%s">'#13#10 + |
835 | 841 | ' <div class="widget-box widget-color-blue2 mbtmheader">'#13#10 + |
836 | - ' <div class="widget-header widget-header-small">(%s) <b>%s</b> escreveu em <b>%s</b></div>'#13#10 + | |
842 | + '%s'#13#10 + // cabeçalho | |
837 | 843 | ' </div>'#13#10 + |
838 | 844 | '%s' + // ferramentas |
839 | 845 | '%s' + // comentários |
@@ -852,12 +858,13 @@ | ||
852 | 858 | |
853 | 859 | var Tools: String; |
854 | 860 | var Attachments: String; |
861 | + var Header: String; | |
855 | 862 | |
856 | 863 | Result := ''; |
857 | 864 | |
858 | 865 | for var Comment: TComment in AComments do |
859 | 866 | begin |
860 | - // -- Ferramentas ------------------------------------------------------ | |
867 | + // -- Ferramentas -------------------------------------------------------- | |
861 | 868 | Tools := ''; |
862 | 869 | Attachments := ''; |
863 | 870 |
@@ -879,8 +886,8 @@ | ||
879 | 886 | |
880 | 887 | Tools := Format(TOOLS_TEMPLATE,[Tools]); |
881 | 888 | end; |
882 | - // --------------------------------------------------------------------- | |
883 | - // -- Anexos ----------------------------------------------------------- | |
889 | + // ----------------------------------------------------------------------- | |
890 | + // -- Anexos ------------------------------------------------------------- | |
884 | 891 | if Length(Comment.Attachments) > 0 then |
885 | 892 | begin |
886 | 893 | var AttachmentItem: String; |
@@ -895,16 +902,24 @@ | ||
895 | 902 | |
896 | 903 | Attachments := Attachments + Format(ATTACHMENTS_TEMPLATE,[AttachmentItem]); |
897 | 904 | end; |
898 | - // --------------------------------------------------------------------- | |
899 | - // -- Linha de comentário final ---------------------------------------- | |
905 | + // ----------------------------------------------------------------------- | |
906 | + // -- Header ------------------------------------------------------------- | |
907 | + if Comment.AttachmentsOnly then | |
908 | + Header := Format(HEADER2_TEMPLATE,[Comment.Creator | |
909 | + ,FormatDateTime('dd/mm/yyyy "às" hh:nn:ss',Comment.Created)]) | |
910 | + else | |
911 | + Header := Format(HEADER1_TEMPLATE,[Comment.Id | |
912 | + ,FormatFloat('00000000',Comment.Id) | |
913 | + ,Comment.Creator | |
914 | + ,FormatDateTime('dd/mm/yyyy "às" hh:nn:ss',Comment.Created)]); | |
915 | + // ----------------------------------------------------------------------- | |
916 | + // -- Linha de comentário final ------------------------------------------ | |
900 | 917 | Result := Result + Format(COMMENT_TEMPLATE,[IfThen(Comment.IsPrivate,'private','public') |
901 | - ,FormatFloat('00000000',Comment.Id) | |
902 | - ,Comment.Creator | |
903 | - ,FormatDateTime('dd/mm/yyyy "às" hh:nn:ss',Comment.Created) | |
918 | + ,Header | |
904 | 919 | ,Tools |
905 | 920 | ,Comment.Text |
906 | 921 | ,Attachments]); |
907 | - // --------------------------------------------------------------------- | |
922 | + // ----------------------------------------------------------------------- | |
908 | 923 | end; |
909 | 924 | end; |
910 | 925 | end; |
@@ -136,7 +136,7 @@ | ||
136 | 136 | var |
137 | 137 | FileInfo: SHFILEINFO; |
138 | 138 | begin |
139 | - SHGetFileInfo(PChar(GetFileName(AId)), 0, FileInfo, SizeOf(FileInfo), SHGFI_TYPENAME); | |
139 | + SHGetFileInfo(PChar(GetFileName(AId)), 0, FileInfo, SizeOf(SHFILEINFO), SHGFI_TYPENAME); | |
140 | 140 | Result := FileInfo.szTypeName; |
141 | 141 | end; |
142 | 142 |
@@ -149,7 +149,7 @@ | ||
149 | 149 | var |
150 | 150 | FileInfo: SHFILEINFO; |
151 | 151 | begin |
152 | - SHGetFileInfo(PChar(GetFileName(AId)), 0, FileInfo, SizeOf(FileInfo), SHGFI_DISPLAYNAME); | |
152 | + SHGetFileInfo(PChar(GetFileName(AId)), 0, FileInfo, SizeOf(SHFILEINFO), SHGFI_DISPLAYNAME); | |
153 | 153 | Result := FileInfo.szDisplayName; |
154 | 154 | end; |
155 | 155 |
@@ -157,7 +157,7 @@ | ||
157 | 157 | var |
158 | 158 | FileInfo: SHFILEINFO; |
159 | 159 | begin |
160 | - SHGetFileInfo(PChar(GetFileName(AId)), 0, FileInfo, SizeOf(FileInfo), SHGFI_ICON or SHGFI_SMALLICON); | |
160 | + SHGetFileInfo(PChar(GetFileName(AId)), 0, FileInfo, SizeOf(SHFILEINFO), SHGFI_ICON or SHGFI_SMALLICON); | |
161 | 161 | Result := FileInfo.hIcon; |
162 | 162 | end; |
163 | 163 |
@@ -180,21 +180,6 @@ | ||
180 | 180 | inherited; |
181 | 181 | end; |
182 | 182 | |
183 | -//procedure TListBox.WMDropFiles(var AMessage: TWMDropFiles); | |
184 | -//begin | |
185 | -// inherited; | |
186 | -// | |
187 | -// with TFileCatcher.Create(AMessage.Drop) do | |
188 | -// try | |
189 | -// for var i: Cardinal := 0 to Pred(FileCount) do | |
190 | -// Items.Add(GetFile(i)); | |
191 | -// finally | |
192 | -// Free; | |
193 | -// end; | |
194 | -// | |
195 | -// AMessage.Result := 0; | |
196 | -//end; | |
197 | - | |
198 | 183 | procedure TListView.WMDropFiles(var AMessage: TWMDropFiles); |
199 | 184 | begin |
200 | 185 | inherited; |
@@ -567,9 +567,51 @@ | ||
567 | 567 | end; |
568 | 568 | end; |
569 | 569 | |
570 | +function ReplaceSpecialElementsFromComment(AElementWithComment: IHTMLElement; const AComment: TComment): String; | |
571 | +var | |
572 | + HTMLElementCollection: IHTMLElementCollection4; | |
573 | +begin | |
574 | + // Substituindo cada <atta> por um link para download do anexo referenciado | |
575 | + HTMLElementCollection := (AElementWithComment as IHTMLElement2).getElementsByTagName('atta') as IHTMLElementCollection4; | |
570 | 576 | |
571 | -// AUnparsedComment é o <td> que contém o comentário propriamente dito | |
572 | -procedure ParseCommentsAndAttachments(AUnparsedComment: IHTMLElement; var AComment: TComment); | |
577 | + if HTMLElementCollection.length > 0 then | |
578 | + begin | |
579 | + var HTMLAnchorElement: IHTMLAnchorElement; | |
580 | + var FileName: String; | |
581 | + var FileNick: String; | |
582 | + var Attachment: TAttachment; | |
583 | + // Aqui o loop precisa ser de trás pra frente porque ao substituir um dos | |
584 | + // elementos a quantidade de elementos circulados diminui e caso o loop | |
585 | + // fosse na ordem direta, estaríamos acessando um índice de elemento que não | |
586 | + // condiz com a realidade, havendo o salto de itens e um AV no último item. | |
587 | + // Ao reverter o loop, é garantido que o índice anterior seja sempre o | |
588 | + // elemento anterior | |
589 | + for var i: Word := Pred(HTMLElementCollection.length) downto 0 do | |
590 | + begin | |
591 | + // Obtém o nome real do arquivo a partir do primeiro <atna> existente | |
592 | + // dentro de <atta> | |
593 | + FileName := (((HTMLElementCollection.item(i) as IHTMLElement2).getElementsByTagName('atna') as IHTMLElementCollection4).item(0) as IHTMLElement).innerText; | |
594 | + // Usa o nome real do arquivo para buscar dentre os anexos do comentário o | |
595 | + // anexo que está sendo referenciado | |
596 | + Attachment := AComment.AttachmentByFileName[FileName]; | |
597 | + // Caso haja uma anexo, prossegue com sua substituição | |
598 | + if Attachment.Id > 0 then | |
599 | + begin | |
600 | + FileNick := (((HTMLElementCollection.item(i) as IHTMLElement2).getElementsByTagName('atnn') as IHTMLElementCollection4).item(0) as IHTMLElement).innerText; | |
601 | + | |
602 | + HTMLAnchorElement := (AElementWithComment.document as IHTMLDocument2).createElement('a') as IHTMLAnchorElement; | |
603 | + HTMLAnchorElement.href := '/ViewAttachment?id=' + Attachment.Id.ToString + '&fn=' + FileName; | |
604 | + (HTMLAnchorElement as IHTMLElement).innerText := FileNick; | |
605 | + | |
606 | + (HTMLElementCollection.item(i) as IHTMLDOMNode).replaceNode(HTMLAnchorElement as IHTMLDomNode); | |
607 | + end; | |
608 | + end; | |
609 | + end; | |
610 | + //-/////////////////////////////////////////////////////////////////////////// | |
611 | + Result := Trim(AElementWithComment.innerHTML); | |
612 | +end; | |
613 | +// AElementWithComment é o <td> que contém o comentário propriamente dito | |
614 | +procedure ParseCommentsAndAttachments(AElementWithComment: IHTMLElement; var AComment: TComment); | |
573 | 615 | var |
574 | 616 | HTMLCollection: IHTMLElementCollection; |
575 | 617 | begin |
@@ -576,7 +618,7 @@ | ||
576 | 618 | // Obtém uma coleção de todos os <a> contidos no comentário, incluindo aqueles |
577 | 619 | // que estão dentro de outros tags e não são filhos imediatos de |
578 | 620 | // AUnparsedComment |
579 | - HTMLCollection := (AUnparsedComment as IHTMLElement2).getElementsByTagName('a'); | |
621 | + HTMLCollection := (AElementWithComment as IHTMLElement2).getElementsByTagName('a'); | |
580 | 622 | // Caso haja <a> precisamos verificar cada um deles para saber se eles se |
581 | 623 | // referem a anexos e processar quando necessário |
582 | 624 | if HTMLCollection.length > 0 then |
@@ -601,7 +643,7 @@ | ||
601 | 643 | // AUnparsedComment de uma só vez, usando um loop só para excluir elementos |
602 | 644 | // que não precisam figurar no comentário final. O loop abaixo também exclui |
603 | 645 | // <br> do fim do comentário, os quais são desnecessários |
604 | - HTMLCollection := AUnparsedComment.children as IHTMLElementCollection; | |
646 | + HTMLCollection := AElementWithComment.children as IHTMLElementCollection; | |
605 | 647 | |
606 | 648 | if HTMLCollection.length > 0 then |
607 | 649 | begin |
@@ -617,7 +659,7 @@ | ||
617 | 659 | // também precisam ser excluídos, pois eles não são necessários no fim do |
618 | 660 | // comentário |
619 | 661 | if (LowerCase(HTMLElement.tagName) = 'div') or (LowerCase(HTMLElement.tagName) = 'br') then |
620 | - (AUnparsedComment as IHTMLDOMNode).removeChild(HTMLElement as IHTMLDOMNode) | |
662 | + (AElementWithComment as IHTMLDOMNode).removeChild(HTMLElement as IHTMLDOMNode) | |
621 | 663 | // Caso o elemento for <a>, preciasamos fazer algumas verificações antes |
622 | 664 | // de excluir, pois apenas <a> referentes a anexos precisam ser excluídos |
623 | 665 | // e há um caso especial onde precisamos excluir um nó de texto que existe |
@@ -631,15 +673,17 @@ | ||
631 | 673 | // que contém o tamanho do anexo, logo, nos livramos dele antes de |
632 | 674 | // excluir o <a> da vez |
633 | 675 | if Attachment.FileSize > 0 then |
634 | - (AUnparsedComment as IHTMLDOMNode).removeChild((HTMLElement as IHTMLDOMNode).nextSibling); | |
676 | + (AElementWithComment as IHTMLDOMNode).removeChild((HTMLElement as IHTMLDOMNode).nextSibling); | |
635 | 677 | |
636 | - (AUnparsedComment as IHTMLDOMNode).removeChild(HTMLElement as IHTMLDOMNode); | |
678 | + (AElementWithComment as IHTMLDOMNode).removeChild(HTMLElement as IHTMLDOMNode); | |
637 | 679 | end; |
638 | 680 | end; |
639 | 681 | end; |
640 | 682 | end; |
641 | - // Neste ponto só deve existir o texto do comentário | |
642 | - AComment.Text := Trim(AUnparsedComment.innerHTML); | |
683 | + // Neste ponto só deve existir o texto do comentário e dentro dele podem | |
684 | + // existir elementos especiais que precisam tratados, por exemplo, elementos | |
685 | + // <atta> que precisam ser substituídos por links para anexos. A função abaixo | |
686 | + AComment.Text := ReplaceSpecialElementsFromComment(AElementWithComment,AComment); | |
643 | 687 | end; |
644 | 688 | |
645 | 689 | { |
@@ -1033,9 +1077,7 @@ | ||
1033 | 1077 | var Comment: TComment; |
1034 | 1078 | var FormsCollection: IHTMLElementCollection; |
1035 | 1079 | var HTMLFormElement: IHTMLFormElement; |
1036 | - // Leia mais adiante porque existem estas variáveis comentadas | |
1037 | -// var LinksCollection: IHTMLElementCollection; | |
1038 | -// var HTMLLinkElement: IHTMLLinkElement; | |
1080 | + var AnchorsCollection: IHTMLElementCollection; | |
1039 | 1081 | |
1040 | 1082 | for var i: Word := 0 to Pred(HTMLElementCollection.length) do |
1041 | 1083 | begin |
@@ -1107,9 +1149,7 @@ | ||
1107 | 1149 | // que é muito mais útil do que esta funcionalidade que eu estou |
1108 | 1150 | // ignorando |
1109 | 1151 | |
1110 | - // Quando não se acha nenhum <form>, ainda pode haver um botão de | |
1111 | - // exclusão em um <a>, dentro de CommentDetails, quando trata-se de um | |
1112 | - // comentário sem texto, mas com anexos | |
1152 | + // Quando não se acha nenhum <form>, ainda pode haver | |
1113 | 1153 | // else |
1114 | 1154 | // begin |
1115 | 1155 | // LinksCollection := (CommentDetails as IHTMLElement2).getElementsByTagName('a'); |
@@ -1125,7 +1165,28 @@ | ||
1125 | 1165 | // end; |
1126 | 1166 | // end; |
1127 | 1167 | |
1168 | + // Algumas linhas de comentário no Mantis não são comentários | |
1169 | + // propriamente ditos, porque não possuem texto. Estas linhas contém | |
1170 | + // apenas arquivos anexados e que aparecem dentro do fluxo de | |
1171 | + // comentários apenas para que se identifique uma cronologia de quando | |
1172 | + // tais arquivos foram anexados. Linhas de comentário que possuem um | |
1173 | + // botão de exclusão em um <a>, dentro de CommentDetails, tratam-se de | |
1174 | + // comentários sem texto, mas com anexos | |
1175 | + AnchorsCollection := (CommentDetails as IHTMLElement2).getElementsByTagName('a'); | |
1128 | 1176 | |
1177 | + if AnchorsCollection.length > 0 then | |
1178 | + for var j: Byte := 0 to Pred(AnchorsCollection.length) do | |
1179 | + if Pos('bug_file_delete.php',String(((AnchorsCollection as IHTMLElementCollection4).item(j) as IHTMLAnchorElement).href)) > 0 then | |
1180 | + begin | |
1181 | + // Ao achar bug_file_delete.php no href do link ele | |
1182 | + // provavelmente será o único presente e isso já é suficiente | |
1183 | + // para indicar que este é um comentário "somente anexo", sendo | |
1184 | + // assim basta configurar a propriedade e sair imediatamente do | |
1185 | + // loop | |
1186 | + Comment.AttachmentsOnly := True; | |
1187 | + Break; | |
1188 | + end; | |
1189 | + | |
1129 | 1190 | // Obtendo a referência a segunda célula da linha, a qual contém o |
1130 | 1191 | // comentário propriamente dito e também referências arquivos |
1131 | 1192 | // anexados juntamente com o comentário, por isso é necessário |
@@ -1135,7 +1196,7 @@ | ||
1135 | 1196 | |
1136 | 1197 | // Um comentário tem anexos quando há em seu texto <div> ou <a> com |
1137 | 1198 | // href apontando para "file_download.php?file_id=xxxx&type=bug". A |
1138 | - // função ParseCommentsAndAttachments faz isso | |
1199 | + // função ParseCommentsAndAttachments faz isso e muito mais | |
1139 | 1200 | ParseCommentsAndAttachments(HTMLElement,Comment); |
1140 | 1201 | // Eu adoro a nova forma de incrementar a arrays a partir do XE7 <3 |
1141 | 1202 | ATask.Comments := ATask.Comments + [Comment]; |
@@ -105,6 +105,9 @@ | ||
105 | 105 | TCommentType = (ctRegular,ctTestsApproval,ctTestsRejection,ctHomologationApproval,ctHomologationRejection); |
106 | 106 | |
107 | 107 | TComment = record |
108 | + private | |
109 | + function GetAttachmentsCount: Word; | |
110 | + function GetAttachmentByFileName(AFileName: String): TAttachment; | |
108 | 111 | public |
109 | 112 | Id: Cardinal; |
110 | 113 | Created: TDateTime; |
@@ -118,8 +121,12 @@ | ||
118 | 121 | CanModify: Boolean; |
119 | 122 | CanDelete: Boolean; |
120 | 123 | CanChangeVisibility: Boolean; |
124 | + AttachmentsOnly: Boolean; | |
121 | 125 | |
122 | 126 | procedure AddOrUpdateAttachment(const AAttachment: TAttachment); |
127 | + | |
128 | + property AttachmentsCount: Word read GetAttachmentsCount; | |
129 | + property AttachmentByFileName[AFileName: String]: TAttachment read GetAttachmentByFileName; | |
123 | 130 | end; |
124 | 131 | |
125 | 132 | TComments = array of TComment; |
@@ -206,6 +213,7 @@ | ||
206 | 213 | function GetCommentsCount: Word; |
207 | 214 | function GetHistoryEntryCount: Word; |
208 | 215 | function GetRelatedTasksCount: Word; |
216 | + function GetCommentById(AId: Cardinal): TComment; | |
209 | 217 | public |
210 | 218 | procedure Clear(AAllButId: Boolean = True); |
211 | 219 |
@@ -234,6 +242,7 @@ | ||
234 | 242 | property CommentsCount: Word read GetCommentsCount; |
235 | 243 | property HistoryEntryCount: Word read GetHistoryEntryCount; |
236 | 244 | property RelatedTasksCount: Word read GetRelatedTasksCount; |
245 | + property CommentById[AId: Cardinal]: TComment read GetCommentById; | |
237 | 246 | end; |
238 | 247 | |
239 | 248 | TTasks = array of TTask; |
@@ -402,6 +411,18 @@ | ||
402 | 411 | Inc(Result,Length(Comment.Attachments)); |
403 | 412 | end; |
404 | 413 | |
414 | +function TTask.GetCommentById(AId: Cardinal): TComment; | |
415 | +begin | |
416 | + Result := Default(TComment); | |
417 | + | |
418 | + for var Comment: TComment in FComments do | |
419 | + if Comment.Id = AId then | |
420 | + begin | |
421 | + Result := Comment; | |
422 | + Break; | |
423 | + end; | |
424 | +end; | |
425 | + | |
405 | 426 | function TTask.GetCommentsCount: Word; |
406 | 427 | begin |
407 | 428 | Result := Length(FComments); |
@@ -508,4 +529,21 @@ | ||
508 | 529 | Attachments := Attachments + [AAttachment]; |
509 | 530 | end; |
510 | 531 | |
532 | +function TComment.GetAttachmentByFileName(AFileName: String): TAttachment; | |
533 | +begin | |
534 | + Result := Default(TAttachment); | |
535 | + | |
536 | + for var Attachment: TAttachment in Attachments do | |
537 | + if LowerCase(Attachment.FileName) = LowerCase(AFileName) then | |
538 | + begin | |
539 | + Result := Attachment; | |
540 | + Break; | |
541 | + end; | |
542 | +end; | |
543 | + | |
544 | +function TComment.GetAttachmentsCount: Word; | |
545 | +begin | |
546 | + Result := Length(Attachments); | |
547 | +end; | |
548 | + | |
511 | 549 | end. |
@@ -183,7 +183,7 @@ | ||
183 | 183 | Comment: String; |
184 | 184 | CommentToken: String; |
185 | 185 | begin |
186 | - if TFormManageNote.ShowMeModal(TForm(Owner),FTask.Id,ACommentId,Comment,CommentToken) = mrOk then | |
186 | + if TFormManageNote.ShowMeModal(Self,FTask,ACommentId,Comment,CommentToken) = mrOk then | |
187 | 187 | begin |
188 | 188 | CommentBackupCreate(ACommentId,Comment); |
189 | 189 |
@@ -202,7 +202,7 @@ | ||
202 | 202 | Comment: String; |
203 | 203 | Dummy: String; |
204 | 204 | begin |
205 | - if TFormManageNote.ShowMeModal(TForm(Owner),FTask.Id,0,Comment,Dummy) = mrOk then | |
205 | + if TFormManageNote.ShowMeModal(Self,FTask,0,Comment,Dummy) = mrOk then | |
206 | 206 | Application.MessageBox('Código para salvar novo comentário','A fazer',MB_ICONINFORMATION); |
207 | 207 | end; |
208 | 208 |
@@ -6,7 +6,8 @@ | ||
6 | 6 | Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, |
7 | 7 | Dialogs, UFormBasicDialog, StdCtrls, Buttons, UPngBitBtn, ExtCtrls, PngImage, |
8 | 8 | KRK.Internet.Edge, Winapi.ActiveX, Vcl.ComCtrls, UInterposersAndHelpers, |
9 | - System.ImageList, Vcl.ImgList, Vcl.Menus, Vcl.ActnPopup, Vcl.XPStyleActnCtrls; | |
9 | + System.ImageList, Vcl.ImgList, Vcl.Menus, Vcl.ActnPopup, Vcl.XPStyleActnCtrls, | |
10 | + UTypes, UDamoTask; | |
10 | 11 | |
11 | 12 | type |
12 | 13 | TFormManageNote = class(TFormBasicDialog) |
@@ -18,6 +19,7 @@ | ||
18 | 19 | IMLIAttachments: TImageList; |
19 | 20 | PUABAttachments: TPopupActionBar; |
20 | 21 | MNUICopyReferenceToFile: TMenuItem; |
22 | + PANEAttachments: TPanel; | |
21 | 23 | procedure EDBRExecuteScript(Sender: TCustomEdgeBrowser; AResult: HRESULT; const AResultObjectAsJson: string); |
22 | 24 | procedure EDBRCreateWebViewCompleted(Sender: TCustomEdgeBrowser; AResult: HRESULT); |
23 | 25 | procedure FormCreate(Sender: TObject); |
@@ -24,23 +26,27 @@ | ||
24 | 26 | procedure EDBRWebResourceRequested(Sender: TCustomEdgeBrowser; Args: TWebResourceRequestedEventArgs); |
25 | 27 | procedure FormDestroy(Sender: TObject); |
26 | 28 | procedure FormShow(Sender: TObject); |
27 | - procedure LIVIAttachmentsChange(Sender: TObject; Item: TListItem; | |
28 | - Change: TItemChange); | |
29 | - procedure LIVIAttachmentsKeyUp(Sender: TObject; var Key: Word; | |
30 | - Shift: TShiftState); | |
29 | + procedure LIVIAttachmentsChange(Sender: TObject; Item: TListItem; Change: TItemChange); | |
30 | + procedure LIVIAttachmentsKeyUp(Sender: TObject; var Key: Word; Shift: TShiftState); | |
31 | 31 | procedure MNUICopyReferenceToFileClick(Sender: TObject); |
32 | + procedure PANEAttachmentsClick(Sender: TObject); | |
32 | 33 | private |
33 | 34 | { Private declarations } |
35 | + FDamoTask: TDamoTask; | |
36 | + FTask: TTask; | |
37 | + FComment: String; | |
38 | + FCommentId: Cardinal; | |
34 | 39 | FUpdating: Boolean; |
35 | - FComment: String; | |
36 | 40 | FPostContent: TStringStream; |
37 | 41 | |
38 | 42 | procedure DoDropFiles(ASender: TObject; const ADropHandle: LRESULT; out AMessageResult: LRESULT); |
43 | + procedure ConfigureAttachments; | |
44 | + procedure AddAttachment(AFileName: String; AFileSize: Cardinal); | |
39 | 45 | protected |
40 | 46 | procedure ValidateSave; override; |
41 | 47 | public |
42 | 48 | { Public declarations } |
43 | - class function ShowMeModal(AOwner: TComponent; ATaskNumber, ACommentId: Cardinal; out AComment: String; out AUpdateToken: String): TModalResult; reintroduce; | |
49 | + class function ShowMeModal(ADamoTask: TDamoTask; ATask: TTask; ACommentId: Cardinal; out AComment: String; out AUpdateToken: String): TModalResult; reintroduce; | |
44 | 50 | end; |
45 | 51 | |
46 | 52 | implementation |
@@ -60,38 +66,92 @@ | ||
60 | 66 | Application.MessageBox(PChar('A referência ao arquivo "' + LIVIAttachments.Selected.Caption + '" foi adicionada à área de transferência. Você pode colá-la no editor de comentário, onde é possível também dar um apelido a esta referência, selecionando-a e clicando no ícone com um clipe de papel'),'Referência copiada',MB_ICONINFORMATION); |
61 | 67 | end; |
62 | 68 | |
63 | -procedure TFormManageNote.DoDropFiles(ASender: TObject; const ADropHandle: LRESULT; out AMessageResult: LRESULT); | |
69 | +procedure TFormManageNote.PANEAttachmentsClick(Sender: TObject); | |
70 | +begin | |
71 | + inherited; | |
72 | + | |
73 | + if FDamoTask.OPDIAttachment.Execute then | |
74 | + begin | |
75 | + var Info: TWin32FileAttributeData; | |
76 | + | |
77 | + if not GetFileAttributesEx(PChar(FDamoTask.OPDIAttachment.FileName), GetFileExInfoStandard, @Info) then | |
78 | + AddAttachment(FDamoTask.OPDIAttachment.FileName,0) | |
79 | + else | |
80 | + AddAttachment(FDamoTask.OPDIAttachment.FileName,Int64(Info.nFileSizeLow) or Int64(Info.nFileSizeHigh shl 32)); | |
81 | + end; | |
82 | +end; | |
83 | + | |
84 | +procedure TFormManageNote.AddAttachment(AFileName: String; AFileSize: Cardinal); | |
64 | 85 | var |
86 | + FileInfo: SHFILEINFO; | |
65 | 87 | Icon: TIcon; |
66 | 88 | begin |
89 | + Icon := TIcon.Create; | |
90 | + try | |
91 | + with LIVIAttachments.Items.Add do | |
92 | + begin | |
93 | + SHGetFileInfo(PChar(AFileName), 0, FileInfo, SizeOf(SHFILEINFO), SHGFI_TYPENAME or SHGFI_ICON or SHGFI_SMALLICON or SHGFI_USEFILEATTRIBUTES); | |
94 | + | |
95 | + Icon.Handle := FileInfo.hIcon; | |
96 | + ImageIndex := LIVIAttachments.SmallImages.AddIcon(Icon); | |
97 | + DestroyIcon(Icon.Handle); | |
98 | + | |
99 | + Caption := ExtractFileName(AFileName); | |
100 | + SubItems.Add(FormatFloat('###,###,###,##0', AFileSize) + ' Bytes'); | |
101 | + SubItems.Add(FileInfo.szTypeName); | |
102 | + | |
103 | + if AFileName <> Caption then | |
104 | + SubItems.Add(ExtractFilePath(AFileName)); | |
105 | + end; | |
106 | + finally | |
107 | + Icon.Free; | |
108 | + end; | |
109 | +end; | |
110 | + | |
111 | +procedure TFormManageNote.ConfigureAttachments; | |
112 | +begin | |
113 | + // A aba de anexos só é visível se estamos no modo de inserção, ou no modo de | |
114 | + // edição quando há anexos associados ao comentário | |
115 | + TASHAttachments.TabVisible := (not FUpdating) or (FTask.CommentById[FCommentId].AttachmentsCount > 0); | |
116 | + // Caso a aba de anexos esteja visível e estivermos no modo de edição, | |
117 | + // precisamos carregar os anexos no ListView, que, neste caso, não aceitará | |
118 | + // mais anexos, servido apenas para que possamos copiar referências a eles | |
119 | + if TASHAttachments.TabVisible and FUpdating then | |
120 | + begin | |
121 | + DragAcceptFiles(LIVIAttachments.Handle, False); | |
122 | + | |
123 | + LIVIAttachments.OnKeyUp := nil; | |
124 | + LIVIAttachments.MultiSelect := False; | |
125 | + LIVIAttachments.Columns.Delete(3); // não tem caminho para o arquivo nessa visualização | |
126 | + LIVIAttachments.Margins.Bottom := 7; | |
127 | + PANEAttachments.Hide; | |
128 | + | |
129 | + LIVIAttachments.Items.BeginUpdate; | |
130 | + try | |
131 | + for var Attachment in FTask.CommentById[FCommentId].Attachments do | |
132 | + AddAttachment(Attachment.FileName,Attachment.FileSize); | |
133 | + finally | |
134 | + LIVIAttachments.Items.EndUpdate; | |
135 | + end; | |
136 | + end; | |
137 | +end; | |
138 | + | |
139 | +procedure TFormManageNote.DoDropFiles(ASender: TObject; const ADropHandle: LRESULT; out AMessageResult: LRESULT); | |
140 | +begin | |
67 | 141 | // Parte do código existente em TFileCatcher que diz respeito a obtenção de |
68 | 142 | // informações sobre arquivos foi obtido a partir de |
69 | 143 | // https://www.swissdelphicenter.ch/en/showcode.php?id=421 |
70 | 144 | |
71 | 145 | TListView(ASender).Items.BeginUpdate; |
72 | - Icon := TIcon.Create; | |
73 | 146 | try |
74 | 147 | with TFileCatcher.Create(ADropHandle) do |
75 | 148 | try |
76 | 149 | for var i: Cardinal := 0 to Pred(FileCount) do |
77 | - begin | |
78 | - with TListView(ASender).Items.Add do | |
79 | - begin | |
80 | - Caption := ExtractFileName(FileNames[i]); | |
81 | - SubItems.Add(FormatFloat('###,###,###,##0', FileSizes[i]) + ' Bytes'); | |
82 | - SubItems.Add(FileTypes[i]); | |
83 | - Subitems.Add(ExtractFilePath(FileNames[i])); | |
84 | - | |
85 | - Icon.Handle := FileIcons[i]; | |
86 | - ImageIndex := TListView(ASender).SmallImages.AddIcon(Icon); | |
87 | - DestroyIcon(Icon.Handle); | |
88 | - end; | |
89 | - end; | |
150 | + AddAttachment(FileNames[i],FileSizes[i]); | |
90 | 151 | finally |
91 | 152 | Free; |
92 | 153 | end; |
93 | 154 | finally |
94 | - Icon.Free; | |
95 | 155 | TListView(ASender).Items.EndUpdate; |
96 | 156 | end; |
97 | 157 |
@@ -181,7 +241,8 @@ | ||
181 | 241 | // Navigate ou NavigateToString |
182 | 242 | EDBR.CreateWebView; |
183 | 243 | |
184 | - TASHAttachments.TabVisible := not FUpdating; | |
244 | + ConfigureAttachments; | |
245 | + | |
185 | 246 | PACO.ActivePage := TASHComment; |
186 | 247 | end; |
187 | 248 |
@@ -194,6 +255,8 @@ | ||
194 | 255 | else |
195 | 256 | for var i: Byte := 0 to Pred(TListView(Sender).Columns.Count) do |
196 | 257 | TListView(Sender).Columns[i].Width := -1; |
258 | + | |
259 | + TASHAttachments.Caption := 'Anexos (' + TListView(Sender).Items.Count.ToString + ')'; | |
197 | 260 | end; |
198 | 261 | |
199 | 262 | procedure TFormManageNote.LIVIAttachmentsKeyUp(Sender: TObject; var Key: Word; Shift: TShiftState); |
@@ -201,18 +264,26 @@ | ||
201 | 264 | inherited; |
202 | 265 | |
203 | 266 | if Key = VK_DELETE then |
267 | + begin | |
204 | 268 | LIVIAttachments.DeleteSelected; |
269 | + LIVIAttachmentsChange(Sender,nil,ctText); | |
270 | + end; | |
205 | 271 | end; |
206 | 272 | |
207 | -class function TFormManageNote.ShowMeModal(AOwner: TComponent; ATaskNumber, ACommentId: Cardinal; out AComment: String; out AUpdateToken: String): TModalResult; | |
273 | +class function TFormManageNote.ShowMeModal(ADamoTask: TDamoTask; ATask: TTask; ACommentId: Cardinal; out AComment: String; out AUpdateToken: String): TModalResult; | |
208 | 274 | begin |
209 | 275 | Result := mrAbort; // Se tudo der errado... |
210 | 276 | |
211 | - with Self.Create(AOwner) do | |
277 | + with Self.Create(ADamoTask.Owner) do | |
212 | 278 | begin |
213 | - FUpdating := ACommentId > 0; | |
279 | + FDamoTask := ADamoTask; | |
280 | + FTask := ATask; | |
281 | + FCommentId := ACommentId; | |
214 | 282 | AComment := ''; |
283 | + AUpdateToken := ''; | |
284 | + | |
215 | 285 | FComment := ''; |
286 | + FUpdating := FCommentId > 0; | |
216 | 287 | |
217 | 288 | AutoCaption := False; |
218 | 289 |
@@ -219,9 +290,9 @@ | ||
219 | 290 | Caption := 'Gerenciador de anotações - ' + Application.Title; |
220 | 291 | |
221 | 292 | if FUpdating then |
222 | - LABECaption.Caption := 'Alterando a anotação ~' + ACommentId.ToString + ' da tarefa #' + ATaskNumber.ToString | |
293 | + LABECaption.Caption := 'Alterando a anotação ~' + FCommentId.ToString + ' da tarefa #' + ATask.Id.ToString | |
223 | 294 | else |
224 | - LABECaption.Caption := 'Redigindo uma nova anotação para a tarefa #' + ATaskNumber.ToString; | |
295 | + LABECaption.Caption := 'Redigindo uma nova anotação para a tarefa #' + ATask.Id.ToString; | |
225 | 296 | |
226 | 297 | // Se estamos tentando editar um comentário.. |
227 | 298 | if FUpdating then |
@@ -229,7 +300,7 @@ | ||
229 | 300 | // É obrigatório sempre executar esta função, pois mesmo que não usemos os |
230 | 301 | // comentário original, ainda precisaremos do UpdateToken. Caso a função |
231 | 302 | // não seja bem sucedida, terminamos o form com uma mensagem de erro |
232 | - if not GetCommentForEdition(Handle,ACommentId,FComment,AUpdateToken) then | |
303 | + if not GetCommentForEdition(Handle,FCommentId,FComment,AUpdateToken) then | |
233 | 304 | begin |
234 | 305 | Application.MessageBox('Não foi possível obter um comentário para edição. Por favor, tente novamente!','Erro ao obter um comentário',MB_ICONERROR); |
235 | 306 | Close; |
@@ -236,9 +307,9 @@ | ||
236 | 307 | end |
237 | 308 | // Caso exista um backup, pergunta se quer carregar. Caso se responda não |
238 | 309 | // ou caso não haja backup, será carregado o comentário obtido do Mantis |
239 | - else if CommentBackupExists(ACommentId) and (Application.MessageBox('Existe um backup do texto do comentário atual, deseja carregá-lo?','Deseja carregar o backup?',MB_ICONQUESTION or MB_YESNO) = IDYES) then | |
310 | + else if CommentBackupExists(FCommentId) and (Application.MessageBox('Existe um backup do texto do comentário atual, deseja carregá-lo?','Deseja carregar o backup?',MB_ICONQUESTION or MB_YESNO) = IDYES) then | |
240 | 311 | begin |
241 | - FComment := CommentBackupLoad(ACommentId); | |
312 | + FComment := CommentBackupLoad(FCommentId); | |
242 | 313 | Result := ShowModal; |
243 | 314 | AComment := FComment; |
244 | 315 | end |
@@ -82,7 +82,7 @@ | ||
82 | 82 | procedure FormDestroy(Sender: TObject); |
83 | 83 | procedure EDBRCommentsCreateWebViewCompleted(Sender: TCustomEdgeBrowser; AResult: HRESULT); |
84 | 84 | procedure EDBRCommentsWebResourceRequested(Sender: TCustomEdgeBrowser; Args: TWebResourceRequestedEventArgs); |
85 | - procedure EDBRCommentsNavigationStarting(Sender: TCustomEdgeBrowser; Args: TNavigationStartingEventArgs); | |
85 | + procedure DoNavigationStarting(Sender: TCustomEdgeBrowser; Args: TNavigationStartingEventArgs); | |
86 | 86 | procedure EDBRDescriptionCreateWebViewCompleted(Sender: TCustomEdgeBrowser; AResult: HRESULT); |
87 | 87 | procedure EDBRDescriptionWebResourceRequested(Sender: TCustomEdgeBrowser; Args: TWebResourceRequestedEventArgs); |
88 | 88 | procedure EDBRAdditionalInformationCreateWebViewCompleted(Sender: TCustomEdgeBrowser; AResult: HRESULT); |
@@ -90,9 +90,12 @@ | ||
90 | 90 | procedure EDBRStepsToReproduceCreateWebViewCompleted(Sender: TCustomEdgeBrowser; AResult: HRESULT); |
91 | 91 | procedure EDBRStepsToReproduceWebResourceRequested(Sender: TCustomEdgeBrowser; Args: TWebResourceRequestedEventArgs); |
92 | 92 | procedure ACTNRefreshExecute(Sender: TObject); |
93 | + procedure TASHDescriptionShow(Sender: TObject); | |
93 | 94 | private |
94 | 95 | { Private declarations } |
95 | 96 | FDamoTask: TDamoTask; |
97 | + FCommentId: Cardinal; | |
98 | + FDescriptionLoaded: Boolean; | |
96 | 99 | FAttachmentsLoaded: Boolean; |
97 | 100 | FCommentsAndAttachmentsLoaded: Boolean; |
98 | 101 | FAdditionalInfoLoaded: Boolean; |
@@ -118,10 +121,10 @@ | ||
118 | 121 | procedure CreateParams(var Params: TCreateParams); override; |
119 | 122 | public |
120 | 123 | { Public declarations } |
121 | - constructor Create(AOwner: TComponent; ATaskId: Cardinal); reintroduce; | |
124 | + constructor Create(AOwner: TComponent; ATaskId: Cardinal; ACommentId: Cardinal = 0); reintroduce; | |
122 | 125 | |
123 | - class function ShowMe(var ATask: TTask; AModal: Boolean = False): TModalResult; overload; | |
124 | - class function ShowMe(ATaskId: Cardinal; AModal: Boolean = False): TModalResult; overload; | |
126 | + class function ShowMe(var ATask: TTask; ACommentId: Cardinal = 0; AModal: Boolean = False): TModalResult; overload; | |
127 | + class function ShowMe(ATaskId: Cardinal; ACommentId: Cardinal = 0; AModal: Boolean = False): TModalResult; overload; | |
125 | 128 | |
126 | 129 | procedure InitializeFormTask(var ATask: TTask); |
127 | 130 | end; |
@@ -141,9 +144,10 @@ | ||
141 | 144 | FDamoTask.Refresh; |
142 | 145 | end; |
143 | 146 | |
144 | -constructor TFormTask.Create(AOwner: TComponent; ATaskId: Cardinal); | |
147 | +constructor TFormTask.Create(AOwner: TComponent; ATaskId: Cardinal; ACommentId: Cardinal = 0); | |
145 | 148 | begin |
146 | 149 | FDamoTask := TDamoTask.Create(Self); |
150 | + FCommentId := ACommentId; | |
147 | 151 | |
148 | 152 | inherited Create(AOwner); |
149 | 153 | // É necessário dar um nome único ao TDataModule para que cada instância |
@@ -199,10 +203,10 @@ | ||
199 | 203 | begin |
200 | 204 | inherited; |
201 | 205 | Sender.AddWebResourceRequestedFilter('*MantisBTMonitorComments.php',COREWEBVIEW2_WEB_RESOURCE_CONTEXT_ALL); |
202 | - Sender.Navigate(Configurations.MantisBTBaseUrl + '/mantis/config/MantisBTMonitorComments.php'); | |
206 | + Sender.Navigate(Configurations.MantisBTBaseUrl + '/mantis/config/MantisBTMonitorComments.php#' + FCommentId.ToString); | |
203 | 207 | end; |
204 | 208 | |
205 | -procedure TFormTask.EDBRCommentsNavigationStarting(Sender: TCustomEdgeBrowser; Args: TNavigationStartingEventArgs); | |
209 | +procedure TFormTask.DoNavigationStarting(Sender: TCustomEdgeBrowser; Args: TNavigationStartingEventArgs); | |
206 | 210 | var |
207 | 211 | URI: PChar; |
208 | 212 | begin |
@@ -385,7 +389,7 @@ | ||
385 | 389 | procedure TFormTask.HandleOpenTaskMessage(var AMessage: TMessage); |
386 | 390 | begin |
387 | 391 | // AMessage.LParam contem o código do comentário, mas não o estou usando aqui |
388 | - TFormTask.ShowMe(AMessage.WParam); | |
392 | + TFormTask.ShowMe(AMessage.WParam,AMessage.LParam); | |
389 | 393 | end; |
390 | 394 | |
391 | 395 | procedure TFormTask.IMAGHeaderClick(Sender: TObject); |
@@ -411,8 +415,8 @@ | ||
411 | 415 | FDamoTask.Task := ATask; |
412 | 416 | |
413 | 417 | LoadTaskHeader; |
414 | - LoadDescription; | |
415 | 418 | |
419 | + FDescriptionLoaded := False; | |
416 | 420 | FAdditionalInfoLoaded := False; |
417 | 421 | FStepsToReproduceLoaded := False; |
418 | 422 | FAttachmentsLoaded := False; |
@@ -419,7 +423,13 @@ | ||
419 | 423 | FHistoryLoaded := False; |
420 | 424 | FCommentsAndAttachmentsLoaded := False; |
421 | 425 | |
422 | - PACO.ActivePage := TASHDescription; | |
426 | + // Configurar o ActivePage de um TTabSheet executa seu evento OnShow. Abaixo | |
427 | + // estamos abrindo a página correta de acordo com ter ou não ter um id de | |
428 | + // comentário informado | |
429 | + if FCommentId > 0 then | |
430 | + PACO.ActivePage := TASHComments | |
431 | + else | |
432 | + PACO.ActivePage := TASHDescription; | |
423 | 433 | end; |
424 | 434 | |
425 | 435 | procedure TFormTask.KRDGRelatedTasksDblClick(Sender: TObject); |
@@ -449,12 +459,9 @@ | ||
449 | 459 | // OnCreateWebViewCompleted, no qual um filtro é adicionado e onde é feita a |
450 | 460 | // navegação para a página de informações adicionais |
451 | 461 | EDBRAdditionalInformation.ReinitializeWebView; |
452 | -// LoadWebBrowserHTML(WEBRAdditionalInformation,FDamoTask.Task.AdditionalInformation); | |
453 | 462 | |
454 | 463 | FAdditionalInfoLoaded := True; |
455 | 464 | end; |
456 | - | |
457 | -// WEBRAdditionalInformation.AddWindowSubClass; | |
458 | 465 | end; |
459 | 466 | |
460 | 467 | procedure TFormTask.LoadAttachmentsAndRelatedTasks; |
@@ -483,14 +490,15 @@ | ||
483 | 490 | |
484 | 491 | procedure TFormTask.LoadDescription; |
485 | 492 | begin |
486 | - // Reinicializa o WebView o que provoca a execução de | |
487 | - // OnCreateWebViewCompleted, no qual um filtro é adicionado e onde é feita a | |
488 | - // navegação para a página de descrição | |
489 | - EDBRDescription.ReinitializeWebView; | |
493 | + if not FDescriptionLoaded then | |
494 | + begin | |
495 | + // Reinicializa o WebView o que provoca a execução de | |
496 | + // OnCreateWebViewCompleted, no qual um filtro é adicionado e onde é feita a | |
497 | + // navegação para a página de descrição | |
498 | + EDBRDescription.ReinitializeWebView; | |
490 | 499 | |
491 | -// LoadWebBrowserHTML(WEBRDescription,FDamoTask.Task.Description); | |
492 | -// WEBRDescription.AddWindowSubClass; | |
493 | -// WEBRDescription.DisablePopUpMenu := True; | |
500 | + FDescriptionLoaded := True; | |
501 | + end; | |
494 | 502 | end; |
495 | 503 | |
496 | 504 | procedure TFormTask.LoadHistory; |
@@ -544,16 +552,16 @@ | ||
544 | 552 | Close; |
545 | 553 | end; |
546 | 554 | |
547 | -class function TFormTask.ShowMe(ATaskId: Cardinal; AModal: Boolean): TModalResult; | |
555 | +class function TFormTask.ShowMe(ATaskId: Cardinal; ACommentId: Cardinal = 0; AModal: Boolean = False): TModalResult; | |
548 | 556 | var |
549 | 557 | Task: TTask; |
550 | 558 | begin |
551 | 559 | Task.Id := ATaskId; |
552 | 560 | |
553 | - Result := ShowMe(Task,AModal); | |
561 | + Result := ShowMe(Task,ACommentId,AModal); | |
554 | 562 | end; |
555 | 563 | |
556 | -class function TFormTask.ShowMe(var ATask: TTask; AModal: Boolean = False): TModalResult; | |
564 | +class function TFormTask.ShowMe(var ATask: TTask; ACommentId: Cardinal = 0; AModal: Boolean = False): TModalResult; | |
557 | 565 | var |
558 | 566 | i: Word; |
559 | 567 | begin |
@@ -564,7 +572,7 @@ | ||
564 | 572 | Break; |
565 | 573 | |
566 | 574 | if i = Application.ComponentCount then |
567 | - with Self.Create(Application,ATask.Id) do | |
575 | + with Self.Create(Application,ATask.Id,ACommentId) do | |
568 | 576 | begin |
569 | 577 | AutoCaption := True; |
570 | 578 |
@@ -588,8 +596,28 @@ | ||
588 | 596 | else |
589 | 597 | Show; |
590 | 598 | end |
599 | + // Ao chegar neste ponto estamos tentando abrir uma janela que já está aberta. | |
600 | + // Neste caso, simplesmente coloca esta janela na frente das outras e lida com | |
601 | + // uma possível referência a um comentário | |
591 | 602 | else |
603 | + begin | |
604 | + TFormTask(Application.Components[i]).FCommentId := ACommentId; | |
605 | + // Caso o id de um comentário tenha sido informado e caso os comentários | |
606 | + // nesta janela previamente aberta já tiverem sido carregados, precisamos | |
607 | + // executar uma função JavaScript para ir para o comentário. Caso os | |
608 | + // comentários não tenham sido carregados ainda, a simples atribuição a | |
609 | + // FCommentId na linha anterior é suficiente para que os comentários sejam | |
610 | + // carregados apontando para o comentário contido em FCommentId | |
611 | + if (ACommentId > 0) then | |
612 | + begin | |
613 | + if TFormTask(Application.Components[i]).FCommentsAndAttachmentsLoaded then | |
614 | + TFormTask(Application.Components[i]).EDBRComments.ExecuteScript('goTo("' + ACommentId.ToString + '")'); | |
615 | + | |
616 | + TFormTask(Application.Components[i]).TASHComments.Show; | |
617 | + end; | |
618 | + | |
592 | 619 | TForm(Application.Components[i]).BringToFront; |
620 | + end; | |
593 | 621 | end; |
594 | 622 | |
595 | 623 | procedure TFormTask.TASHAdditionalInformationShow(Sender: TObject); |
@@ -610,6 +638,12 @@ | ||
610 | 638 | LoadComments; |
611 | 639 | end; |
612 | 640 | |
641 | +procedure TFormTask.TASHDescriptionShow(Sender: TObject); | |
642 | +begin | |
643 | + inherited; | |
644 | + LoadDescription; | |
645 | +end; | |
646 | + | |
613 | 647 | procedure TFormTask.TASHHistoryShow(Sender: TObject); |
614 | 648 | begin |
615 | 649 | inherited; |