prompt: You will be provided with a partial code base and an issue statement explaining a problem to resolve.
  <issue>
  Visual Studio: IntelliSense tooltips reported twice
  ### Steps to reproduce:
  1. Open Visual Studio 2019
  2. Open a C# project
  3. Enable reporting of Tooltips
  4. Trigger an IntelliSense autocomplete suggestion by typing something.
  5. Arrow through the suggestions
  
  ### Actual behavior:
  The selected item is announced, followed by twice the tooltip.
  
  ### Expected behavior:
  The selected item is announced, followed by once the tooltip.
  
  ### System configuration
  #### NVDA installed/portable/running from source:
  Installed
  
  #### NVDA version:
  alpha-20957
  
  #### Windows version:
  Windows 10 2004
  
  #### Name and version of other software in use when reproducing the issue:
  Visual Studio 2019 16.7.3 Enterprise
  
  ### Other questions
  #### Does the issue still occur after restarting your computer?
  Yes
  
  #### Have you tried any other versions of NVDA? If so, please report their behaviors.
  No
  
  #### If addons are disabled, is your problem still occuring?
  Yes
  
  #### Did you try to run the COM registry fixing tool in NVDA menu / tools?
  Yes
  
  </issue>
  <code>
  [start of source/NVDAObjects/UIA/VisualStudio.py]
  1 # This file is covered by the GNU General Public License.
  2 # See the file COPYING for more details.
  3 # Copyright (C) 2020 NV Access Limited, Leonard de Ruijter
  4 
  5 """
  6 Object overlay classes for Visual Studio components
  7 available in Visual Studio and SQL Server Management Studio.
  8 """
  9 
  10 from . import UIA
  11 import speech
  12 import braille
  13 import api
  14 
  15 
  16 class IntelliSenseItem(UIA):
  17 
  18 	def _get_name(self):
  19 		return self.UIAElement.cachedAutomationID
  20 
  21 	def event_UIA_elementSelected(self):
  22 		# Cancel speech to have speech announce the selection as soon as possible.
  23 		# This is needed because L{reportFocus} does not cancel speech.
  24 		# Therefore, if speech wouldn't be cancelled,
  25 		# selection announcements would queue up when changing selection rapidly.
  26 		speech.cancelSpeech()
  27 		api.setNavigatorObject(self, isFocus=True)
  28 		self.reportFocus()
  29 		# Display results as flash messages.
  30 		braille.handler.message(braille.getPropertiesBraille(
  31 			name=self.name, role=self.role, positionInfo=self.positionInfo, description=self.description
  32 		))
  33 
  34 
  35 class IntelliSenseList(UIA):
  36 	...
  37 
  38 
  39 class IntelliSenseLiveRegion(UIA):
  40 	"""
  41 	Visual Studio uses both Intellisense menu item objects and a live region
  42 	to communicate Intellisense selections.
  43 	NVDA uses the menu item approach and therefore the live region provides doubled information
  44 	and is disabled.
  45 	"""
  46 
  47 	_shouldAllowUIALiveRegionChangeEvent = False
  48 
  49 
  50 _INTELLISENSE_LIST_AUTOMATION_IDS = {
  51 	"listBoxCompletions",
  52 	"CompletionList"
  53 }
  54 
  55 
  56 def findExtraOverlayClasses(obj, clsList):
  57 	if obj.UIAAutomationId in _INTELLISENSE_LIST_AUTOMATION_IDS:
  58 		clsList.insert(0, IntelliSenseList)
  59 	elif isinstance(obj.parent, IntelliSenseList) and obj.UIAElement.cachedClassName == "IntellisenseMenuItem":
  60 		clsList.insert(0, IntelliSenseItem)
  61 	elif (
  62 		obj.UIAElement.cachedClassName == "LiveTextBlock"
  63 		and obj.previous
  64 		and isinstance(obj.previous.previous, IntelliSenseList)
  65 	):
  66 		clsList.insert(0, IntelliSenseLiveRegion)
  67
  [end of source/NVDAObjects/UIA/VisualStudio.py]
  </code>
  
  I need you to solve this issue by generating a single patch file that I can apply directly to this repository using git apply. Please respond with a single patch file in the following format.
  <patch>
  diff --git a/file.py b/file.py
  --- a/file.py
  +++ b/file.py
  @@ -1,27 +1,35 @@
   def euclidean(a, b):
  -    while b:
  -        a, b = b, a % b
  -    return a
  +    if b == 0:
  +        return a
  +    return euclidean(b, a % b)
   
   
   def bresenham(x0, y0, x1, y1):
       points = []
       dx = abs(x1 - x0)
       dy = abs(y1 - y0)
  -    sx = 1 if x0 < x1 else -1
  -    sy = 1 if y0 < y1 else -1
  -    err = dx - dy
  +    x, y = x0, y0
  +    sx = -1 if x0 > x1 else 1
  +    sy = -1 if y0 > y1 else 1
   
  -    while True:
  -        points.append((x0, y0))
  -        if x0 == x1 and y0 == y1:
  -            break
  -        e2 = 2 * err
  -        if e2 > -dy:
  -            err -= dy
  -            x0 += sx
  -        if e2 < dx:
  -            err += dx
  -            y0 += sy
  +    if dx > dy:
  +        err = dx / 2.0
  +        while x != x1:
  +            points.append((x, y))
  +            err -= dy
  +            if err < 0:
  +                y += sy
  +                err += dx
  +            x += sx
  +    else:
  +        err = dy / 2.0
  +        while y != y1:
  +            points.append((x, y))
  +            err -= dx
  +            if err < 0:
  +                x += sx
  +                err += dy
  +            y += sy
  +
  +    points.append((x, y))
       return points
  
  </patch>
