Modules/ClipboardWatcher/ProfileFilter.vb
2019-09-27 16:28:42 +02:00

480 lines
20 KiB
VB.net

Imports System.Text.RegularExpressions
Imports System.Windows.Forms
Imports DigitalData.Modules.Database
Imports DigitalData.Modules.Language.Utils
Imports DigitalData.Modules.Logging
Imports DigitalData.Modules.Windows
Imports DigitalData.Modules.ZooFlow.Params
Imports DigitalData.Modules.ZooFlow.State
Imports Patterns
Public Class ProfileFilter
Private _ProfileMatch As ProfileMatch
Private _ProfileTable As DataTable
Private _ProcessTable As DataTable
Private _WindowTable As DataTable
Private _ControlTable As DataTable
Private _Profiles As List(Of ProfileData)
Private _TreeView As TreeView
Private _LogConfig As LogConfig
Private _Logger As Logger
Public ReadOnly Property Profiles As List(Of ProfileData)
Get
Return _Profiles
End Get
End Property
Public Sub New(LogConfig As LogConfig, ProfileDatatable As DataTable, ProcessTable As DataTable, WindowDatatable As DataTable, ControlDatatable As DataTable, TreeView As TreeView)
Try
_ProfileMatch = New ProfileMatch(LogConfig)
_ProfileTable = ProfileDatatable
_ProcessTable = ProcessTable
_WindowTable = WindowDatatable
_ControlTable = ControlDatatable
_Profiles = TransformProfiles()
_TreeView = TreeView
_LogConfig = LogConfig
_Logger = LogConfig.GetLogger()
Catch ex As Exception
_Logger.Error(ex)
Throw ex
End Try
End Sub
Public Function ToList() As List(Of ProfileData)
Return _Profiles
End Function
Public Function FilterProfilesByClipboardRegex(Profiles As List(Of ProfileData), ClipboardContents As String) As List(Of ProfileData)
Dim oFilteredProfiles As New List(Of ProfileData)
Dim oRootNode As TreeNode = New TreeNode() With {
.Text = $"Suche nach '{ClipboardContents}'",
.Tag = "ROOT"
}
_TreeView.Nodes.Add(oRootNode)
For Each oProfile In Profiles
_Logger.Debug("Current Profile: {0}", oProfile.Name)
Dim oNode = _ProfileMatch.NewProfileNode(oProfile)
oRootNode.Nodes.Add(oNode)
Try
Dim oRegex As New Regex(oProfile.Regex)
Dim oMatch = oRegex.Match(ClipboardContents)
If oMatch.Success Then
_Logger.Debug("FilterProfilesByClipboardRegex: Clipboard Regex Matched: {0}", ClipboardContents)
oFilteredProfiles.Add(oProfile)
oProfile.IsMatched = True
Dim oSubnode = _ProfileMatch.NewClipboardRegexNode(oProfile, oMatch.Success)
oNode.Nodes.Add(oSubnode)
End If
Catch ex As Exception
_Logger.Warn("Regex '{0}' could not be processed for input '{1}'", oProfile.Regex, ClipboardContents)
_Logger.Error(ex)
End Try
Next
Return oFilteredProfiles
End Function
Public Function FilterProfilesByProcess(Profiles As List(Of ProfileData), CurrentProcessName As String) As List(Of ProfileData)
Dim oFilteredProfiles As New List(Of ProfileData)
Try
For Each oProfile In Profiles
Dim oGuid = oProfile.Guid
If oProfile.IsMatched = False Then
Continue For
End If
Dim oProcesses As New List(Of ProcessData)
For Each oProcessDef As ProcessData In oProfile.Processes
If oProcessDef.PROFILE_ID <> oGuid Then
Continue For
End If
Dim oIsMatch = oProcessDef.ProcessName.ToLower = CurrentProcessName.ToLower
Dim oParent = _ProfileMatch.FindNodeByTag(_TreeView.Nodes, oProfile.Name & "-REGEX")
If oParent IsNot Nothing Then
Dim oNode = _ProfileMatch.NewProcessNode(oProfile, oProcessDef, oIsMatch)
oParent.Nodes.Add(oNode)
End If
_Logger.Debug($"FilterProfilesByProcess: Checking Profile: {oProfile.Name} ...")
If oIsMatch Then
_Logger.Debug($"Yes...Processname Matched: {oProcessDef.ProcessName}")
'TODO: Add Debug Data
oFilteredProfiles.Add(oProfile)
oProfile.MatchedProcessID = oProcessDef.Guid
oProcessDef.IsMatched = True
oProcesses.Add(oProcessDef)
oProfile.IsMatched = True
oProfile.MatchedProcessID = oProcessDef.Guid
End If
Next
If oFilteredProfiles.Count > 0 Then
oProfile.Processes = oProcesses
End If
Next
Return oFilteredProfiles
Catch ex As Exception
_Logger.Warn("Unexpected error in FilterProfilesByProcess...")
_Logger.Error(ex)
End Try
End Function
Public Function FilterWindowsByWindowTitleRegex(Profiles As List(Of ProfileData), WindowTitle As String) As List(Of ProfileData)
Dim oProfiles As New List(Of ProfileData)
For Each oProfile As ProfileData In Profiles
_Logger.Debug("Checking WindowDefinition for profile: {0}...", oProfile.Name)
If oProfile.IsMatched = False Then Continue For
Dim oWindows As New List(Of WindowData)
For Each oWindowDef As WindowData In oProfile.Windows
If oWindowDef.WindowProcessID <> oProfile.MatchedProcessID Then Continue For
Try
If oWindowDef.Regex = String.Empty Then
oProfile.MatchedWindowID = oWindowDef.Guid
oWindowDef.IsMatched = True
oWindows.Add(oWindowDef)
Exit For
End If
Dim oRegex As New Regex(oWindowDef.Regex)
Dim oMatch = oRegex.Match(WindowTitle)
If oMatch.Success Then
_Logger.Debug("MATCH on WindowTitle: {0}", WindowTitle)
oProfile.MatchedWindowID = oWindowDef.Guid
oWindowDef.IsMatched = True
oWindows.Add(oWindowDef)
End If
Dim oParent = _ProfileMatch.FindNodeByTag(_TreeView.Nodes, oWindowDef.WindowProcessID & "-PROCESS")
If oParent IsNot Nothing Then
Dim oNode = _ProfileMatch.NewWindowNode(oProfile, oWindowDef, oMatch.Success)
oParent.Nodes.Add(oNode)
End If
Catch ex As Exception
_Logger.Warn("Regex '{0}' could not be processed for input '{1}'", oWindowDef.Regex, WindowTitle)
_Logger.Error(ex)
End Try
Next
If oWindows.Count > 0 Then
oProfile.Windows = oWindows
oProfile.IsMatched = True
oProfiles.Add(oProfile)
End If
Next
Return oProfiles
End Function
Public Function FilterProfilesByFocusedControlLocation(Profiles As List(Of ProfileData), ClipboardContents As String, WindowHandle As IntPtr) As List(Of ProfileData)
Dim oFilteredProfiles As New List(Of ProfileData)
Dim oWindow As New Window(_LogConfig)
For Each oProfile In Profiles
If oProfile.IsMatched = False Then Continue For
If oProfile.Controls.Count = 0 Then
oFilteredProfiles.Add(oProfile)
Continue For
End If
Dim oControls As New List(Of ControlData)
For Each oControl In oProfile.Controls
Dim oControlBounds = oWindow.GetFocusedControlLocation(WindowHandle)
Dim oFound As Boolean = False
For Each oItem As KeyValuePair(Of String, Window.RectangleInfo) In oControlBounds
Select Case oItem.Key
Case "TOPLEFT"
If oControl.TopLeft.Top = oItem.Value.Top And oControl.TopLeft.Left = oItem.Value.Left Then
oFound = True
End If
Case "TOPRIGHT"
If oControl.TopRight.Top = oItem.Value.Top And oControl.TopLeft.Right = oItem.Value.Right Then
oFound = True
End If
Case "BOTTOMLEFT"
If oControl.BottomLeft.Bottom = oItem.Value.Bottom And oControl.TopLeft.Left = oItem.Value.Left Then
oFound = True
End If
Case "BOTTOMRIGHT"
If oControl.BottomRight.Bottom = oItem.Value.Bottom And oControl.TopLeft.Right = oItem.Value.Right Then
oFound = True
End If
End Select
Next
If oFound Then
oControls.Add(oControl)
End If
Dim oParent = _ProfileMatch.FindNodeByTag(_TreeView.Nodes, oControl.WindowId & "-WINDOW")
If oParent IsNot Nothing Then
Dim oNode = _ProfileMatch.NewControlNode(oProfile, oControl, oFound)
oParent.Nodes.Add(oNode)
End If
Next
If oControls.Count > 0 Then
oProfile.Controls = oControls
oFilteredProfiles.Add(oProfile)
End If
Next
Return oFilteredProfiles
End Function
Public Function FilterProfilesBySearchResults(Profiles As List(Of ProfileData), Database As MSSQLServer, User As UserState, ClipboardContents As String) As List(Of ProfileData)
Dim oProfiles As New List(Of ProfileData)
For Each oProfile In Profiles
Dim oResultDocs As Integer = 0
Dim oResultData As Integer = 0
Dim oPatterns As New ClassPatterns(_LogConfig)
Dim oDataSearches As DataTable
Dim oDocSearches As DataTable
Try
oDataSearches = Database.GetDatatable($"SELECT COUNT_COMMAND FROM TBCW_PROF_DATA_SEARCH WHERE ACTIVE = 1 AND PROFILE_ID = {oProfile.Guid}")
Catch ex As Exception
_Logger.Error(ex)
Continue For
End Try
Try
oDocSearches = Database.GetDatatable($"SELECT COUNT_COMMAND FROM TBCW_PROF_DOC_SEARCH WHERE ACTIVE = 1 AND PROFILE_ID = {oProfile.Guid}")
Catch ex As Exception
_Logger.Error(ex)
Continue For
End Try
For Each oRow As DataRow In oDataSearches.Rows
Dim oCountCommand = String.Empty
Try
oCountCommand = NotNull(oRow.Item("COUNT_COMMAND"), String.Empty)
If oCountCommand = String.Empty Then
Continue For
End If
oCountCommand = oPatterns.ReplaceInternalValues(oCountCommand)
oCountCommand = oPatterns.ReplaceUserValues(oCountCommand, User)
oCountCommand = oPatterns.ReplaceClipboardContents(oCountCommand, ClipboardContents)
oResultData += NotNull(Of Integer)(Database.GetScalarValue(oCountCommand), 0)
Catch ex As Exception
_Logger.Warn("Invalid SQL Query for Counting Data in Profile {0}: {1}", oProfile.Guid, oCountCommand)
End Try
Next
For Each oRow As DataRow In oDocSearches.Rows
Dim oCountCommand = String.Empty
Try
oCountCommand = NotNull(oRow.Item("COUNT_COMMAND"), String.Empty)
If oCountCommand = String.Empty Then
Continue For
End If
oCountCommand = oPatterns.ReplaceInternalValues(oCountCommand)
oCountCommand = oPatterns.ReplaceUserValues(oCountCommand, User)
oCountCommand = oPatterns.ReplaceClipboardContents(oCountCommand, ClipboardContents)
oResultDocs += NotNull(Of Integer)(Database.GetScalarValue(oCountCommand), 0)
Catch ex As Exception
_Logger.Warn("Invalid SQL Query for Counting Data in Profile {0}: {1}", oProfile.Guid, oCountCommand)
End Try
Next
If oResultData > 0 Or oResultDocs > 0 Then
oProfile.CountData = oResultData
oProfile.CountDocs = oResultDocs
oProfiles.Add(oProfile)
End If
Next
Return oProfiles
End Function
Public Function FilterWindowsByWindowClipboardRegex(Profiles As List(Of ProfileData), ClipboardContents As String) As List(Of ProfileData)
Dim oProfiles As New List(Of ProfileData)
For Each oProfile As ProfileData In Profiles
_Logger.Debug("Current Profile: {0}", oProfile.Name)
Dim oWindows As New List(Of WindowData)
For Each w As WindowData In oProfile.Windows
Try
If w.Regex = String.Empty Then
oWindows.Add(w)
End If
Dim oRegex As New Regex(w.Regex)
Dim oMatch = oRegex.Match(ClipboardContents)
If oMatch.Success Then
_Logger.Debug("Window Clipboard Regex Matched: {0}", ClipboardContents)
oWindows.Add(w)
End If
Dim oResult As TreeNode = _ProfileMatch.FindNodeByTag(_TreeView.Nodes, oProfile.Name & "-REGEX")
If Not IsNothing(oResult) Then
Dim oNode As New TreeNode($"MATCH on WINDOW Clipboard Regex [{w.Regex}]: {oMatch.Success}")
oNode.ImageIndex = 2
oNode.Tag = oProfile.Name & "-WINDOW_REGEX"
oResult.Nodes.Add(oNode)
End If
Catch ex As Exception
_Logger.Warn("Regex '{0}' could not be processed for input '{1}'", w.Regex, ClipboardContents)
_Logger.Error(ex)
End Try
Next
If oWindows.Count > 0 Then
oProfile.Windows = oWindows
oProfiles.Add(oProfile)
End If
Next
Return oProfiles
End Function
Public Function ClearNotMatchedProfiles(Profiles As List(Of ProfileData)) As List(Of ProfileData)
Dim oFilteredProfiles As New List(Of ProfileData)
For Each oProfile In Profiles
If oProfile.IsMatched Then
oFilteredProfiles.Add(oProfile)
End If
Next
Return oFilteredProfiles
End Function
Public Function ClearDuplicateProfiles(Profiles As List(Of ProfileData)) As List(Of ProfileData)
Return Profiles.
GroupBy(Function(Profile) Profile.Guid).
Select(Function(GroupedProfiles) GroupedProfiles.First).
ToList()
End Function
Private Function TransformProfiles() As List(Of ProfileData)
Dim oList As New List(Of ProfileData)
For Each oRow As DataRow In _ProfileTable.Rows
Dim oProfileId = oRow.Item("GUID")
Dim oProcessList As List(Of ProcessData) = TransformProcesses(oProfileId, _ProcessTable)
Dim oWindowList As List(Of WindowData) = TransformWindows(oProfileId, _WindowTable)
Dim oControlList As List(Of ControlData) = TransformControls(oProfileId, _ControlTable)
oList.Add(New ProfileData() With {
.Guid = oRow.Item("GUID"),
.Regex = oRow.Item("REGEX_EXPRESSION"),
.Name = NotNull(oRow.Item("NAME"), String.Empty),
.Comment = NotNull(oRow.Item("COMMENT"), String.Empty),
.ProfileType = NotNull(oRow.Item("PROFILE_TYPE"), String.Empty),
.Processes = oProcessList,
.Windows = oWindowList,
.Controls = oControlList
})
Next
oList = oList.
Distinct().
ToList()
Return oList
End Function
Private Function TransformControls(ProfileId As Integer, ControlDatatable As DataTable) As List(Of ControlData)
Dim oControlList As New List(Of ControlData)
For Each oRow As DataRow In ControlDatatable.Rows
If oRow.Item("PROFILE_ID") = ProfileId Then
oControlList.Add(New ControlData() With {
.Guid = oRow.Item("GUID"),
.Description = NotNull(oRow.Item("DESCRIPTION"), String.Empty),
.WindowId = oRow.Item("WINDOW_ID"),
.TopLeft = New ControlBounds() With {
.Left = oRow.Item("TOPLEFT_LEFT"),
.Right = oRow.Item("TOPLEFT_RIGHT"),
.Top = oRow.Item("TOPLEFT_TOP"),
.Bottom = oRow.Item("TOPLEFT_BOTTOM")
},
.TopRight = New ControlBounds() With {
.Left = oRow.Item("TOPRIGHT_LEFT"),
.Right = oRow.Item("TOPRIGHT_RIGHT"),
.Top = oRow.Item("TOPRIGHT_TOP"),
.Bottom = oRow.Item("TOPRIGHT_BOTTOM")
},
.BottomLeft = New ControlBounds() With {
.Left = oRow.Item("BOTTOMLEFT_LEFT"),
.Right = oRow.Item("BOTTOMLEFT_RIGHT"),
.Top = oRow.Item("BOTTOMLEFT_TOP"),
.Bottom = oRow.Item("BOTTOMLEFT_BOTTOM")
},
.BottomRight = New ControlBounds() With {
.Left = oRow.Item("BOTTOMRIGHT_LEFT"),
.Right = oRow.Item("BOTTOMRIGHT_RIGHT"),
.Top = oRow.Item("BOTTOMRIGHT_TOP"),
.Bottom = oRow.Item("BOTTOMRIGHT_BOTTOM")
}
})
End If
Next
Return oControlList
End Function
Private Function TransformProcesses(ProfileId As Integer, ProcessDatatable As DataTable) As List(Of ProcessData)
Dim oProcessList As New List(Of ProcessData)
For Each oRow As DataRow In ProcessDatatable.Rows
If oRow.Item("PROFILE_ID") = ProfileId Then
oProcessList.Add(New ProcessData() With {
.Guid = oRow.Item("GUID"),
.PROFILE_ID = oRow.Item("PROFILE_ID"),
.ProcessName = NotNull(oRow.Item("PROC_NAME"), String.Empty)
})
End If
Next
oProcessList = oProcessList.
Distinct().
ToList()
Return oProcessList
End Function
Private Function TransformWindows(ProfileId As Integer, WindowDatatable As DataTable) As List(Of WindowData)
Dim oWindowList As New List(Of WindowData)
For Each oRow As DataRow In WindowDatatable.Rows
If oRow.Item("PROFILE_ID") = ProfileId Then
oWindowList.Add(New WindowData() With {
.Guid = oRow.Item("GUID"),
.WindowProcessID = oRow.Item("PROCESS_ID"),
.Title = NotNull(oRow.Item("DESCRIPTION"), String.Empty),
.Regex = NotNull(oRow.Item("REGEX"), String.Empty),
.Sequence = NotNull(oRow.Item("SEQUENCE"), 0)
})
End If
Next
Return oWindowList
End Function
End Class