mirror of
https://gitlab.com/freepascal.org/lazarus/lazarus.git
synced 2025-04-10 03:48:27 +02:00
IDE: started TLazDocHintProvider
git-svn-id: trunk@12806 -
This commit is contained in:
parent
8748812f81
commit
c21eb20d00
1
.gitattributes
vendored
1
.gitattributes
vendored
@ -1879,6 +1879,7 @@ ide/lazdoc.pas svneol=native#text/plain
|
||||
ide/lazdocfrm.lfm svneol=native#text/plain
|
||||
ide/lazdocfrm.lrs svneol=native#text/plain
|
||||
ide/lazdocfrm.pas svneol=native#text/plain
|
||||
ide/lazdochints.pas svneol=native#text/plain
|
||||
ide/lazdocselectinherited.lfm svneol=native#text/plain
|
||||
ide/lazdocselectinherited.lrs svneol=native#text/plain
|
||||
ide/lazdocselectinherited.pas svneol=native#text/plain
|
||||
|
@ -779,6 +779,7 @@ begin
|
||||
repeat
|
||||
if (FileInfo.Name='.') or (FileInfo.Name='..') or (FileInfo.Name='')
|
||||
or ((FileInfo.Attr and faDirectory)<>0) then continue;
|
||||
DebugLn(['TBuildManager.CheckUnitPathForAmbiguousPascalFiles AAA1 ',CurDir+FileInfo.Name]);
|
||||
if FilenameIsPascalUnit(FileInfo.Name) then
|
||||
CurUnitTree:=SourceUnitTree
|
||||
else if (CompareFileExt(FileInfo.Name,CompiledExt,false)=0) then
|
||||
@ -789,6 +790,7 @@ begin
|
||||
if (CurUnitName='') or (not IsValidIdent(CurUnitName)) then
|
||||
continue;
|
||||
CurFilename:=CurDir+FileInfo.Name;
|
||||
DebugLn(['TBuildManager.CheckUnitPathForAmbiguousPascalFiles ',CurUnitName,' ',CurFilename]);
|
||||
// check if unit already found
|
||||
ANode:=CurUnitTree.FindKey(PChar(CurUnitName),
|
||||
TListSortCompare(@CompareUnitNameAndUnitFile));
|
||||
|
@ -46,9 +46,15 @@ type
|
||||
{ TCodeHintProvider }
|
||||
|
||||
TCodeHintProvider = class(TComponent)
|
||||
private
|
||||
FControl: TControl;
|
||||
protected
|
||||
procedure SetControl(const AValue: TControl); virtual;
|
||||
public
|
||||
procedure GetPreferredSize(var PreferredWidth, PreferredHeight: integer); virtual;
|
||||
procedure Paint(Canvas: TCanvas; const ARect: TRect); virtual; abstract;
|
||||
procedure UpdateHint; virtual;
|
||||
property Control: TControl read FControl write SetControl;
|
||||
end;
|
||||
|
||||
{ TCodeHelpFrm }
|
||||
@ -89,7 +95,7 @@ type
|
||||
property PreferredHeight: integer read FPreferredHeight write SetPreferredHeight;
|
||||
property Provider: TCodeHintProvider read FProvider write SetProvider;
|
||||
end;
|
||||
|
||||
|
||||
var
|
||||
CodeHelpFrm: TCodeHelpFrm = nil;
|
||||
|
||||
@ -105,7 +111,6 @@ begin
|
||||
exit;
|
||||
end;
|
||||
UpdatePosition;
|
||||
UpdateHints;
|
||||
end;
|
||||
|
||||
procedure TCodeHelpFrm.FormCreate(Sender: TObject);
|
||||
@ -203,8 +208,12 @@ end;
|
||||
procedure TCodeHelpFrm.SetProvider(const AValue: TCodeHintProvider);
|
||||
begin
|
||||
if FProvider=AValue then exit;
|
||||
if FProvider<>nil then begin
|
||||
FProvider.Control:=nil;
|
||||
end;
|
||||
FProvider:=AValue;
|
||||
if FProvider<>nil then begin
|
||||
FProvider.Control:=Self;
|
||||
FProvider.GetPreferredSize(FPreferredWidth,FPreferredHeight);
|
||||
end;
|
||||
end;
|
||||
@ -268,7 +277,7 @@ var
|
||||
SrcEdit: TSourceEditorInterface;
|
||||
AnchorBounds: TRect;
|
||||
begin
|
||||
if not NeedVisible then exit;
|
||||
if (not NeedVisible) or Visible then exit;
|
||||
DesktopBounds:=Rect(30,30,Screen.DesktopWidth-30,Screen.DesktopHeight-50);
|
||||
NewBounds:=Bounds(DesktopBounds.Left,DesktopBounds.Top,30,30);
|
||||
|
||||
@ -333,7 +342,7 @@ procedure TCodeHelpFrm.UpdateHints;
|
||||
begin
|
||||
if not Visible then exit;
|
||||
//DebugLn(['TCodeHelpFrm.UpdateHints ']);
|
||||
|
||||
if Provider<>nil then Provider.UpdateHint;
|
||||
end;
|
||||
|
||||
function TCodeHelpFrm.NeedVisible: boolean;
|
||||
@ -349,11 +358,22 @@ end;
|
||||
|
||||
{ TCodeHintProvider }
|
||||
|
||||
procedure TCodeHintProvider.SetControl(const AValue: TControl);
|
||||
begin
|
||||
if FControl=AValue then exit;
|
||||
FControl:=AValue;
|
||||
end;
|
||||
|
||||
procedure TCodeHintProvider.GetPreferredSize(var PreferredWidth,
|
||||
PreferredHeight: integer);
|
||||
begin
|
||||
|
||||
end;
|
||||
|
||||
procedure TCodeHintProvider.UpdateHint;
|
||||
begin
|
||||
|
||||
end;
|
||||
|
||||
end.
|
||||
|
||||
|
@ -42,7 +42,7 @@ uses
|
||||
LazIDEIntf, HelpIntfs, IDEHelpIntf,
|
||||
LazarusIDEStrConsts, TransferMacros, DialogProcs, IDEOptionDefs,
|
||||
ObjInspExt, EnvironmentOpts, AboutFrm, MsgView, Project, PackageDefs, MainBar,
|
||||
OutputFilter, HelpOptions, MainIntf, LazConf, HelpFPCMessages,
|
||||
OutputFilter, HelpOptions, MainIntf, LazConf, HelpFPCMessages, LazDoc,
|
||||
IDEContextHelpEdit;
|
||||
|
||||
type
|
||||
@ -425,6 +425,8 @@ begin
|
||||
HelpViewers:=THelpViewers.Create;
|
||||
RegisterIDEHelpDatabases;
|
||||
RegisterDefaultIDEHelpViewers;
|
||||
|
||||
LazDocBoss:=TLazDocManager.Create;
|
||||
|
||||
// register property editors for URL handling
|
||||
RegisterPropertyEditor(TypeInfo(AnsiString),
|
||||
@ -433,6 +435,7 @@ end;
|
||||
|
||||
destructor THelpManager.Destroy;
|
||||
begin
|
||||
FreeThenNil(LazDocBoss);
|
||||
FPCMessagesHelpDB:=nil;
|
||||
FreeThenNil(HelpDatabases);
|
||||
FreeThenNil(HelpViewers);
|
||||
|
@ -68,6 +68,9 @@ type
|
||||
procedure FreeDocs;
|
||||
end;
|
||||
|
||||
var
|
||||
LazDocBoss: TLazDocManager = nil;// set by the IDE
|
||||
|
||||
function CompareLazFPDocFilenames(Data1, Data2: Pointer): integer;
|
||||
function CompareAnsistringWithLazFPDocFile(Key, Data: Pointer): integer;
|
||||
|
||||
|
@ -24,7 +24,6 @@
|
||||
* *
|
||||
***************************************************************************
|
||||
|
||||
|
||||
see for todo list: http://wiki.lazarus.freepascal.org/index.php/LazDoc
|
||||
}
|
||||
|
||||
@ -37,13 +36,19 @@ unit LazDocFrm;
|
||||
interface
|
||||
|
||||
uses
|
||||
// FCL
|
||||
Classes, SysUtils, StrUtils,
|
||||
// LCL
|
||||
LCLProc, LResources, StdCtrls, Buttons, ComCtrls, Controls, Dialogs,
|
||||
ExtCtrls, Forms, Graphics,
|
||||
// Synedit
|
||||
SynEdit,
|
||||
// codetools
|
||||
CodeAtom, CodeCache, CodeToolManager,
|
||||
Laz_DOM, Laz_XMLRead, Laz_XMLWrite,
|
||||
// IDEIntf
|
||||
IDEHelpIntf, LazHelpIntf,
|
||||
// IDE
|
||||
IDEOptionDefs, EnvironmentOpts,
|
||||
IDEProcs, LazarusIDEStrConsts, LazDocSelectInherited, LazDoc;
|
||||
|
||||
@ -132,7 +137,6 @@ type
|
||||
private
|
||||
FCaretXY: TPoint;
|
||||
FChanged: Boolean;
|
||||
FLazDocBoss: TLazDocManager;
|
||||
FFlags: TLazDocFormFlags;
|
||||
fUpdateLock: Integer;
|
||||
fEntry: TLazDocInheritedEntry;
|
||||
@ -170,7 +174,6 @@ type
|
||||
procedure ClearEntry(DoSave: Boolean);
|
||||
property DocFile: TLazFPDocFile read GetDocFile;
|
||||
property Doc: TXMLdocument read GetDoc;
|
||||
property LazDocBoss: TLazDocManager read FLazDocBoss;
|
||||
property SourceFilename: string read GetSourceFilename;
|
||||
property CaretXY: TPoint read FCaretXY;
|
||||
end;
|
||||
@ -269,7 +272,6 @@ end;
|
||||
|
||||
procedure TLazDocForm.FormCreate(Sender: TObject);
|
||||
begin
|
||||
FLazDocBoss:=TLazDocManager.Create;
|
||||
fEntry:=TLazDocInheritedEntry.Create;
|
||||
|
||||
Caption := lisLazDocMainFormCaption;
|
||||
@ -313,7 +315,6 @@ begin
|
||||
ClearInherited(false);
|
||||
Application.RemoveAllHandlersOfObject(Self);
|
||||
FreeAndNil(fEntry);
|
||||
FreeAndNil(FLazDocBoss);
|
||||
end;
|
||||
|
||||
procedure TLazDocForm.FormResize(Sender: TObject);
|
||||
@ -754,7 +755,7 @@ begin
|
||||
if not Entry.DocFilenameValid then begin
|
||||
Entry.DocFilenameValid:=true;
|
||||
Entry.DocFilename:=
|
||||
LazDocBoss.GetFPDocFilenameForSource(Entry.SrcFilename,true);
|
||||
LazDocBoss.GetFPDocFilenameForSource(Entry.SrcFilename,true);
|
||||
//DebugLn(['TLazDocForm.UpdateInheritedEntries Source=',Entry.SrcFilename,' -> FPDoc=',Entry.DocFilename]);
|
||||
if not All then exit;
|
||||
end;
|
||||
|
133
ide/lazdochints.pas
Normal file
133
ide/lazdochints.pas
Normal file
@ -0,0 +1,133 @@
|
||||
{
|
||||
***************************************************************************
|
||||
* *
|
||||
* This source is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License as published by *
|
||||
* the Free Software Foundation; either version 2 of the License, or *
|
||||
* (at your option) any later version. *
|
||||
* *
|
||||
* This code is distributed in the hope that it will be useful, but *
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
|
||||
* General Public License for more details. *
|
||||
* *
|
||||
* A copy of the GNU General Public License is available on the World *
|
||||
* Wide Web at <http://www.gnu.org/copyleft/gpl.html>. You can also *
|
||||
* obtain it by writing to the Free Software Foundation, *
|
||||
* Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||
* *
|
||||
***************************************************************************
|
||||
|
||||
Author: Mattias Gaertner
|
||||
|
||||
Abstract:
|
||||
Hint using the lazdoc data.
|
||||
}
|
||||
unit LazDocHints;
|
||||
|
||||
{$mode objfpc}{$H+}
|
||||
|
||||
interface
|
||||
|
||||
uses
|
||||
Classes, SysUtils, LCLProc, Forms, Controls, Graphics,
|
||||
CodeToolManager, CodeCache, BasicCodeTools, IdentCompletionTool,
|
||||
SrcEditorIntf,
|
||||
CodeHelpForm, LazDoc;
|
||||
|
||||
type
|
||||
|
||||
{ TLazDocHintProvider }
|
||||
|
||||
TLazDocHintProvider = class(TCodeHintProvider)
|
||||
private
|
||||
FHintValid: boolean;
|
||||
FWaitingForIdle: boolean;
|
||||
procedure SetHintValid(const AValue: boolean);
|
||||
procedure SetWaitingForIdle(const AValue: boolean);
|
||||
procedure ApplicationIdle(Sender: TObject; var Done: Boolean);
|
||||
procedure ReadLazDocData;
|
||||
public
|
||||
destructor Destroy; override;
|
||||
procedure Paint(Canvas: TCanvas; const ARect: TRect); override;
|
||||
procedure UpdateHint; override;
|
||||
property WaitingForIdle: boolean read FWaitingForIdle write SetWaitingForIdle;
|
||||
property HintValid: boolean read FHintValid write SetHintValid;
|
||||
end;
|
||||
|
||||
implementation
|
||||
|
||||
{ TLazDocHintProvider }
|
||||
|
||||
procedure TLazDocHintProvider.SetWaitingForIdle(const AValue: boolean);
|
||||
begin
|
||||
if FWaitingForIdle=AValue then exit;
|
||||
FWaitingForIdle:=AValue;
|
||||
if Application<>nil then begin
|
||||
if FWaitingForIdle then
|
||||
Application.AddOnIdleHandler(@ApplicationIdle)
|
||||
else
|
||||
Application.RemoveOnIdleHandler(@ApplicationIdle);
|
||||
end;
|
||||
end;
|
||||
|
||||
procedure TLazDocHintProvider.SetHintValid(const AValue: boolean);
|
||||
begin
|
||||
if FHintValid=AValue then exit;
|
||||
FHintValid:=AValue;
|
||||
end;
|
||||
|
||||
procedure TLazDocHintProvider.ApplicationIdle(Sender: TObject; var Done: Boolean
|
||||
);
|
||||
begin
|
||||
WaitingForIdle:=false;
|
||||
ReadLazDocData;
|
||||
end;
|
||||
|
||||
procedure TLazDocHintProvider.ReadLazDocData;
|
||||
var
|
||||
Position: LongInt;
|
||||
Item: TIdentifierListItem;
|
||||
Code: TCodeBuffer;
|
||||
DocFilename: String;
|
||||
begin
|
||||
if (SourceEditorWindow=nil) or (CodeToolBoss=nil)
|
||||
or (CodeToolBoss.IdentifierList=nil) then
|
||||
exit;
|
||||
Position:=SourceEditorWindow.CompletionBoxPosition;
|
||||
if (Position<0) or (Position>=CodeToolBoss.IdentifierList.GetFilteredCount) then
|
||||
exit;
|
||||
Item:=CodeToolBoss.IdentifierList.FilteredItems[Position];
|
||||
DebugLn(['TLazDocHintProvider.ReadLazDocData Identifier=',GetIdentifier(Item.Identifier)]);
|
||||
if (Item.Node<>nil) then begin
|
||||
if (Item.Tool.Scanner=nil) then exit;
|
||||
Code:=TCodeBuffer(Item.Tool.Scanner.MainCode);
|
||||
if Code=nil then exit;
|
||||
DocFilename:=LazDocBoss.GetFPDocFilenameForSource(Code.Filename,false);
|
||||
if DocFilename='' then exit;
|
||||
DebugLn(['TLazDocHintProvider.ReadLazDocData DocFilename=',DocFilename]);
|
||||
end else begin
|
||||
|
||||
end;
|
||||
end;
|
||||
|
||||
destructor TLazDocHintProvider.Destroy;
|
||||
begin
|
||||
WaitingForIdle:=false;
|
||||
inherited Destroy;
|
||||
end;
|
||||
|
||||
procedure TLazDocHintProvider.Paint(Canvas: TCanvas; const ARect: TRect);
|
||||
begin
|
||||
|
||||
|
||||
end;
|
||||
|
||||
procedure TLazDocHintProvider.UpdateHint;
|
||||
begin
|
||||
WaitingForIdle:=true;
|
||||
inherited UpdateHint;
|
||||
end;
|
||||
|
||||
end.
|
||||
|
@ -59,7 +59,8 @@ uses
|
||||
EnvironmentOpts, MsgView, SearchResultView, InputHistory, CodeMacroPrompt,
|
||||
CodeTemplatesDlg,
|
||||
SortSelectionDlg, EncloseSelectionDlg, DiffDialog, ConDef, InvertAssignTool,
|
||||
SourceEditProcs, SourceMarks, CharacterMapDlg, frmSearch, LazDocFrm,
|
||||
SourceEditProcs, SourceMarks, CharacterMapDlg, frmSearch,
|
||||
LazDocHints, LazDocFrm,
|
||||
BaseDebugManager, Debugger, MainIntf, TodoDlg;
|
||||
|
||||
type
|
||||
@ -573,19 +574,20 @@ type
|
||||
procedure OnApplicationUserInput(Sender: TObject; Msg: Cardinal);
|
||||
procedure ShowSynEditHint(const MousePos: TPoint);
|
||||
|
||||
Procedure NextEditor;
|
||||
Procedure PrevEditor;
|
||||
procedure NextEditor;
|
||||
procedure PrevEditor;
|
||||
procedure MoveEditor(OldPageIndex, NewPageIndex: integer);
|
||||
procedure MoveEditorLeft(PageIndex: integer);
|
||||
procedure MoveEditorRight(PageIndex: integer);
|
||||
procedure MoveActivePageLeft;
|
||||
procedure MoveActivePageRight;
|
||||
Procedure ProcessParentCommand(Sender: TObject;
|
||||
procedure ProcessParentCommand(Sender: TObject;
|
||||
var Command: TSynEditorCommand; var AChar: TUTF8Char; Data: pointer;
|
||||
var Handled: boolean);
|
||||
Procedure ParentCommandProcessed(Sender: TObject;
|
||||
procedure ParentCommandProcessed(Sender: TObject;
|
||||
var Command: TSynEditorCommand; var AChar: TUTF8Char; Data: pointer;
|
||||
var Handled: boolean);
|
||||
function GetCompletionBoxPosition: integer; override;
|
||||
|
||||
// marks
|
||||
function FindBookmark(BookmarkID: integer): TSourceEditor;
|
||||
@ -621,7 +623,7 @@ type
|
||||
function FindSourceEditorWithEditorComponent(
|
||||
EditorComp: TComponent): TSourceEditor;
|
||||
function FindSourceEditorWithFilename(const Filename: string): TSourceEditor;
|
||||
Function GetActiveSE: TSourceEditor;
|
||||
function GetActiveSE: TSourceEditor;
|
||||
procedure SetActiveSE(SrcEdit: TSourceEditor);
|
||||
function GetActiveEditor: TSourceEditorInterface; override;
|
||||
procedure SetActiveEditor(const AValue: TSourceEditorInterface); override;
|
||||
@ -633,11 +635,11 @@ type
|
||||
procedure GetSourceText(PageIndex: integer; OnlySelection: boolean;
|
||||
var Source: string);
|
||||
|
||||
Function ActiveFileName: AnsiString;
|
||||
Function FindUniquePageName(FileName:string; IgnorePageIndex:integer):string;
|
||||
function ActiveFileName: AnsiString;
|
||||
function FindUniquePageName(FileName:string; IgnorePageIndex:integer):string;
|
||||
function SomethingModified: boolean;
|
||||
procedure UpdateStatusBar;
|
||||
Procedure ClearUnusedEditorComponents(Force: boolean);
|
||||
procedure ClearUnusedEditorComponents(Force: boolean);
|
||||
procedure ClearErrorLines; override;
|
||||
procedure ClearExecutionLines;
|
||||
|
||||
@ -703,17 +705,17 @@ type
|
||||
procedure CopyFilenameClicked(Sender: TObject);
|
||||
|
||||
// bookmarks
|
||||
Procedure ToggleBookmark(Value: Integer);
|
||||
Procedure SetBookmark(Value: Integer);
|
||||
Procedure GotoBookmark(Value: Integer);
|
||||
procedure ToggleBookmark(Value: Integer);
|
||||
procedure SetBookmark(Value: Integer);
|
||||
procedure GotoBookmark(Value: Integer);
|
||||
|
||||
Procedure ReloadEditorOptions;
|
||||
procedure ReloadEditorOptions;
|
||||
procedure CheckFont;
|
||||
Procedure GetSynEditPreviewSettings(APreviewEditor: TObject);
|
||||
procedure GetSynEditPreviewSettings(APreviewEditor: TObject);
|
||||
function GetEditorControlSettings(EditControl: TControl): boolean; override;
|
||||
function GetHighlighterSettings(Highlighter: TObject): boolean; override;
|
||||
|
||||
Property CodeTemplateModul: TSynEditAutoComplete
|
||||
property CodeTemplateModul: TSynEditAutoComplete
|
||||
read FCodeTemplateModul write FCodeTemplateModul;
|
||||
procedure OnCodeTemplateTokenNotFound(Sender: TObject; AToken: string;
|
||||
AnEditor: TCustomSynEdit; var Index:integer);
|
||||
@ -726,7 +728,7 @@ type
|
||||
|
||||
procedure FindReplaceDlgKey(Sender: TObject; var Key: Word;
|
||||
Shift: TShiftState; FindDlgComponent: TFindDlgComponent);
|
||||
published
|
||||
public
|
||||
property OnAddJumpPoint: TOnAddJumpPoint
|
||||
read FOnAddJumpPoint write FOnAddJumpPoint;
|
||||
property OnCloseClicked: TOnCloseSrcEditor
|
||||
@ -2169,7 +2171,7 @@ Begin
|
||||
OnCommandProcessed := @UserCommandProcessed;
|
||||
OnReplaceText := @OnReplace;
|
||||
OnGutterClick := @Self.OnGutterClick;
|
||||
OnSpecialLineColors:=@OnEditorSpecialLineColor;
|
||||
OnSpecialLineColors := @OnEditorSpecialLineColor;
|
||||
OnMouseMove := @EditorMouseMoved;
|
||||
OnMouseWheel := @EditorMouseWheel;
|
||||
OnMouseDown := @EditorMouseDown;
|
||||
@ -4008,6 +4010,13 @@ begin
|
||||
SrcEditMenuEditorProperties.OnClick:=@EditorPropertiesClicked;
|
||||
end;
|
||||
|
||||
function TSourceNotebook.GetCompletionBoxPosition: integer;
|
||||
begin
|
||||
Result:=-1;
|
||||
if CurCompletionControl<>nil then
|
||||
Result:=CurCompletionControl.Position;
|
||||
end;
|
||||
|
||||
procedure TSourceNotebook.UpdateHighlightMenuItems;
|
||||
var
|
||||
h: TLazSyntaxHighlighter;
|
||||
@ -4759,6 +4768,7 @@ begin
|
||||
if CodeHelpFrm=nil then begin
|
||||
CodeHelpFrm:=TCodeHelpFrm.Create(Self);
|
||||
CodeHelpFrm.Name:='TSourceNotebook_CodeHelpFrm';
|
||||
CodeHelpFrm.Provider:=TLazDocHintProvider.Create(CodeHelpFrm);
|
||||
end;
|
||||
CodeHelpFrm.AnchorForm:=CurCompletionControl.TheForm;
|
||||
{$IFDEF EnableCodeHelp}
|
||||
|
@ -141,6 +141,7 @@ type
|
||||
protected
|
||||
function GetActiveEditor: TSourceEditorInterface; virtual; abstract;
|
||||
procedure SetActiveEditor(const AValue: TSourceEditorInterface); virtual; abstract;
|
||||
function GetCompletionBoxPosition: integer; virtual; abstract;
|
||||
public
|
||||
function SourceEditorIntfWithFilename(
|
||||
const Filename: string): TSourceEditorInterface;
|
||||
@ -152,6 +153,8 @@ type
|
||||
function GetEditorControlSettings(EditControl: TControl): boolean; virtual; abstract;
|
||||
function GetHighlighterSettings(Highlighter: TObject): boolean; virtual; abstract;
|
||||
procedure ClearErrorLines; virtual; abstract;
|
||||
|
||||
property CompletionBoxPosition: integer read GetCompletionBoxPosition;
|
||||
end;
|
||||
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user