golden_diff: diff --git a/source/NVDAObjects/UIA/VisualStudio.py b/source/NVDAObjects/UIA/VisualStudio.py
  --- a/source/NVDAObjects/UIA/VisualStudio.py
  +++ b/source/NVDAObjects/UIA/VisualStudio.py
  @@ -7,10 +7,11 @@
   available in Visual Studio and SQL Server Management Studio.
   """
   
  -from . import UIA
  +from . import UIA, ToolTip
   import speech
   import braille
   import api
  +import time
   
   
   class IntelliSenseItem(UIA):
  @@ -53,6 +54,34 @@
   }
   
   
  +class CompletionToolTip(ToolTip):
  +	""" A tool tip for which duplicate open events can be fired.
  +	"""
  +
  +	#: Keeps track of the last ToolTipOpened event (text, time)
  +	_lastToolTipOpenedInfo = (None, None)
  +	#: The duplicate tooltip events will be dropped within this time window
  +	_preventDuplicateToolTipSeconds = 0.2
  +
  +	def event_UIA_toolTipOpened(self):
  +		oldText, oldTime = self._lastToolTipOpenedInfo
  +		newText = self.name
  +		newTime = time.time()
  +		self.__class__._lastToolTipOpenedInfo = (newText, newTime)
  +		withinPossibleDupToolTipTimeWindow = (
  +			oldTime is not None
  +			and (newTime - oldTime) < self._preventDuplicateToolTipSeconds
  +		)
  +		if newText == oldText and withinPossibleDupToolTipTimeWindow:
  +			# Tool-tip event suspected to be a duplicate, drop the event.
  +			# - Users attempting to rapidly re-announce tool-tips may
  +			#   have the announcement erroneously  suppressed
  +			# - Users on slower systems (or systems under load) may still
  +			#   receive duplicate announcements
  +			return
  +		super().event_UIA_toolTipOpened()
  +
  +
   def findExtraOverlayClasses(obj, clsList):
   	if obj.UIAAutomationId in _INTELLISENSE_LIST_AUTOMATION_IDS:
   		clsList.insert(0, IntelliSenseList)
  @@ -64,3 +93,5 @@
   		and isinstance(obj.previous.previous, IntelliSenseList)
   	):
   		clsList.insert(0, IntelliSenseLiveRegion)
  +	elif obj.UIAAutomationId == "completion tooltip":
  +		clsList.insert(0, CompletionToolTip)
  
verification_info: {"golden_diff": "diff --git a/source/NVDAObjects/UIA/VisualStudio.py b/source/NVDAObjects/UIA/VisualStudio.py\n--- a/source/NVDAObjects/UIA/VisualStudio.py\n+++ b/source/NVDAObjects/UIA/VisualStudio.py\n@@ -7,10 +7,11 @@\n available in Visual Studio and SQL Server Management Studio.\n \"\"\"\n \n-from . import UIA\n+from . import UIA, ToolTip\n import speech\n import braille\n import api\n+import time\n \n \n class IntelliSenseItem(UIA):\n@@ -53,6 +54,34 @@\n }\n \n \n+class CompletionToolTip(ToolTip):\n+\t\"\"\" A tool tip for which duplicate open events can be fired.\n+\t\"\"\"\n+\n+\t#: Keeps track of the last ToolTipOpened event (text, time)\n+\t_lastToolTipOpenedInfo = (None, None)\n+\t#: The duplicate tooltip events will be dropped within this time window\n+\t_preventDuplicateToolTipSeconds = 0.2\n+\n+\tdef event_UIA_toolTipOpened(self):\n+\t\toldText, oldTime = self._lastToolTipOpenedInfo\n+\t\tnewText = self.name\n+\t\tnewTime = time.time()\n+\t\tself.__class__._lastToolTipOpenedInfo = (newText, newTime)\n+\t\twithinPossibleDupToolTipTimeWindow = (\n+\t\t\toldTime is not None\n+\t\t\tand (newTime - oldTime) < self._preventDuplicateToolTipSeconds\n+\t\t)\n+\t\tif newText == oldText and withinPossibleDupToolTipTimeWindow:\n+\t\t\t# Tool-tip event suspected to be a duplicate, drop the event.\n+\t\t\t# - Users attempting to rapidly re-announce tool-tips may\n+\t\t\t#   have the announcement erroneously  suppressed\n+\t\t\t# - Users on slower systems (or systems under load) may still\n+\t\t\t#   receive duplicate announcements\n+\t\t\treturn\n+\t\tsuper().event_UIA_toolTipOpened()\n+\n+\n def findExtraOverlayClasses(obj, clsList):\n \tif obj.UIAAutomationId in _INTELLISENSE_LIST_AUTOMATION_IDS:\n \t\tclsList.insert(0, IntelliSenseList)\n@@ -64,3 +93,5 @@\n \t\tand isinstance(obj.previous.previous, IntelliSenseList)\n \t):\n \t\tclsList.insert(0, IntelliSenseLiveRegion)\n+\telif obj.UIAAutomationId == \"completion tooltip\":\n+\t\tclsList.insert(0, CompletionToolTip)\n", "issue": "Visual Studio: IntelliSense tooltips reported twice\n### Steps to reproduce:\r\n1. Open Visual Studio 2019\r\n2. Open a C# project\r\n3. Enable reporting of Tooltips\r\n4. Trigger an IntelliSense autocomplete suggestion by typing something.\r\n5. Arrow through the suggestions\r\n\r\n### Actual behavior:\r\nThe selected item is announced, followed by twice the tooltip.\r\n\r\n### Expected behavior:\r\nThe selected item is announced, followed by once the tooltip.\r\n\r\n### System configuration\r\n#### NVDA installed/portable/running from source:\r\nInstalled\r\n\r\n#### NVDA version:\r\nalpha-20957\r\n\r\n#### Windows version:\r\nWindows 10 2004\r\n\r\n#### Name and version of other software in use when reproducing the issue:\r\nVisual Studio 2019 16.7.3 Enterprise\r\n\r\n### Other questions\r\n#### Does the issue still occur after restarting your computer?\r\nYes\r\n\r\n#### Have you tried any other versions of NVDA? If so, please report their behaviors.\r\nNo\r\n\r\n#### If addons are disabled, is your problem still occuring?\r\nYes\r\n\r\n#### Did you try to run the COM registry fixing tool in NVDA menu / tools?\r\nYes\n", "before_files": [{"content": "# This file is covered by the GNU General Public License.\n# See the file COPYING for more details.\n# Copyright (C) 2020 NV Access Limited, Leonard de Ruijter\n\n\"\"\"\nObject overlay classes for Visual Studio components\navailable in Visual Studio and SQL Server Management Studio.\n\"\"\"\n\nfrom . import UIA\nimport speech\nimport braille\nimport api\n\n\nclass IntelliSenseItem(UIA):\n\n\tdef _get_name(self):\n\t\treturn self.UIAElement.cachedAutomationID\n\n\tdef event_UIA_elementSelected(self):\n\t\t# Cancel speech to have speech announce the selection as soon as possible.\n\t\t# This is needed because L{reportFocus} does not cancel speech.\n\t\t# Therefore, if speech wouldn't be cancelled,\n\t\t# selection announcements would queue up when changing selection rapidly.\n\t\tspeech.cancelSpeech()\n\t\tapi.setNavigatorObject(self, isFocus=True)\n\t\tself.reportFocus()\n\t\t# Display results as flash messages.\n\t\tbraille.handler.message(braille.getPropertiesBraille(\n\t\t\tname=self.name, role=self.role, positionInfo=self.positionInfo, description=self.description\n\t\t))\n\n\nclass IntelliSenseList(UIA):\n\t...\n\n\nclass IntelliSenseLiveRegion(UIA):\n\t\"\"\"\n\tVisual Studio uses both Intellisense menu item objects and a live region\n\tto communicate Intellisense selections.\n\tNVDA uses the menu item approach and therefore the live region provides doubled information\n\tand is disabled.\n\t\"\"\"\n\n\t_shouldAllowUIALiveRegionChangeEvent = False\n\n\n_INTELLISENSE_LIST_AUTOMATION_IDS = {\n\t\"listBoxCompletions\",\n\t\"CompletionList\"\n}\n\n\ndef findExtraOverlayClasses(obj, clsList):\n\tif obj.UIAAutomationId in _INTELLISENSE_LIST_AUTOMATION_IDS:\n\t\tclsList.insert(0, IntelliSenseList)\n\telif isinstance(obj.parent, IntelliSenseList) and obj.UIAElement.cachedClassName == \"IntellisenseMenuItem\":\n\t\tclsList.insert(0, IntelliSenseItem)\n\telif (\n\t\tobj.UIAElement.cachedClassName == \"LiveTextBlock\"\n\t\tand obj.previous\n\t\tand isinstance(obj.previous.previous, IntelliSenseList)\n\t):\n\t\tclsList.insert(0, IntelliSenseLiveRegion)\n", "path": "source/NVDAObjects/UIA/VisualStudio.py"}]}