mirror of
https://github.com/HeidiSQL/HeidiSQL.git
synced 2025-08-26 20:50:20 +08:00
Add support for Windows 7 task button progress. Unify all callers of ProgressBarStatus in a set of 5 functions in main unit instead of helpers, as this is where the progress bar is placed and also we need the handle of the main window.
This commit is contained in:
@ -4,7 +4,7 @@ interface
|
||||
|
||||
uses
|
||||
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
|
||||
Dialogs, StdCtrls, ExtCtrls, Menus, VirtualTrees, SynExportHTML;
|
||||
Dialogs, StdCtrls, ExtCtrls, Menus, ComCtrls, VirtualTrees, SynExportHTML;
|
||||
|
||||
type
|
||||
TGridExportFormat = (efExcel, efCSV, efHTML, efXML, efSQLInsert, efSQLReplace, efLaTeX, efWiki);
|
||||
@ -391,7 +391,7 @@ begin
|
||||
NodeCount := Grid.SelectedCount
|
||||
else
|
||||
NodeCount := Grid.RootNodeCount;
|
||||
EnableProgressBar(NodeCount);
|
||||
MainForm.EnableProgress(NodeCount);
|
||||
TableName := BestTableName(GridData);
|
||||
|
||||
if radioOutputCopyToClipboard.Checked then
|
||||
@ -522,7 +522,7 @@ begin
|
||||
Mainform.ShowStatusMsg('Exporting row '+FormatNumber(Node.Index+1)+' of '+FormatNumber(NodeCount)+
|
||||
' ('+IntToStr(Trunc((Node.Index+1) / NodeCount *100))+'%, '+FormatByteNumber(S.Size)+')'
|
||||
);
|
||||
Mainform.ProgressBarStatus.Position := Node.Index+1;
|
||||
MainForm.ProgressStep;
|
||||
end;
|
||||
RowNum := Grid.GetNodeData(Node);
|
||||
GridData.RecNo := RowNum^;
|
||||
@ -681,12 +681,13 @@ begin
|
||||
on E:EFCreateError do begin
|
||||
// Keep form open if file cannot be created
|
||||
ModalResult := mrNone;
|
||||
MainForm.SetProgressState(pbsError);
|
||||
ErrorDialog(E.Message);
|
||||
end;
|
||||
end;
|
||||
end;
|
||||
|
||||
Mainform.ProgressBarStatus.Visible := False;
|
||||
Mainform.DisableProgress;
|
||||
Mainform.ShowStatusMsg('Freeing data...');
|
||||
FreeAndNil(S);
|
||||
Mainform.ShowStatusMsg;
|
||||
|
@ -153,7 +153,6 @@ type
|
||||
function GetRegValue( valueName: String; defaultValue: Boolean; Session: String = '' ) : Boolean; Overload;
|
||||
function GetRegValue( valueName: String; defaultValue: String; Session: String = '' ) : String; Overload;
|
||||
procedure DeInitializeVTNodes(Sender: TBaseVirtualTree);
|
||||
procedure EnableProgressBar(MaxValue: Integer);
|
||||
function CompareNumbers(List: TStringList; Index1, Index2: Integer): Integer;
|
||||
function ListIndexByRegExpr(List: TStrings; Expression: String): Integer;
|
||||
function FindNode(VT: TVirtualStringTree; idx: Cardinal; ParentNode: PVirtualNode): PVirtualNode;
|
||||
@ -1678,15 +1677,6 @@ begin
|
||||
end;
|
||||
|
||||
|
||||
procedure EnableProgressBar(MaxValue: Integer);
|
||||
begin
|
||||
Mainform.ProgressBarStatus.State := pbsNormal;
|
||||
Mainform.ProgressBarStatus.Visible := True;
|
||||
Mainform.ProgressBarStatus.Max := MaxValue;
|
||||
Mainform.ProgressBarStatus.Position := 0;
|
||||
end;
|
||||
|
||||
|
||||
function CompareNumbers(List: TStringList; Index1, Index2: Integer): Integer;
|
||||
var
|
||||
Number1, Number2 : Extended;
|
||||
|
@ -612,7 +612,7 @@ var
|
||||
begin
|
||||
// Insert files
|
||||
Screen.Cursor := crHourglass;
|
||||
EnableProgressBar(ListFiles.RootNodeCount);
|
||||
MainForm.EnableProgress(ListFiles.RootNodeCount);
|
||||
|
||||
Node := ListFiles.GetFirst;
|
||||
while Assigned(Node) do begin
|
||||
@ -670,11 +670,11 @@ begin
|
||||
sql := sql + ')';
|
||||
try
|
||||
FConnection.Query(sql);
|
||||
Mainform.ProgressBarStatus.StepIt;
|
||||
Mainform.ProgressBarStatus.Repaint;
|
||||
Mainform.ProgressStep;
|
||||
except
|
||||
on E:EDatabaseError do begin
|
||||
Screen.Cursor := crDefault;
|
||||
MainForm.SetProgressState(pbsError);
|
||||
ErrorDialog(E.Message);
|
||||
ModalResult := mrNone;
|
||||
break;
|
||||
@ -685,7 +685,7 @@ begin
|
||||
ListFiles.DeleteNode(DoneNode);
|
||||
end;
|
||||
Screen.Cursor := crDefault;
|
||||
Mainform.ProgressBarStatus.Hide;
|
||||
MainForm.DisableProgress;
|
||||
end;
|
||||
|
||||
|
||||
|
@ -85,6 +85,8 @@ uses Main, helpers;
|
||||
|
||||
{$R *.DFM}
|
||||
|
||||
const
|
||||
ProgressBarSteps=100;
|
||||
|
||||
|
||||
procedure Tloaddataform.FormCreate(Sender: TObject);
|
||||
@ -275,6 +277,7 @@ var
|
||||
begin
|
||||
Screen.Cursor := crHourglass;
|
||||
StartTickCount := GetTickCount;
|
||||
MainForm.EnableProgress(ProgressBarSteps);
|
||||
|
||||
ColumnCount := 0;
|
||||
for i:=0 to chkListColumns.Items.Count-1 do begin
|
||||
@ -320,11 +323,13 @@ begin
|
||||
on E:EDatabaseError do begin
|
||||
Screen.Cursor := crDefault;
|
||||
ModalResult := mrNone;
|
||||
MainForm.SetProgressState(pbsError);
|
||||
ErrorDialog(E.Message);
|
||||
end;
|
||||
end;
|
||||
|
||||
Mainform.ShowStatusMsg;
|
||||
MainForm.DisableProgress;
|
||||
Screen.Cursor := crDefault;
|
||||
end;
|
||||
|
||||
@ -405,15 +410,13 @@ var
|
||||
IsEncl, IsTerm, IsLineTerm: Boolean;
|
||||
InEncl: Boolean;
|
||||
OutStream: TMemoryStream;
|
||||
const
|
||||
ProgressBarSteps=100;
|
||||
|
||||
procedure NextChar;
|
||||
begin
|
||||
Inc(P);
|
||||
Inc(ProgressChars);
|
||||
if ProgressChars >= ProgressCharsPerStep then begin
|
||||
Mainform.ProgressBarStatus.StepIt;
|
||||
Mainform.ProgressStep;
|
||||
Mainform.ShowStatusMsg('Importing textfile, row '+FormatNumber(RowCount-IgnoreLines)+', '+IntToStr(Mainform.ProgressBarStatus.Position)+'%');
|
||||
ProgressChars := 0;
|
||||
end;
|
||||
@ -504,8 +507,6 @@ const
|
||||
end;
|
||||
|
||||
begin
|
||||
EnableProgressBar(ProgressBarSteps);
|
||||
|
||||
TermLen := Length(Term);
|
||||
EnclLen := Length(Encl);
|
||||
LineTermLen := Length(LineTerm);
|
||||
@ -567,7 +568,6 @@ begin
|
||||
Contents := '';
|
||||
FreeAndNil(OutStream);
|
||||
RowCount := Max(RowCount-IgnoreLines, 0);
|
||||
Mainform.ProgressBarStatus.Hide;
|
||||
end;
|
||||
|
||||
|
||||
|
130
source/main.pas
130
source/main.pas
@ -14,7 +14,7 @@ uses
|
||||
Messages, ExtCtrls, ComCtrls, StdActns, ActnList, ImgList, ToolWin, Clipbrd, SynMemo,
|
||||
SynEdit, SynEditTypes, SynEditKeyCmds, VirtualTrees, DateUtils, SyncObjs,
|
||||
ShlObj, SynEditMiscClasses, SynEditSearch, SynEditRegexSearch, SynCompletionProposal, SynEditHighlighter,
|
||||
SynHighlighterSQL, Tabs, SynUnicode, SynRegExpr, ExtActns, IOUtils, Types, Themes,
|
||||
SynHighlighterSQL, Tabs, SynUnicode, SynRegExpr, ExtActns, IOUtils, Types, Themes, ComObj,
|
||||
CommCtrl, Contnrs, Generics.Collections, SynEditExport, SynExportHTML, Math, ExtDlgs, Registry, AppEvnts,
|
||||
routine_editor, trigger_editor, event_editor, options, EditVar, helpers, createdatabase, table_editor,
|
||||
TableTools, View, Usermanager, SelectDBObject, connections, sqlhelp, dbconnection,
|
||||
@ -70,6 +70,34 @@ type
|
||||
destructor Destroy; override;
|
||||
end;
|
||||
|
||||
ITaskbarList = interface(IUnknown)
|
||||
[SID_ITaskbarList]
|
||||
function HrInit: HRESULT; stdcall;
|
||||
function AddTab(hwnd: HWND): HRESULT; stdcall;
|
||||
function DeleteTab(hwnd: HWND): HRESULT; stdcall;
|
||||
function ActivateTab(hwnd: HWND): HRESULT; stdcall;
|
||||
function SetActiveAlt(hwnd: HWND): HRESULT; stdcall;
|
||||
end;
|
||||
ITaskbarList2 = interface(ITaskbarList)
|
||||
[SID_ITaskbarList2]
|
||||
function MarkFullscreenWindow(hwnd: HWND; fFullscreen: BOOL): HRESULT; stdcall;
|
||||
end;
|
||||
ITaskbarList3 = interface(ITaskbarList2)
|
||||
[SID_ITaskbarList3]
|
||||
function SetProgressValue(hwnd: HWND; ullCompleted: ULONGLONG; ullTotal: ULONGLONG): HRESULT; stdcall;
|
||||
function SetProgressState(hwnd: HWND; tbpFlags: Integer): HRESULT; stdcall;
|
||||
function RegisterTab(hwndTab: HWND; hwndMDI: HWND): HRESULT; stdcall;
|
||||
function UnregisterTab(hwndTab: HWND): HRESULT; stdcall;
|
||||
function SetTabOrder(hwndTab: HWND; hwndInsertBefore: HWND): HRESULT; stdcall;
|
||||
function SetTabActive(hwndTab: HWND; hwndMDI: HWND; tbatFlags: Integer): HRESULT; stdcall;
|
||||
function ThumbBarAddButtons(hwnd: HWND; cButtons: UINT; pButton: PThumbButton): HRESULT; stdcall;
|
||||
function ThumbBarUpdateButtons(hwnd: HWND; cButtons: UINT; pButton: PThumbButton): HRESULT; stdcall;
|
||||
function ThumbBarSetImageList(hwnd: HWND; himl: HIMAGELIST): HRESULT; stdcall;
|
||||
function SetOverlayIcon(hwnd: HWND; hIcon: HICON; pszDescription: LPCWSTR): HRESULT; stdcall;
|
||||
function SetThumbnailTooltip(hwnd: HWND; pszTip: LPCWSTR): HRESULT; stdcall;
|
||||
function SetThumbnailClip(hwnd: HWND; var prcClip: TRect): HRESULT; stdcall;
|
||||
end;
|
||||
|
||||
TMainForm = class(TForm)
|
||||
MainMenu1: TMainMenu;
|
||||
File1: TMenuItem;
|
||||
@ -947,6 +975,12 @@ type
|
||||
AppVersion: String;
|
||||
AppDescription: String;
|
||||
|
||||
// Task button interface
|
||||
TaskbarList: ITaskbarList;
|
||||
TaskbarList2: ITaskbarList2;
|
||||
TaskbarList3: ITaskbarList3;
|
||||
TaskbarList4: ITaskbarList4;
|
||||
|
||||
property Connections: TDBConnectionList read FConnections;
|
||||
property Delimiter: String read FDelimiter write SetDelimiter;
|
||||
procedure PaintColorBar(Value, Max: Extended; TargetCanvas: TCanvas; CellRect: TRect);
|
||||
@ -990,6 +1024,11 @@ type
|
||||
procedure BeforeQueryExecution(Thread: TQueryThread);
|
||||
procedure AfterQueryExecution(Thread: TQueryThread);
|
||||
procedure FinishedQueryExecution(Thread: TQueryThread);
|
||||
procedure EnableProgress(MaxValue: Integer);
|
||||
procedure DisableProgress;
|
||||
procedure SetProgressPosition(Value: Integer);
|
||||
procedure ProgressStep;
|
||||
procedure SetProgressState(State: TProgressbarState);
|
||||
end;
|
||||
|
||||
|
||||
@ -1295,6 +1334,15 @@ begin
|
||||
FIsWine := Assigned(wine_nt_to_unix_file_name);
|
||||
FreeLibrary(NTHandle);
|
||||
|
||||
// Taskbar button interface for Windows 7
|
||||
if CheckWin32Version(6, 1) then begin
|
||||
TaskbarList := CreateComObject(CLSID_TaskbarList) as ITaskbarList;
|
||||
TaskbarList.HrInit;
|
||||
Supports(TaskbarList, IID_ITaskbarList2, TaskbarList2);
|
||||
Supports(TaskbarList, IID_ITaskbarList3, TaskbarList3);
|
||||
Supports(TaskbarList, IID_ITaskbarList4, TaskbarList4);
|
||||
end;
|
||||
|
||||
// "All users" folder for HeidiSQL's data (All Users\Application Data)
|
||||
FDirnameCommonAppData := GetShellFolder(CSIDL_COMMON_APPDATA) + '\' + APPNAME + '\';
|
||||
|
||||
@ -2174,7 +2222,7 @@ begin
|
||||
Batch := SplitSQL(Text);
|
||||
Text := '';
|
||||
|
||||
EnableProgressBar(Batch.Count);
|
||||
EnableProgress(Batch.Count);
|
||||
Tab.ResultTabs.Clear;
|
||||
Tab.tabsetQuery.Tabs.Clear;
|
||||
FreeAndNil(Tab.QueryProfile);
|
||||
@ -2207,7 +2255,7 @@ begin
|
||||
if Thread.QueriesInPacket > 1 then
|
||||
Text := 'queries #' + FormatNumber(Thread.BatchPosition+1) + ' to #' + FormatNumber(Thread.BatchPosition+Thread.QueriesInPacket);
|
||||
ShowStatusMsg('Executing '+Text+' of '+FormatNumber(Thread.Batch.Count)+' ...');
|
||||
ProgressBarStatus.Position := Thread.BatchPosition;
|
||||
SetProgressPosition(Thread.BatchPosition);
|
||||
end;
|
||||
|
||||
|
||||
@ -2298,7 +2346,7 @@ begin
|
||||
|
||||
// Error handling
|
||||
if IsNotEmpty(Thread.ErrorMessage) then begin
|
||||
ProgressBarStatus.State := pbsError;
|
||||
SetProgressState(pbsError);
|
||||
GoToErrorPos(Thread.ErrorMessage);
|
||||
ErrorDialog(Thread.ErrorMessage);
|
||||
end;
|
||||
@ -2335,7 +2383,7 @@ begin
|
||||
end;
|
||||
|
||||
// Clean up
|
||||
ProgressBarStatus.Hide;
|
||||
DisableProgress;
|
||||
Tab.QueryRunning := False;
|
||||
ValidateControls(Thread);
|
||||
OperationRunning(False);
|
||||
@ -2947,15 +2995,14 @@ begin
|
||||
if MessageDialog('Delete '+IntToStr(Grid.SelectedCount)+' row(s)?',
|
||||
mtConfirmation, [mbOK, mbCancel]) = mrOK then begin
|
||||
FocusAfterDelete := nil;
|
||||
EnableProgressBar(Grid.SelectedCount);
|
||||
EnableProgress(Grid.SelectedCount);
|
||||
Node := GetNextNode(Grid, nil, True);
|
||||
while Assigned(Node) do begin
|
||||
RowNum := Grid.GetNodeData(Node);
|
||||
ShowStatusMsg('Deleting row #'+FormatNumber(ProgressBarStatus.Position+1)+' of '+FormatNumber(ProgressBarStatus.Max)+' ...');
|
||||
Results.RecNo := RowNum^;
|
||||
if Results.DeleteRow then begin
|
||||
ProgressBarStatus.StepIt;
|
||||
ProgressBarStatus.Repaint;
|
||||
ProgressStep;
|
||||
SetLength(Nodes, Length(Nodes)+1);
|
||||
Nodes[Length(Nodes)-1] := Node;
|
||||
FocusAfterDelete := Node;
|
||||
@ -2978,11 +3025,11 @@ begin
|
||||
ValidateControls(Sender);
|
||||
end;
|
||||
except on E:EDatabaseError do begin
|
||||
ProgressBarStatus.State := pbsError;
|
||||
SetProgressState(pbsError);
|
||||
ErrorDialog('Grid editing error', E.Message);
|
||||
end;
|
||||
end;
|
||||
Mainform.ProgressBarStatus.Visible := False;
|
||||
DisableProgress;
|
||||
ShowStatusMsg();
|
||||
end;
|
||||
|
||||
@ -3048,24 +3095,24 @@ begin
|
||||
if MessageDialog('Empty '+IntToStr(Objects.count)+' table(s) and/or view(s) ?', Names,
|
||||
mtConfirmation, [mbOk, mbCancel]) = mrOk then begin
|
||||
Screen.Cursor := crHourglass;
|
||||
EnableProgressBar(Objects.Count);
|
||||
EnableProgress(Objects.Count);
|
||||
try
|
||||
for TableOrView in Objects do begin
|
||||
case TableOrView.Connection.Parameters.NetTypeGroup of
|
||||
ngMySQL: TableOrView.Connection.Query('TRUNCATE ' + TableOrView.QuotedName);
|
||||
ngMSSQL: TableOrView.Connection.Query('DELETE FROM ' + TableOrView.QuotedName);
|
||||
end;
|
||||
ProgressBarStatus.StepIt;
|
||||
ProgressStep;
|
||||
end;
|
||||
actRefresh.Execute;
|
||||
except
|
||||
on E:EDatabaseError do begin
|
||||
ProgressBarStatus.State := pbsError;
|
||||
SetProgressState(pbsError);
|
||||
ErrorDialog(E.Message);
|
||||
end;
|
||||
end;
|
||||
Objects.Free;
|
||||
ProgressBarStatus.Hide;
|
||||
DisableProgress;
|
||||
Screen.Cursor := crDefault;
|
||||
end;
|
||||
end;
|
||||
@ -10073,6 +10120,61 @@ begin
|
||||
end;
|
||||
|
||||
|
||||
procedure TMainForm.EnableProgress(MaxValue: Integer);
|
||||
begin
|
||||
// Initialize progres bar and button
|
||||
SetProgressPosition(0);
|
||||
SetProgressState(pbsNormal);
|
||||
ProgressBarStatus.Visible := True;
|
||||
ProgressBarStatus.Max := MaxValue;
|
||||
end;
|
||||
|
||||
|
||||
procedure TMainForm.DisableProgress;
|
||||
begin
|
||||
// Hide global progress bar
|
||||
SetProgressPosition(0);
|
||||
ProgressBarStatus.Hide;
|
||||
if Assigned(TaskBarList3) then
|
||||
TaskBarList3.SetProgressState(Application.MainForm.Handle, 0);
|
||||
end;
|
||||
|
||||
|
||||
procedure TMainForm.SetProgressPosition(Value: Integer);
|
||||
begin
|
||||
// Advance progress bar and task progress position
|
||||
ProgressBarStatus.Position := Value;
|
||||
ProgressBarStatus.Repaint;
|
||||
if Assigned(TaskBarList3) then
|
||||
TaskBarList3.SetProgressValue(Application.MainForm.Handle, Value, ProgressBarStatus.Max);
|
||||
end;
|
||||
|
||||
|
||||
procedure TMainForm.ProgressStep;
|
||||
begin
|
||||
SetProgressPosition(ProgressBarStatus.Position+1);
|
||||
end;
|
||||
|
||||
|
||||
procedure TMainForm.SetProgressState(State: TProgressbarState);
|
||||
var
|
||||
Flag: Integer;
|
||||
begin
|
||||
// Set error or pause state in progress bar or task button
|
||||
ProgressBarStatus.State := State;
|
||||
ProgressBarStatus.Repaint;
|
||||
if Assigned(TaskBarList3) then begin
|
||||
case State of
|
||||
pbsNormal: Flag := 2;
|
||||
pbsError: Flag := 4;
|
||||
pbsPaused: Flag := 8;
|
||||
else Flag := 0;
|
||||
end;
|
||||
TaskBarList3.SetProgressState(Application.MainForm.Handle, Flag);
|
||||
end;
|
||||
end;
|
||||
|
||||
|
||||
|
||||
{ TQueryTab }
|
||||
|
||||
|
@ -542,11 +542,11 @@ begin
|
||||
end;
|
||||
|
||||
// Update columns
|
||||
EnableProgressBar(FColumns.Count + DeletedKeys.Count + FKeys.Count);
|
||||
MainForm.EnableProgress(FColumns.Count + DeletedKeys.Count + FKeys.Count);
|
||||
Node := listColumns.GetFirst;
|
||||
PreviousCol := nil;
|
||||
while Assigned(Node) do begin
|
||||
Mainform.ProgressBarStatus.StepIt;
|
||||
Mainform.ProgressStep;
|
||||
Col := listColumns.GetNodeData(Node);
|
||||
if Col.Status <> esUntouched then begin
|
||||
ColSpec := DBObject.Connection.QuoteIdent(Col.Name);
|
||||
@ -602,7 +602,7 @@ begin
|
||||
|
||||
// Drop indexes, also changed indexes, which will be readded below
|
||||
for i:=0 to DeletedKeys.Count-1 do begin
|
||||
Mainform.ProgressBarStatus.StepIt;
|
||||
Mainform.ProgressStep;
|
||||
if DeletedKeys[i] = PKEY then
|
||||
IndexSQL := 'PRIMARY KEY'
|
||||
else
|
||||
@ -611,7 +611,7 @@ begin
|
||||
end;
|
||||
// Add changed or added indexes
|
||||
for i:=0 to FKeys.Count-1 do begin
|
||||
Mainform.ProgressBarStatus.StepIt;
|
||||
Mainform.ProgressStep;
|
||||
if FKeys[i].Modified and (not FKeys[i].Added) then begin
|
||||
if FKeys[i].OldIndexType = PKEY then
|
||||
IndexSQL := 'PRIMARY KEY'
|
||||
@ -634,7 +634,7 @@ begin
|
||||
|
||||
FreeAndNil(Specs);
|
||||
Mainform.ShowStatusMsg;
|
||||
Mainform.ProgressBarStatus.Hide;
|
||||
MainForm.DisableProgress;
|
||||
Screen.Cursor := crDefault;
|
||||
end;
|
||||
|
||||
|
@ -537,7 +537,7 @@ begin
|
||||
FCancelled := False;
|
||||
FObjectSizesDone := 0;
|
||||
FObjectSizesDoneExact := 0;
|
||||
EnableProgressBar(100);
|
||||
MainForm.EnableProgress(100);
|
||||
SessionNode := TreeObjects.GetFirstChild(nil);
|
||||
while Assigned(SessionNode) do begin
|
||||
DBNode := TreeObjects.GetFirstChild(SessionNode);
|
||||
@ -607,7 +607,7 @@ begin
|
||||
|
||||
btnCloseOrCancel.Caption := 'Close';
|
||||
btnCloseOrCancel.ModalResult := mrCancel;
|
||||
Mainform.ProgressBarStatus.Hide;
|
||||
MainForm.DisableProgress;
|
||||
tabsTools.Enabled := True;
|
||||
treeObjects.Enabled := True;
|
||||
ValidateControls(Sender);
|
||||
@ -793,7 +793,7 @@ begin
|
||||
Percent := 100 / Max(FObjectSizes,1) * FObjectSizesDoneExact;
|
||||
lblCheckedSize.Caption := 'Selected objects size: '+FormatByteNumber(FObjectSizes)+'. '+
|
||||
FormatNumber(Percent, 1) + '% done.';
|
||||
Mainform.ProgressBarStatus.Position := Round(Percent);
|
||||
MainForm.SetProgressPosition(Round(Percent));
|
||||
Application.ProcessMessages;
|
||||
end;
|
||||
|
||||
|
Reference in New Issue
Block a user