jj
This commit is contained in:
441
DocumentViewer/DocumentViewer.vb
Normal file
441
DocumentViewer/DocumentViewer.vb
Normal file
@@ -0,0 +1,441 @@
|
||||
Imports System.ComponentModel
|
||||
Imports System.Globalization
|
||||
Imports System.Text.RegularExpressions
|
||||
Imports GdPicture14
|
||||
|
||||
Public Class DocumentViewer
|
||||
Private Enum ZoomMode
|
||||
Zoom50
|
||||
Zoom100
|
||||
Zoom150
|
||||
Zoom200
|
||||
ZoomSelectedArea
|
||||
ZoomFitToViewer
|
||||
ZoomFitWidth
|
||||
ZoomFitHeight
|
||||
End Enum
|
||||
|
||||
Private _docPath As String
|
||||
Private _currentSearchOccurence As Integer = 0
|
||||
Private _toggleGamma As Boolean = True
|
||||
Private _licenseKey As String = String.Empty
|
||||
|
||||
Public Sub Init(LicenseKey As String)
|
||||
Dim oLicenceManager As New GdPicture14.LicenseManager()
|
||||
oLicenceManager.RegisterKEY(LicenseKey) 'Please, replace XXXX by a valid demo or commercial license key.
|
||||
End Sub
|
||||
|
||||
Private Sub DocumentViewer_Load(sender As Object, e As EventArgs) Handles Me.Load
|
||||
Dim zoomModes As New Dictionary(Of ZoomMode, String) From {
|
||||
{ZoomMode.Zoom50, "50%"},
|
||||
{ZoomMode.Zoom100, "100%"},
|
||||
{ZoomMode.Zoom150, "150%"},
|
||||
{ZoomMode.Zoom200, "200%"},
|
||||
{ZoomMode.ZoomSelectedArea, "Zoom to selected area"},
|
||||
{ZoomMode.ZoomFitToViewer, "Fit to viewer"},
|
||||
{ZoomMode.ZoomFitWidth, "Fit to viewer width"},
|
||||
{ZoomMode.ZoomFitHeight, "Fit to viewer height"}
|
||||
}
|
||||
|
||||
For Each item In zoomModes
|
||||
cbZoom.Items.Add(item.Value)
|
||||
Next
|
||||
|
||||
UpdateMainUi()
|
||||
End Sub
|
||||
|
||||
Public Sub Load_File_from_Path(filepath As String)
|
||||
CloseDocument()
|
||||
_docPath = filepath
|
||||
ToolStripStatusLabel2.Text = _docPath
|
||||
GdViewer1.ZoomMode = ViewerZoomMode.ZoomModeWidthViewer
|
||||
GdViewer1.DocumentAlignment = ViewerDocumentAlignment.DocumentAlignmentTopCenter
|
||||
|
||||
GdViewer1.DisplayFromFile(filepath)
|
||||
GdViewer1.Focus()
|
||||
UpdateMainUi()
|
||||
End Sub
|
||||
|
||||
Private Sub CloseDocument()
|
||||
GdViewer1.CloseDocument()
|
||||
UpdateMainUi()
|
||||
End Sub
|
||||
|
||||
Private Sub btnOpen_Click(sender As Object, e As EventArgs) Handles btnOpen.Click
|
||||
CloseDocument()
|
||||
|
||||
GdViewer1.ZoomMode = ViewerZoomMode.ZoomModeWidthViewer
|
||||
GdViewer1.DocumentAlignment = ViewerDocumentAlignment.DocumentAlignmentTopCenter
|
||||
|
||||
If OpenFileDialog.ShowDialog() = DialogResult.OK Then
|
||||
GdViewer1.DisplayFromFile(OpenFileDialog.FileName)
|
||||
End If
|
||||
|
||||
GdViewer1.Focus()
|
||||
UpdateMainUi()
|
||||
End Sub
|
||||
|
||||
Private Function GetDocumentTypeLabel() As String
|
||||
Dim result As String = ""
|
||||
Select Case GdViewer1.GetDocumentType()
|
||||
Case DocumentType.DocumentTypeBitmap
|
||||
result = "Bilddatei"
|
||||
Case DocumentType.DocumentTypeMetaFile
|
||||
result = "Metafile"
|
||||
Case DocumentType.DocumentTypePDF
|
||||
result = "PDF"
|
||||
Case DocumentType.DocumentTypeSVG
|
||||
result = "SVG"
|
||||
Case DocumentType.DocumentTypeTXT
|
||||
result = "Textdatei"
|
||||
Case DocumentType.DocumentTypeUnknown
|
||||
result = "Unbekannt"
|
||||
End Select
|
||||
Return result
|
||||
End Function
|
||||
|
||||
Private Sub UpdateMainUi()
|
||||
If GdViewer1.PageCount = 0 Then
|
||||
btnOpen.Enabled = True
|
||||
btnPrint.Enabled = False
|
||||
btnFirstPage.Enabled = False
|
||||
btnPreviousPage.Enabled = False
|
||||
tbCurrentPage.Enabled = False
|
||||
lblPageCount.Enabled = False
|
||||
btnNextPage.Enabled = False
|
||||
btnLastPage.Enabled = False
|
||||
btnZoomOut.Enabled = False
|
||||
cbZoom.Enabled = False
|
||||
btnZoomIn.Enabled = False
|
||||
btnFitPage.Enabled = False
|
||||
btnFitWidth.Enabled = False
|
||||
btnRotateLeft.Enabled = False
|
||||
btnRotateRight.Enabled = False
|
||||
btnFlipX.Enabled = False
|
||||
btnFlipY.Enabled = False
|
||||
tbCurrentPage.Text = "0"
|
||||
lblPageCount.Text = "/ 0"
|
||||
cbZoom.SelectedIndex = -1
|
||||
Else
|
||||
btnOpen.Enabled = False
|
||||
btnPrint.Enabled = True
|
||||
btnFirstPage.Enabled = True
|
||||
btnPreviousPage.Enabled = True
|
||||
tbCurrentPage.Enabled = True
|
||||
lblPageCount.Enabled = True
|
||||
btnNextPage.Enabled = True
|
||||
btnLastPage.Enabled = True
|
||||
btnZoomOut.Enabled = True
|
||||
cbZoom.Enabled = True
|
||||
btnZoomIn.Enabled = True
|
||||
btnFitPage.Enabled = True
|
||||
btnFitWidth.Enabled = True
|
||||
btnRotateLeft.Enabled = True
|
||||
btnRotateRight.Enabled = True
|
||||
btnFlipX.Enabled = True
|
||||
btnFlipY.Enabled = True
|
||||
UpdateaNavigationToolbar()
|
||||
End If
|
||||
End Sub
|
||||
|
||||
Private Sub btnFirstPage_Click(ByVal sender As System.Object, ByVal e As EventArgs) Handles btnFirstPage.Click
|
||||
GdViewer1.DisplayFirstPage()
|
||||
End Sub
|
||||
|
||||
Private Sub btnPreviousPage_Click(ByVal sender As System.Object, ByVal e As EventArgs) Handles btnPreviousPage.Click
|
||||
GdViewer1.DisplayPreviousPage()
|
||||
End Sub
|
||||
|
||||
Private Sub btnNextPage_Click(ByVal sender As System.Object, ByVal e As EventArgs) Handles btnNextPage.Click
|
||||
GdViewer1.DisplayNextPage()
|
||||
End Sub
|
||||
|
||||
Private Sub btnLastPage_Click(ByVal sender As System.Object, ByVal e As EventArgs) Handles btnLastPage.Click
|
||||
GdViewer1.DisplayLastPage()
|
||||
End Sub
|
||||
|
||||
Private Sub tbCurrentPage_Leave(ByVal sender As System.Object, ByVal e As EventArgs) Handles tbCurrentPage.Leave
|
||||
Dim page As Integer = 0
|
||||
If Integer.TryParse(tbCurrentPage.Text, page) Then
|
||||
If page > 0 And page <= GdViewer1.PageCount Then
|
||||
GdViewer1.DisplayPage(page)
|
||||
UpdateaNavigationToolbar()
|
||||
End If
|
||||
End If
|
||||
End Sub
|
||||
|
||||
Private Sub GdViewer1_PageChanged() Handles GdViewer1.PageChanged
|
||||
UpdateaNavigationToolbar()
|
||||
End Sub
|
||||
|
||||
Private Sub ChangeZoomValue()
|
||||
If cbZoom.SelectedIndex <> -1 Then
|
||||
Select Case CType(cbZoom.SelectedIndex, ZoomMode)
|
||||
Case ZoomMode.Zoom50
|
||||
GdViewer1.Zoom = 50.0F / 100
|
||||
Case ZoomMode.Zoom100
|
||||
GdViewer1.Zoom = 100.0F / 100
|
||||
Case ZoomMode.Zoom150
|
||||
GdViewer1.Zoom = 150.0F / 100
|
||||
Case ZoomMode.Zoom200
|
||||
GdViewer1.Zoom = 250.0F / 100
|
||||
Case ZoomMode.ZoomSelectedArea
|
||||
If GdViewer1.IsRect() Then
|
||||
GdViewer1.ZoomRect()
|
||||
Else
|
||||
GdViewer1.MouseMode = ViewerMouseMode.MouseModeAreaSelection
|
||||
GdViewer1.Focus()
|
||||
End If
|
||||
Case ZoomMode.ZoomFitToViewer
|
||||
GdViewer1.ZoomMode = ViewerZoomMode.ZoomModeFitToViewer
|
||||
Case ZoomMode.ZoomFitWidth
|
||||
GdViewer1.ZoomMode = ViewerZoomMode.ZoomModeWidthViewer
|
||||
Case ZoomMode.ZoomFitHeight
|
||||
GdViewer1.ZoomMode = ViewerZoomMode.ZoomModeHeightViewer
|
||||
End Select
|
||||
Else
|
||||
If (IsNumeric(Regex.Replace(cbZoom.Text, "[^0-9,.]", ""))) Then
|
||||
GdViewer1.Zoom = Val(Regex.Replace(cbZoom.Text, "[^0-9,.]", "")) / 100
|
||||
End If
|
||||
End If
|
||||
UpdateaNavigationToolbar()
|
||||
End Sub
|
||||
|
||||
Private Sub cbZoom_SelectedIndexChanged(ByVal sender As System.Object, ByVal e As EventArgs) Handles cbZoom.SelectedIndexChanged
|
||||
ChangeZoomValue()
|
||||
End Sub
|
||||
|
||||
Private Sub GdViewer1_AfterZoomChange() Handles GdViewer1.AfterZoomChange
|
||||
UpdateaNavigationToolbar()
|
||||
If GdViewer1.MouseMode = ViewerMouseMode.MouseModeAreaZooming Then
|
||||
GdViewer1.MouseMode = ViewerMouseMode.MouseModePan
|
||||
End If
|
||||
End Sub
|
||||
|
||||
Private Sub btnZoomOut_Click(ByVal sender As System.Object, ByVal e As EventArgs) Handles btnZoomOut.Click
|
||||
GdViewer1.ZoomOUT()
|
||||
End Sub
|
||||
|
||||
Private Sub btnZoomIn_Click(ByVal sender As System.Object, ByVal e As EventArgs) Handles btnZoomIn.Click
|
||||
GdViewer1.ZoomIN()
|
||||
End Sub
|
||||
|
||||
Private Sub cbZoom_TextUpdate(ByVal sender As System.Object, ByVal e As EventArgs) Handles cbZoom.Validating
|
||||
ChangeZoomValue()
|
||||
End Sub
|
||||
|
||||
Private Sub btnPrint_Click(ByVal sender As System.Object, ByVal e As EventArgs) Handles btnPrint.Click
|
||||
If GdViewer1.PageCount = 0 Then
|
||||
Return
|
||||
End If
|
||||
Using f As New frmViewerPrint(GdViewer1)
|
||||
f.ShowDialog(Me)
|
||||
If f.DialogResult <> DialogResult.OK Then
|
||||
Return
|
||||
End If
|
||||
Dim printSettings As frmViewerPrint.PrintSettings = f.printConfiguration
|
||||
If Not GdViewer1.PrintSetActivePrinter(printSettings.Printer) Then
|
||||
Return
|
||||
End If
|
||||
GdViewer1.PrintSetDocumentName("GdPicture Print Job " + DateTime.Now.ToString("yyyy-MM-dd HH\mm"))
|
||||
GdViewer1.PrintSetAlignment(printSettings.PrintAlignment)
|
||||
Select Case printSettings.Orientation
|
||||
Case frmViewerPrint.PrintOrientation.AutoDetection
|
||||
GdViewer1.PrintSetAutoRotation(True)
|
||||
Exit Select
|
||||
Case frmViewerPrint.PrintOrientation.Portrait
|
||||
GdViewer1.PrintSetAutoRotation(False)
|
||||
GdViewer1.PrintSetOrientation(PrinterOrientation.PrinterOrientationPortrait)
|
||||
Exit Select
|
||||
Case frmViewerPrint.PrintOrientation.Paysage
|
||||
GdViewer1.PrintSetAutoRotation(False)
|
||||
GdViewer1.PrintSetOrientation(PrinterOrientation.PrinterOrientationLandscape)
|
||||
Exit Select
|
||||
End Select
|
||||
GdViewer1.PrintSetCopies(printSettings.Copies)
|
||||
If printSettings.Copies > 1 Then
|
||||
GdViewer1.PrintSetCollate(printSettings.Collate)
|
||||
End If
|
||||
Select Case printSettings.PagesToPrint
|
||||
Case frmViewerPrint.PagesToPrint.All
|
||||
GdViewer1.PrintSetFromToPage(1, GdViewer1.PageCount)
|
||||
GdViewer1.Print(printSettings.PrintSize)
|
||||
Exit Select
|
||||
Case frmViewerPrint.PagesToPrint.Current
|
||||
GdViewer1.PrintSetFromToPage(GdViewer1.CurrentPage, GdViewer1.CurrentPage)
|
||||
GdViewer1.Print(printSettings.PrintSize)
|
||||
Exit Select
|
||||
Case frmViewerPrint.PagesToPrint.Range
|
||||
If printSettings.PageRange IsNot Nothing And printSettings.PageRange <> String.Empty Then
|
||||
If printSettings.PageRange.Contains("-") Then
|
||||
Dim pageStart As Integer = 0
|
||||
If Integer.TryParse(printSettings.PageRange.Split("-"c)(0), pageStart) Then
|
||||
Dim pageEnd As Integer = 0
|
||||
If Integer.TryParse(printSettings.PageRange.Split("-"c)(1), pageEnd) Then
|
||||
If pageEnd < pageStart Then
|
||||
GdViewer1.PrintSetFromToPage(pageEnd, pageStart)
|
||||
GdViewer1.Print(printSettings.PrintSize)
|
||||
Else
|
||||
GdViewer1.PrintSetFromToPage(pageStart, pageEnd)
|
||||
GdViewer1.Print(printSettings.PrintSize)
|
||||
End If
|
||||
Else
|
||||
MessageBox.Show("Page range is invalid.", "Error", MessageBoxButtons.OK, MessageBoxIcon.[Error])
|
||||
End If
|
||||
Else
|
||||
MessageBox.Show("Page range is invalid.", "Error", MessageBoxButtons.OK, MessageBoxIcon.[Error])
|
||||
End If
|
||||
Else
|
||||
Dim page As Integer = 0
|
||||
If Integer.TryParse(printSettings.PageRange, page) Then
|
||||
GdViewer1.PrintSetFromToPage(page, page)
|
||||
GdViewer1.Print(printSettings.PrintSize)
|
||||
Else
|
||||
MessageBox.Show("Page range is invalid.", "Error", MessageBoxButtons.OK, MessageBoxIcon.[Error])
|
||||
End If
|
||||
End If
|
||||
Else
|
||||
MessageBox.Show("Page range is invalid.", "Error", MessageBoxButtons.OK, MessageBoxIcon.[Error])
|
||||
End If
|
||||
Exit Select
|
||||
End Select
|
||||
End Using
|
||||
End Sub
|
||||
|
||||
Private Sub btnRotateLeft_Click(ByVal sender As System.Object, ByVal e As EventArgs) Handles btnRotateLeft.Click
|
||||
GdViewer1.Rotate(RotateFlipType.Rotate270FlipNone)
|
||||
End Sub
|
||||
|
||||
Private Sub btnRotateRight_Click(ByVal sender As System.Object, ByVal e As EventArgs) Handles btnRotateRight.Click
|
||||
GdViewer1.Rotate(RotateFlipType.Rotate90FlipNone)
|
||||
End Sub
|
||||
|
||||
Private Sub btnFlipX_Click(ByVal sender As System.Object, ByVal e As EventArgs) Handles btnFlipX.Click
|
||||
GdViewer1.Rotate(RotateFlipType.RotateNoneFlipX)
|
||||
End Sub
|
||||
|
||||
Private Sub btnFlipY_Click(ByVal sender As System.Object, ByVal e As EventArgs) Handles btnFlipY.Click
|
||||
GdViewer1.Rotate(RotateFlipType.RotateNoneFlipY)
|
||||
End Sub
|
||||
|
||||
Private Sub GdViewer1_TransferEnded(ByVal status As GdPictureStatus, ByVal download As System.Boolean) Handles GdViewer1.TransferEnded
|
||||
GdViewer1.Focus()
|
||||
UpdateMainUi()
|
||||
End Sub
|
||||
|
||||
Private Sub cbZoom_Validating(ByVal sender As System.Object, ByVal e As CancelEventArgs) Handles cbZoom.Validating
|
||||
ChangeZoomValue()
|
||||
End Sub
|
||||
|
||||
Private Sub AddSearchRegion(ByVal occurence As Integer, ByVal leftCoordinate As Single, ByVal topCoordinate As Single, ByVal regionWidth As Single, ByVal regionheight As Single, ByVal ensureVisibility As Boolean)
|
||||
Dim searchRegion As Integer = GdViewer1.AddRegionInches("SearchResult" & occurence, leftCoordinate, topCoordinate, regionWidth, regionheight, ForegroundMixMode.ForegroundMixModeMASKPEN, Color.Yellow)
|
||||
GdViewer1.SetRegionEditable(searchRegion, False)
|
||||
If ensureVisibility Then
|
||||
GdViewer1.EnsureRegionVisibility(searchRegion)
|
||||
End If
|
||||
End Sub
|
||||
|
||||
Private Sub btnSettings_Click(ByVal sender As Object, ByVal e As EventArgs) Handles btnSettings.Click
|
||||
Using frmSettings As New frmViewerSettings(GdViewer1)
|
||||
frmSettings.ShowDialog(Me)
|
||||
End Using
|
||||
UpdateaNavigationToolbar()
|
||||
End Sub
|
||||
|
||||
Private Sub UpdateaNavigationToolbar()
|
||||
Dim currentPage As Integer = GdViewer1.CurrentPage()
|
||||
tbCurrentPage.Text = currentPage.ToString()
|
||||
lblPageCount.Text = "/ " & GdViewer1.PageCount.ToString()
|
||||
If currentPage = 1 Then
|
||||
btnFirstPage.Enabled = False
|
||||
btnPreviousPage.Enabled = False
|
||||
Else
|
||||
btnFirstPage.Enabled = True
|
||||
btnPreviousPage.Enabled = True
|
||||
End If
|
||||
If currentPage = GdViewer1.PageCount Then
|
||||
btnNextPage.Enabled = False
|
||||
btnLastPage.Enabled = False
|
||||
Else
|
||||
btnNextPage.Enabled = True
|
||||
btnLastPage.Enabled = True
|
||||
End If
|
||||
cbZoom.Text = String.Format(CultureInfo.InvariantCulture, "{0:#0.##%}", GdViewer1.Zoom)
|
||||
|
||||
|
||||
Dim widthInches, heightInches As Double
|
||||
|
||||
If GdViewer1.GetDocumentType = DocumentType.DocumentTypePDF Then
|
||||
widthInches = GdViewer1.PdfGetPageWidth / 72
|
||||
heightInches = GdViewer1.PdfGetPageHeight / 72
|
||||
Else
|
||||
widthInches = GdViewer1.PageWidth / GdViewer1.HorizontalResolution
|
||||
heightInches = GdViewer1.PageHeight / GdViewer1.VerticalResolution
|
||||
End If
|
||||
|
||||
Me.ToolStripStatusLabel1.Text = "Typ: " + GetDocumentTypeLabel() + " - " +
|
||||
"Seitengröße (zoll): " + Trim(Str(Math.Round(widthInches, 2))) + " × " + Trim(Str(Math.Round(heightInches, 2))) + " - " +
|
||||
"Seitengröße (pixel): " + Trim(Str(GdViewer1.PageWidth)) + " × " + Trim(Str(GdViewer1.PageHeight)) + " - " +
|
||||
"Horizontale Auflösung: " + Trim(Str(Math.Round(GdViewer1.HorizontalResolution, 2))) + " DPI - " +
|
||||
"Vertikale Auflösung: " + Trim(Str(Math.Round(GdViewer1.VerticalResolution, 2))) + " DPI"
|
||||
|
||||
End Sub
|
||||
|
||||
Private Sub btnFitWidth_Click(ByVal sender As Object, ByVal e As EventArgs) Handles btnFitWidth.Click
|
||||
GdViewer1.ZoomMode = ViewerZoomMode.ZoomModeWidthViewer
|
||||
End Sub
|
||||
|
||||
Private Sub btnFitPage_Click(ByVal sender As Object, ByVal e As EventArgs) Handles btnFitPage.Click
|
||||
GdViewer1.ZoomMode = ViewerZoomMode.ZoomModeFitToViewer
|
||||
End Sub
|
||||
|
||||
Private Sub DefaultToolStripMenuItem_Click(ByVal sender As System.Object, ByVal e As EventArgs) Handles DefaultToolStripMenuItem.Click
|
||||
GdViewer1.MouseMode = ViewerMouseMode.MouseModeDefault
|
||||
DefaultToolStripMenuItem.Checked = True
|
||||
AreaSelectionToolStripMenuItem.Checked = False
|
||||
PanToolStripMenuItem.Checked = False
|
||||
AreaZoomingToolStripMenuItem.Checked = False
|
||||
MagnifierToolStripMenuItem.Checked = False
|
||||
GdViewer1.Focus()
|
||||
End Sub
|
||||
|
||||
Private Sub AreaSelectionToolStripMenuItem_Click(ByVal sender As System.Object, ByVal e As EventArgs) Handles AreaSelectionToolStripMenuItem.Click
|
||||
GdViewer1.MouseMode = ViewerMouseMode.MouseModeAreaSelection
|
||||
DefaultToolStripMenuItem.Checked = False
|
||||
AreaSelectionToolStripMenuItem.Checked = True
|
||||
PanToolStripMenuItem.Checked = False
|
||||
AreaZoomingToolStripMenuItem.Checked = False
|
||||
MagnifierToolStripMenuItem.Checked = False
|
||||
GdViewer1.Focus()
|
||||
End Sub
|
||||
|
||||
Private Sub PanToolStripMenuItem_Click(ByVal sender As System.Object, ByVal e As EventArgs) Handles PanToolStripMenuItem.Click
|
||||
GdViewer1.MouseMode = ViewerMouseMode.MouseModePan
|
||||
DefaultToolStripMenuItem.Checked = False
|
||||
AreaSelectionToolStripMenuItem.Checked = False
|
||||
PanToolStripMenuItem.Checked = True
|
||||
AreaZoomingToolStripMenuItem.Checked = False
|
||||
MagnifierToolStripMenuItem.Checked = False
|
||||
GdViewer1.Focus()
|
||||
End Sub
|
||||
|
||||
Private Sub AreaZoomingToolStripMenuItem_Click(ByVal sender As System.Object, ByVal e As EventArgs) Handles AreaZoomingToolStripMenuItem.Click
|
||||
GdViewer1.MouseMode = ViewerMouseMode.MouseModeAreaZooming
|
||||
DefaultToolStripMenuItem.Checked = False
|
||||
AreaSelectionToolStripMenuItem.Checked = False
|
||||
PanToolStripMenuItem.Checked = False
|
||||
AreaZoomingToolStripMenuItem.Checked = True
|
||||
MagnifierToolStripMenuItem.Checked = False
|
||||
GdViewer1.Focus()
|
||||
End Sub
|
||||
|
||||
Private Sub MagnifierToolStripMenuItem_Click(ByVal sender As System.Object, ByVal e As EventArgs) Handles MagnifierToolStripMenuItem.Click
|
||||
GdViewer1.MouseMode = ViewerMouseMode.MouseModeMagnifier
|
||||
DefaultToolStripMenuItem.Checked = False
|
||||
AreaSelectionToolStripMenuItem.Checked = False
|
||||
PanToolStripMenuItem.Checked = False
|
||||
AreaZoomingToolStripMenuItem.Checked = False
|
||||
MagnifierToolStripMenuItem.Checked = True
|
||||
GdViewer1.Focus()
|
||||
End Sub
|
||||
End Class
|
||||
Reference in New Issue
Block a user