You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
ORPA-pyOpenRPA/Resources/WPy64-3720/python-3.7.2.amd64/Lib/site-packages/pywinauto/controls/common_controls.py

3833 lines
135 KiB

# GUI Application automation and testing library
# Copyright (C) 2006-2018 Mark Mc Mahon and Contributors
# https://github.com/pywinauto/pywinauto/graphs/contributors
# http://pywinauto.readthedocs.io/en/latest/credits.html
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
#
# * Redistributions of source code must retain the above copyright notice, this
# list of conditions and the following disclaimer.
#
# * Redistributions in binary form must reproduce the above copyright notice,
# this list of conditions and the following disclaimer in the documentation
# and/or other materials provided with the distribution.
#
# * Neither the name of pywinauto nor the names of its
# contributors may be used to endorse or promote products derived from
# this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
"""
Classes that wrap the Windows Common controls
.. implicitly document some private classes
.. autoclass:: _toolbar_button
:members:
:show-inheritance:
.. autoclass:: _treeview_element
:members:
:show-inheritance:
.. autoclass:: _listview_item
:members:
:show-inheritance:
"""
from __future__ import print_function
import time
import ctypes
from ctypes import wintypes
import warnings
import locale
import six
from .. import win32functions
from .. import win32defines
from .. import win32structures
from .. import findbestmatch
from ..remote_memory_block import RemoteMemoryBlock
from . import hwndwrapper
from ..timings import Timings
from ..timings import wait_until
from ..timings import TimeoutError
from ..handleprops import is64bitprocess
from ..sysinfo import is_x64_Python
from .. import deprecated
# Todo: I should return iterators from things like items() and texts()
# to save building full lists all the time
class _listview_item(object):
"""Wrapper around ListView items"""
#----------------------------------------------------------------
def __init__(self, lv_ctrl, item_index, subitem_index=0):
"""Initialize the item"""
self.listview_ctrl = lv_ctrl
# ensure the item_index is an integer or
# convert it to one
self.item_index = self._as_item_index(item_index)
self.subitem_index = subitem_index
#self._as_parameter_ = self.item_index
#-----------------------------------------------------------
def _as_item_index(self, item):
"""Ensure that item is an item index
If a string is passed in then it will be searched for in the
list of item titles.
"""
index = item
if isinstance(item, six.string_types):
index = int((self.listview_ctrl.texts().index(item) - 1) / self.listview_ctrl.column_count())
return index
#-----------------------------------------------------------
def __eq__(self, other):
"""Return True if the parent control and the indexes are the same as the other."""
if isinstance(other, _listview_item):
return self.listview_ctrl == other.listview_ctrl and \
self.item_index == other.item_index and \
self.subitem_index == other.subitem_index
else:
return False
#-----------------------------------------------------------
def __ne__(self, other):
"""Return True if not matched the parent control or an index."""
return not self == other
#----------------------------------------------------------------
def _readitem(self):
"""Read the list view item"""
# set up a memory block in the remote application
remote_mem = RemoteMemoryBlock(self.listview_ctrl)
# set up the item structure to get the text
item = self.listview_ctrl.LVITEM()
item.mask = \
win32defines.LVIF_TEXT | \
win32defines.LVIF_IMAGE | \
win32defines.LVIF_INDENT | \
win32defines.LVIF_STATE
item.iItem = self.item_index
item.iSubItem = self.subitem_index
item.stateMask = wintypes.UINT(-1)
item.cchTextMax = 2000
item.pszText = remote_mem.Address() + \
ctypes.sizeof(item) + 1
# Write the local LVITEM structure to the remote memory block
remote_mem.Write(item)
# Fill in the requested item
retval = self.listview_ctrl.send_message(
self.listview_ctrl.LVM_GETITEM,
0, # MSDN: wParam for LVM_GETITEM must be zero
remote_mem)
text = ''
# if it succeeded
if retval:
remote_mem.Read(item)
# Read the remote text string
char_data = self.listview_ctrl.create_buffer(2000)
remote_mem.Read(char_data, item.pszText)
text = self.listview_ctrl.text_decode(char_data.value)
else:
raise RuntimeError(
"We should never get to this part of ListView.get_item(), retval = " + str(retval) +
', GetLastError() = ' + str(ctypes.GetLastError()) +
', item_index = ' + str(self.item_index) + ', subitem_index = ' + str(self.subitem_index))
del remote_mem
return item, text
#----------------------------------------------------------------
def __getitem__(self, key):
"""Return property name"""
warnings.warn('ListView item properties "text", "state", "image" and "indent" are deprecated! ' +
'Use methods text(), state(), image() and indent().', DeprecationWarning)
item, text = self._readitem()
if key == 'text':
return text
if key == 'state':
return item.state
if key == 'image':
return item.iImage
if key == 'indent':
return item.iIndent
raise KeyError('Incorrect property: "' + str(key) + '", can be "text", "state", "image" or "indent".')
#----------------------------------------------------------------
def text(self):
"""Return the text of the item"""
return self._readitem()[1]
# Non PEP-8 alias
Text = deprecated(text)
#----------------------------------------------------------------
def item(self):
"""Return the item itself (LVITEM instance)"""
return self._readitem()[0]
# Non PEP-8 alias
Item = deprecated(item)
#----------------------------------------------------------------
def item_data(self):
"""Return the item data (dictionary)"""
item_data = {}
item, text = self._readitem()
# and add it to the titles
item_data['text'] = text
item_data['state'] = item.state
item_data['image'] = item.iImage
item_data['indent'] = item.iIndent
return item_data
# Non PEP-8 alias
ItemData = deprecated(item_data)
#----------------------------------------------------------------
def state(self):
"""Return the state of the item"""
return self.item().state
# Non PEP-8 alias
State = deprecated(state)
#----------------------------------------------------------------
def image(self):
"""Return the image index of the item"""
return self.item().iImage
# Non PEP-8 alias
Image = deprecated(image)
#----------------------------------------------------------------
def indent(self):
"""Return the indent of the item"""
return self.item().iIndent
# Non PEP-8 alias
Indent = deprecated(indent)
#----------------------------------------------------------------
def rectangle(self, area="all"):
"""Return the rectangle of the item.
Possible ``area`` values:
* ``"all"`` Returns the bounding rectangle of the entire item, including the icon and label.
* ``"icon"`` Returns the bounding rectangle of the icon or small icon.
* ``"text"`` Returns the bounding rectangle of the item text.
* ``"select"`` Returns the union of the "icon" and "text" rectangles, but excludes columns in report view.
"""
# set up a memory block in the remote application
remote_mem = RemoteMemoryBlock(self.listview_ctrl)
rect = win32structures.RECT()
# If listview_ctrl has LVS_REPORT we can get access to subitems rectangles
is_table = self.listview_ctrl.has_style(win32defines.LVS_REPORT)
if area.lower() == "all" or not area:
rect.left = win32defines.LVIR_BOUNDS
elif area.lower() == "icon":
rect.left = win32defines.LVIR_ICON
elif area.lower() == "text":
rect.left = win32defines.LVIR_LABEL
elif area.lower() == "select":
rect.left = win32defines.LVIR_BOUNDS if is_table else win32defines.LVIR_SELECTBOUNDS
else:
raise ValueError('Incorrect rectangle area of the list view item: "' + str(area) + '"')
if is_table:
# The one-based index of the subitem.
rect.top = self.subitem_index
# Write the local RECT structure to the remote memory block
remote_mem.Write(rect)
# Depends on subitems rectangles availability
message = win32defines.LVM_GETSUBITEMRECT if is_table else win32defines.LVM_GETITEMRECT
# Fill in the requested item
retval = self.listview_ctrl.send_message(
message,
self.item_index,
remote_mem)
# If it's not succeeded
if not retval:
del remote_mem
raise RuntimeError("Did not succeed in getting rectangle")
rect = remote_mem.Read(rect)
del remote_mem
return rect
# Non PEP-8 alias
Rectangle = deprecated(rectangle)
#----------------------------------------------------------------
def click(self, button="left", double=False, where="text", pressed=""):
"""Click on the list view item
where can be any one of "all", "icon", "text", "select", "check"
defaults to "text"
"""
self.ensure_visible()
if where.lower() != "check":
point_to_click = self.rectangle(area=where.lower()).mid_point()
self.listview_ctrl.click(
button,
coords=(point_to_click.x, point_to_click.y),
double=double,
pressed=pressed)
else:
# Click on checkbox
point_to_click = self.rectangle(area="icon").mid_point()
point_to_click.y = self.rectangle(area="icon").bottom - 3
# Check ListView display mode
# (to be able to process 'Full Row Details' mode separately
remote_mem = RemoteMemoryBlock(self.listview_ctrl)
hittest = win32structures.LVHITTESTINFO()
hittest.pt = point_to_click
# Actually, there is no need to set hittest.iItem, because
# send_message followed by remote_mem.Read always refreshes it
#hittest.iItem = self.item_index
hittest.iSubItem = self.subitem_index
remote_mem.Write(hittest)
self.listview_ctrl.send_message(win32defines.LVM_HITTEST, 0, remote_mem)
remote_mem.Read(hittest)
# Hittest flag
checkbox_found = False
if hittest.flags == win32defines.LVHT_ONITEMICON:
# Large Icons, Small Icons, List, Details
while not checkbox_found and point_to_click.x > 0:
point_to_click.x -= 1
hittest = win32structures.LVHITTESTINFO()
hittest.pt = point_to_click
#hittest.iItem = self.item_index
hittest.iSubItem = self.subitem_index
remote_mem.Write(hittest)
self.listview_ctrl.send_message(win32defines.LVM_HITTEST, 0, remote_mem)
remote_mem.Read(hittest)
if hittest.flags == win32defines.LVHT_ONITEMSTATEICON:
checkbox_found = True
break
elif hittest.flags == win32defines.LVHT_ONITEM:
# Full Row Details
warnings.warn("Full Row Details 'check' area is detected in experimental mode. Use carefully!")
point_to_click.x = self.rectangle(area="icon").left - 8
# Check if point_to_click is still on item
hittest = win32structures.LVHITTESTINFO()
hittest.pt = point_to_click
#hittest.iItem = self.item_index
hittest.iSubItem = self.subitem_index
remote_mem.Write(hittest)
self.listview_ctrl.send_message(win32defines.LVM_HITTEST, 0, remote_mem)
remote_mem.Read(hittest)
if hittest.flags == win32defines.LVHT_ONITEM:
checkbox_found = True
else:
raise RuntimeError("Unexpected hit test flags value " + str(hittest.flags) + " trying to find checkbox")
# Click on the found checkbox
if checkbox_found:
self.listview_ctrl.click(
button,
coords=(point_to_click.x, point_to_click.y),
double=double,
pressed=pressed)
else:
raise RuntimeError("Area ('check') not found for this list view item")
return self
# Non PEP-8 alias
Click = deprecated(click)
#----------------------------------------------------------------
def click_input(self, button="left", double=False, wheel_dist=0, where="text", pressed=""):
"""Click on the list view item
where can be any one of "all", "icon", "text", "select", "check"
defaults to "text"
"""
self.ensure_visible()
if where.lower() != "check":
point_to_click = self.rectangle(area=where.lower()).mid_point()
self.listview_ctrl.click_input(
button,
coords=(point_to_click.x, point_to_click.y),
double=double,
wheel_dist=wheel_dist,
pressed=pressed)
else:
# Click on checkbox
point_to_click = self.rectangle(area="icon").mid_point()
point_to_click.y = self.rectangle(area="icon").bottom - 3
# Check ListView display mode
# (to be able to process 'Full Row Details' mode separately
remote_mem = RemoteMemoryBlock(self.listview_ctrl)
hittest = win32structures.LVHITTESTINFO()
hittest.pt = point_to_click
# Actually, there is no need to set hittest.iItem, because
# send_message followed by remote_mem.Read always refreshes it
#hittest.iItem = self.item_index
hittest.iSubItem = self.subitem_index
remote_mem.Write(hittest)
self.listview_ctrl.send_message(win32defines.LVM_HITTEST, 0, remote_mem)
remote_mem.Read(hittest)
# Hittest flag
checkbox_found = False
if hittest.flags == win32defines.LVHT_ONITEMICON:
# Large Icons, Small Icons, List, Details
while not checkbox_found and point_to_click.x > 0:
point_to_click.x -= 1
hittest = win32structures.LVHITTESTINFO()
hittest.pt = point_to_click
#hittest.iItem = self.item_index
hittest.iSubItem = self.subitem_index
remote_mem.Write(hittest)
self.listview_ctrl.send_message(win32defines.LVM_HITTEST, 0, remote_mem)
remote_mem.Read(hittest)
if hittest.flags == win32defines.LVHT_ONITEMSTATEICON:
checkbox_found = True
break
elif hittest.flags == win32defines.LVHT_ONITEM:
# Full Row Details
warnings.warn("Full Row Details 'check' area is detected in experimental mode. Use carefully!")
point_to_click.x = self.rectangle(area="icon").left - 8
# Check if point_to_click is still on item
hittest = win32structures.LVHITTESTINFO()
hittest.pt = point_to_click
#hittest.iItem = self.item_index
hittest.iSubItem = self.subitem_index
remote_mem.Write(hittest)
self.listview_ctrl.send_message(win32defines.LVM_HITTEST, 0, remote_mem)
remote_mem.Read(hittest)
if hittest.flags == win32defines.LVHT_ONITEM:
checkbox_found = True
else:
raise RuntimeError("Unexpected hit test flags value " + str(hittest.flags) + " trying to find checkbox")
# Click on the found checkbox
if checkbox_found:
self.listview_ctrl.click_input(
button,
coords=(point_to_click.x, point_to_click.y),
double=double,
wheel_dist=wheel_dist,
pressed=pressed)
else:
raise RuntimeError("Area ('check') not found for this list view item")
return self
# Non PEP-8 alias
ClickInput = deprecated(click_input)
#----------------------------------------------------------------
def ensure_visible(self):
"""Make sure that the ListView item is visible"""
if self.state() & win32defines.LVS_NOSCROLL:
return None # scroll is disabled
ret = self.listview_ctrl.send_message(
win32defines.LVM_ENSUREVISIBLE,
self.item_index,
win32defines.FALSE)
if ret != win32defines.TRUE:
raise RuntimeError('Fail to make the list view item visible ' +
'(item_index = ' + str(self.item_index) + ')')
return self
# Non PEP-8 alias
EnsureVisible = deprecated(ensure_visible)
#-----------------------------------------------------------
def uncheck(self):
"""Uncheck the ListView item"""
def index_to_state_image_mask(i):
return i << 12
self.listview_ctrl.verify_actionable()
lvitem = self.listview_ctrl.LVITEM()
lvitem.mask = wintypes.UINT(win32defines.LVIF_STATE)
lvitem.state = wintypes.UINT(index_to_state_image_mask(1)) # wintypes.UINT(0x1000)
lvitem.stateMask = wintypes.UINT(win32defines.LVIS_STATEIMAGEMASK)
remote_mem = RemoteMemoryBlock(self.listview_ctrl)
remote_mem.Write(lvitem)
retval = self.listview_ctrl.send_message(
win32defines.LVM_SETITEMSTATE, self.item_index, remote_mem)
if retval != win32defines.TRUE:
raise ctypes.WinError()
del remote_mem
return self
# Non PEP-8 alias
UnCheck = deprecated(uncheck, deprecated_name='UnCheck')
#-----------------------------------------------------------
def check(self):
"""Check the ListView item"""
def index_to_state_image_mask(i):
return i << 12
self.listview_ctrl.verify_actionable()
lvitem = self.listview_ctrl.LVITEM()
lvitem.mask = wintypes.UINT(win32defines.LVIF_STATE)
lvitem.state = wintypes.UINT(index_to_state_image_mask(2)) # wintypes.UINT(0x2000)
lvitem.stateMask = wintypes.UINT(win32defines.LVIS_STATEIMAGEMASK)
remote_mem = RemoteMemoryBlock(self.listview_ctrl)
remote_mem.Write(lvitem)
retval = self.listview_ctrl.send_message(
win32defines.LVM_SETITEMSTATE, self.item_index, remote_mem)
if retval != win32defines.TRUE:
raise ctypes.WinError()
del remote_mem
return self
# Non PEP-8 alias
Check = deprecated(check)
#-----------------------------------------------------------
def is_checked(self):
"""Return whether the ListView item is checked or not"""
state = self.listview_ctrl.send_message(
win32defines.LVM_GETITEMSTATE,
self.item_index,
win32defines.LVIS_STATEIMAGEMASK)
return state & 0x2000 == 0x2000
# Non PEP-8 alias
IsChecked = deprecated(is_checked)
#-----------------------------------------------------------
def is_selected(self):
"""Return True if the item is selected"""
return win32defines.LVIS_SELECTED == self.listview_ctrl.send_message(
win32defines.LVM_GETITEMSTATE, self.item_index, win32defines.LVIS_SELECTED)
# Non PEP-8 alias
IsSelected = deprecated(is_selected)
#-----------------------------------------------------------
def is_focused(self):
"""Return True if the item has the focus"""
return win32defines.LVIS_FOCUSED == self.listview_ctrl.send_message(
win32defines.LVM_GETITEMSTATE, self.item_index, win32defines.LVIS_FOCUSED)
# Non PEP-8 alias
IsFocused = deprecated(is_focused)
#-----------------------------------------------------------
def _modify_selection(self, to_select):
"""Change the selection of the item
to_select should be True to select the item and false
to deselect the item
"""
self.listview_ctrl.verify_actionable()
if self.item_index >= self.listview_ctrl.item_count():
raise IndexError("There are only %d items in the list view not %d" %
(self.listview_ctrl.item_count(), self.item_index + 1))
# first we need to change the state of the item
lvitem = self.listview_ctrl.LVITEM()
lvitem.mask = wintypes.UINT(win32defines.LVIF_STATE)
if to_select:
lvitem.state = wintypes.UINT(win32defines.LVIS_FOCUSED | win32defines.LVIS_SELECTED)
lvitem.stateMask = wintypes.UINT(win32defines.LVIS_FOCUSED | win32defines.LVIS_SELECTED)
remote_mem = RemoteMemoryBlock(self.listview_ctrl)
remote_mem.Write(lvitem, size=ctypes.sizeof(lvitem))
retval = self.listview_ctrl.send_message(
win32defines.LVM_SETITEMSTATE, self.item_index, remote_mem)
if retval != win32defines.TRUE:
raise ctypes.WinError() # ('retval = ' + str(retval))
del remote_mem
# now we need to notify the parent that the state has changed
nmlv = win32structures.NMLISTVIEW()
nmlv.hdr.hwndFrom = self.listview_ctrl.handle
nmlv.hdr.idFrom = self.listview_ctrl.control_id()
nmlv.hdr.code = win32defines.LVN_ITEMCHANGING
nmlv.iItem = self.item_index
#nmlv.iSubItem = 0
nmlv.uNewState = win32defines.LVIS_SELECTED
#nmlv.uOldState = 0
nmlv.uChanged = win32defines.LVIS_SELECTED
nmlv.ptAction = win32structures.POINT()
new_remote_mem = RemoteMemoryBlock(self.listview_ctrl, size=ctypes.sizeof(nmlv))
new_remote_mem.Write(nmlv, size=ctypes.sizeof(nmlv))
retval = self.listview_ctrl.parent().send_message(
win32defines.WM_NOTIFY,
self.listview_ctrl.control_id(),
new_remote_mem)
#if retval != win32defines.TRUE:
# print('retval = ' + str(retval))
# raise ctypes.WinError()
del new_remote_mem
win32functions.WaitGuiThreadIdle(self.listview_ctrl.handle)
time.sleep(Timings.after_listviewselect_wait)
#-----------------------------------------------------------
def select(self):
"""Mark the item as selected
The ListView control must be enabled and visible before an
Item can be selected otherwise an exception is raised
"""
self._modify_selection(True)
return self
# Non PEP-8 alias
Select = deprecated(select)
#-----------------------------------------------------------
def deselect(self):
"""Mark the item as not selected
The ListView control must be enabled and visible before an
Item can be selected otherwise an exception is raised
"""
self._modify_selection(False)
return self
# Non PEP-8 alias
Deselect = deprecated(deselect)
#-----------------------------------------------------------
def inplace_control(self, friendly_class_name=""):
"""Return the editor HwndWrapper of the item
Possible ``friendly_class_name`` values:
* ``""`` Return the first appeared in-place control
* ``"friendlyclassname"`` Returns editor with particular friendlyclassname
"""
# If currently editing in this item or some other
self.listview_ctrl.type_keys("{ENTER}")
# Get a list of visible controls
parent_dlg = self.listview_ctrl.top_level_parent()
list_before_click = [w.handle for w in parent_dlg.element_info.descendants() if w.visible]
# After a click on the visible list an editable element should appear
self.click_input(double=True)
def get_list_after_click():
return [w.handle for w in parent_dlg.element_info.descendants() if w.visible]
try:
def check_func():
return len(get_list_after_click()) > len(list_before_click)
wait_until(Timings.listviewitemcontrol_timeout, 0.05, check_func)
except TimeoutError:
raise TimeoutError(("In-place-edit control for item ({0},{1}) not visible, possible it not editable, " +
"try to set slower timings").format(self.item_index, self.subitem_index));
possible_inplace_ctrls = set(get_list_after_click()) - set(list_before_click)
for handle in possible_inplace_ctrls:
hwnd_friendly_class = hwndwrapper.HwndWrapper(handle).friendlyclassname
if (friendly_class_name == "" or hwnd_friendly_class == friendly_class_name):
return hwndwrapper.HwndWrapper(handle)
names_list = [hwndwrapper.HwndWrapper(handle).friendlyclassname for handle in possible_inplace_ctrls]
raise RuntimeError('In-place-edit control "{2}" for item ({0},{1}) not found in list {3}'.format(
self.item_index, self.subitem_index, friendly_class_name, names_list));
#====================================================================
class ListViewWrapper(hwndwrapper.HwndWrapper):
"""Class that wraps Windows ListView common control
This class derives from HwndWrapper - so has all the methods o
that class also
**see** hwndwrapper.HwndWrapper_
.. _hwndwrapper.HwndWrapper: class-pywinauto.controls.hwndwrapper.HwndWrapper.html
"""
friendlyclassname = "ListView"
windowclasses = [
"SysListView32",
r"WindowsForms\d*\.SysListView32\..*",
"TSysListView",
"ListView.*WndClass",
]
#----------------------------------------------------------------
def __init__(self, hwnd):
"""Initialise the instance"""
super(ListViewWrapper, self).__init__(hwnd)
if self.is_unicode():
self.create_buffer = ctypes.create_unicode_buffer
if is64bitprocess(self.process_id()) or not is_x64_Python():
self.LVCOLUMN = win32structures.LVCOLUMNW
self.LVITEM = win32structures.LVITEMW
else:
self.LVCOLUMN = win32structures.LVCOLUMNW32
self.LVITEM = win32structures.LVITEMW32
self.LVM_GETITEM = win32defines.LVM_GETITEMW
self.LVM_GETCOLUMN = win32defines.LVM_GETCOLUMNW
self.text_decode = lambda v: v
else:
self.create_buffer = ctypes.create_string_buffer
if is64bitprocess(self.process_id()) or not is_x64_Python():
self.LVCOLUMN = win32structures.LVCOLUMNW
self.LVITEM = win32structures.LVITEMW
else:
self.LVCOLUMN = win32structures.LVCOLUMNW32
self.LVITEM = win32structures.LVITEMW32
self.LVM_GETCOLUMN = win32defines.LVM_GETCOLUMNA
self.LVM_GETITEM = win32defines.LVM_GETITEMA
self.text_decode = lambda v: v.decode(locale.getpreferredencoding())
@property
def writable_props(self):
"""Extend default properties list."""
props = super(ListViewWrapper, self).writable_props
props.extend(['column_count',
'item_count',
'columns',
'items',
])
return props
#-----------------------------------------------------------
def column_count(self):
"""Return the number of columns"""
if self.get_header_control() is not None:
return self.get_header_control().item_count()
return 0
# Non PEP-8 alias
ColumnCount = deprecated(column_count)
#-----------------------------------------------------------
def item_count(self):
"""The number of items in the ListView"""
return self.send_message(win32defines.LVM_GETITEMCOUNT)
# Non PEP-8 alias
ItemCount = deprecated(item_count)
#-----------------------------------------------------------
def get_header_control(self):
"""Returns the Header control associated with the ListView"""
try:
return hwndwrapper.HwndWrapper(
self.send_message(win32defines.LVM_GETHEADER))
except hwndwrapper.InvalidWindowHandle:
return None
# Non PEP-8 alias
GetHeaderControl = deprecated(get_header_control)
#-----------------------------------------------------------
def get_column(self, col_index):
"""Get the information for a column of the ListView"""
col_props = {}
col = self.LVCOLUMN()
col.mask = \
win32defines.LVCF_FMT | \
win32defines.LVCF_IMAGE | \
win32defines.LVCF_ORDER | \
win32defines.LVCF_SUBITEM | \
win32defines.LVCF_TEXT | \
win32defines.LVCF_WIDTH
remote_mem = RemoteMemoryBlock(self)
col.cchTextMax = 2000
col.pszText = remote_mem.Address() + ctypes.sizeof(col) + 1
# put the information in the memory that the
# other process can read/write
remote_mem.Write(col)
# ask the other process to update the information
retval = self.send_message(
self.LVM_GETCOLUMN,
col_index,
remote_mem)
col = remote_mem.Read(col)
# if that succeeded then there was a column
if retval:
col = remote_mem.Read(col)
text = self.create_buffer(2000)
remote_mem.Read(text, col.pszText)
col_props['order'] = col.iOrder
col_props['text'] = self.text_decode(text.value)
col_props['format'] = col.fmt
col_props['width'] = col.cx
col_props['image'] = col.iImage
col_props['subitem'] = col.iSubItem
del remote_mem
return col_props
# Non PEP-8 alias
GetColumn = deprecated(get_column)
#-----------------------------------------------------------
def columns(self):
"""Get the information on the columns of the ListView"""
cols = []
for i in range(0, self.column_count()):
cols.append(self.get_column(i))
return cols
# Non PEP-8 alias
Columns = deprecated(columns)
#-----------------------------------------------------------
def column_widths(self):
"""Return a list of all the column widths"""
return [col['width'] for col in self.columns()]
# Non PEP-8 alias
ColumnWidths = deprecated(column_widths)
#-----------------------------------------------------------
def get_item_rect(self, item_index):
"""Return the bounding rectangle of the list view item"""
warnings.warn("Use get_item(item).rectangle() instead", DeprecationWarning)
return self.get_item(item_index).rectangle()
# Non PEP-8 alias
GetItemRect = deprecated(get_item_rect)
#-----------------------------------------------------------
def get_item(self, item_index, subitem_index=0):
"""Return the item of the list view"
* **item_index** Can be either an index of the item or a string
with the text of the item you want returned.
* **subitem_index** A zero based index of the item you want returned.
Defaults to 0.
"""
return _listview_item(self, item_index, subitem_index)
item = get_item # this is an alias to be consistent with other content elements
# Non PEP-8 alias
Item = deprecated(item)
# Non PEP-8 alias
GetItem = deprecated(get_item)
#-----------------------------------------------------------
def items(self):
"""Get all the items in the list view"""
colcount = self.column_count()
if not colcount:
colcount = 1
items = []
# now get the item values...
# for each of the rows
for item_index in range(0, self.item_count()):
# and each of the columns for that row
for subitem_index in range(0, colcount):
# get the item
#yield self.get_item(item_index, subitem_index) # return iterator
items.append(self.get_item(item_index, subitem_index))
return items
# Non PEP-8 alias
Items = deprecated(items)
#-----------------------------------------------------------
def texts(self):
"""Get the texts for the ListView control"""
texts = [self.window_text()]
texts.extend([item.text() for item in self.items()])
return texts
#-----------------------------------------------------------
def uncheck(self, item):
"""Uncheck the ListView item"""
warnings.warn("Use get_item(item).uncheck() instead", DeprecationWarning)
return self.get_item(item).uncheck()
# Non PEP-8 alias
UnCheck = deprecated(uncheck, deprecated_name='UnCheck')
#-----------------------------------------------------------
def check(self, item):
"""Check the ListView item"""
warnings.warn("Use get_item(item).check() instead", DeprecationWarning)
return self.get_item(item).check()
# Non PEP-8 alias
Check = deprecated(check)
#-----------------------------------------------------------
def is_checked(self, item):
"""Return whether the ListView item is checked or not"""
warnings.warn("Use get_item(item).is_checked() instead", DeprecationWarning)
return self.get_item(item).is_checked()
# Non PEP-8 alias
IsChecked = deprecated(is_checked)
#-----------------------------------------------------------
def is_selected(self, item):
"""Return True if the item is selected"""
warnings.warn("Use get_item(item).is_selected() instead", DeprecationWarning)
return self.get_item(item).is_selected()
# Non PEP-8 alias
IsSelected = deprecated(is_selected)
#-----------------------------------------------------------
def is_focused(self, item):
"""Return True if the item has the focus"""
warnings.warn("Use get_item(item).is_focused() instead", DeprecationWarning)
return self.get_item(item).is_focused()
# Non PEP-8 alias
IsFocused = deprecated(is_focused)
#-----------------------------------------------------------
def select(self, item):
"""Mark the item as selected
The ListView control must be enabled and visible before an
Item can be selected otherwise an exception is raised
"""
warnings.warn("Use get_item(item).select() instead", DeprecationWarning)
return self.get_item(item).select()
# Non PEP-8 alias
Select = deprecated(select)
#-----------------------------------------------------------
def deselect(self, item):
"""Mark the item as not selected
The ListView control must be enabled and visible before an
Item can be selected otherwise an exception is raised
"""
warnings.warn("Use get_item(item).deselect() instead", DeprecationWarning)
return self.get_item(item).deselect()
# Naming is not clear - so create an alias.
#UnSelect = deselect
# Non PEP-8 alias
Deselect = deprecated(deselect)
#-----------------------------------------------------------
def get_selected_count(self):
"""Return the number of selected items"""
return self.send_message(win32defines.LVM_GETSELECTEDCOUNT)
# Non PEP-8 alias
GetSelectedCount = deprecated(get_selected_count)
#====================================================================
class _treeview_element(object):
"""Wrapper around TreeView items"""
#----------------------------------------------------------------
def __init__(self, elem, tv_handle):
"""Initialize the item"""
self.tree_ctrl = tv_handle
self.elem = elem
self._as_parameter_ = self.elem
#----------------------------------------------------------------
def text(self):
"""Return the text of the item"""
return self._readitem()[1]
# Non PEP-8 alias
Text = deprecated(text)
#----------------------------------------------------------------
def item(self):
"""Return the item itself"""
return self._readitem()[0]
# Non PEP-8 alias
Item = deprecated(item)
#----------------------------------------------------------------
def state(self):
"""Return the state of the item"""
return self.item().state
# Non PEP-8 alias
State = deprecated(state)
#-----------------------------------------------------------
def is_checked(self):
"""Return whether the TreeView item is checked or not"""
state = self.tree_ctrl.send_message(
win32defines.TVM_GETITEMSTATE,
self.elem,
win32defines.TVIS_STATEIMAGEMASK)
return state & 0x2000 == 0x2000
# Non PEP-8 alias
IsChecked = deprecated(is_checked)
#----------------------------------------------------------------
def client_rect(self, text_area_rect=True):
"""Return a rectangle of a text area of the item
If **text_area_rect** is set to False then it will return
a rectangle for the whole item (usually left is equal to 0).
Defaults to True - which returns just the rectangle of the
text of the item
"""
remote_mem = RemoteMemoryBlock(self.tree_ctrl)
# this is a bit weird
# we have to write the element handle
# but we read the rectangle afterwards!
remote_mem.Write(win32structures.LPARAM(self.elem))
ret = self.tree_ctrl.send_message(
win32defines.TVM_GETITEMRECT, text_area_rect, remote_mem)
# the item is not visible
if not ret:
rect = None
else:
# OK - it's visible so read it
rect = win32structures.RECT()
remote_mem.Read(rect)
del remote_mem
return rect
# Non PEP-8 alias
ClientRect = deprecated(client_rect)
#----------------------------------------------------------------
def click(self, button="left", double=False, where="text", pressed=""):
"""Click on the treeview item
where can be any one of "text", "icon", "button", "check"
defaults to "text"
"""
self.ensure_visible()
# find the text rectangle for the item,
point_to_click = self.client_rect().mid_point()
if where.lower() != "text":
remote_mem = RemoteMemoryBlock(self.tree_ctrl)
point_to_click.x = self.client_rect().left
found = False
while not found and point_to_click.x >= 0:
hittest = win32structures.TVHITTESTINFO()
hittest.pt = point_to_click
hittest.hItem = self.elem
remote_mem.Write(hittest)
self.tree_ctrl.send_message(win32defines.TVM_HITTEST, 0, remote_mem)
remote_mem.Read(hittest)
if where.lower() == 'button' and \
hittest.flags == win32defines.TVHT_ONITEMBUTTON:
found = True
break
if where.lower() == 'icon' and \
hittest.flags == win32defines.TVHT_ONITEMICON:
found = True
break
if where.lower() == 'check' and \
hittest.flags == win32defines.TVHT_ONITEMSTATEICON:
found = True
break
point_to_click.x -= 1
if not found:
raise RuntimeError("Area ('{}') not found for this tree view item".format(where))
self.tree_ctrl.click(
button,
coords=(point_to_click.x, point_to_click.y),
double=double,
pressed=pressed)
return self
# XXX: somehow it works for 64-bit explorer.exe on Win8.1,
# but it doesn't work for 32-bit ControlSpyV6.exe
#absolute = True)
# TODO: if we use click instead of clickInput - then we need to tell the
# treeview to update itself
#self.tree_ctrl.
# Non PEP-8 alias
Click = deprecated(click)
#----------------------------------------------------------------
def click_input(self, button="left", double=False, wheel_dist=0, where="text", pressed=""):
"""Click on the treeview item
where can be any one of "text", "icon", "button", "check"
defaults to "text"
"""
self.ensure_visible()
# find the text rectangle for the item,
point_to_click = self.client_rect().mid_point()
if where.lower() != "text":
remote_mem = RemoteMemoryBlock(self.tree_ctrl)
point_to_click.x = self.client_rect().left
found = False
while not found and point_to_click.x >= 0:
hittest = win32structures.TVHITTESTINFO()
hittest.pt = point_to_click
hittest.hItem = self.elem
remote_mem.Write(hittest)
self.tree_ctrl.send_message(win32defines.TVM_HITTEST, 0, remote_mem)
remote_mem.Read(hittest)
if where.lower() == 'button' and \
hittest.flags == win32defines.TVHT_ONITEMBUTTON:
found = True
break
if where.lower() == 'icon' and \
hittest.flags == win32defines.TVHT_ONITEMICON:
found = True
break
if where.lower() == 'check' and \
hittest.flags == win32defines.TVHT_ONITEMSTATEICON:
found = True
break
point_to_click.x -= 1
if not found:
raise RuntimeError("Area ('%s') not found for this tree view item" % where)
self.tree_ctrl.click_input(
button,
coords=(point_to_click.x, point_to_click.y),
double=double,
wheel_dist=wheel_dist,
pressed=pressed)
return self
# Non PEP-8 alias
ClickInput = deprecated(click_input)
#----------------------------------------------------------------
def start_dragging(self, button='left', pressed=''):
"""Start dragging the item"""
#self.ensure_visible()
# find the text rectangle for the item
rect = self.client_rect()
point_to_click = rect.mid_point()
#self.tree_ctrl.set_focus()
self.tree_ctrl.press_mouse_input(
button, coords=(point_to_click.x, point_to_click.y), pressed=pressed, absolute=False)
for i in range(5):
self.tree_ctrl.move_mouse_input(
coords=(rect.left + i, rect.top), pressed=pressed, absolute=False)
return self
# Non PEP-8 alias
StartDragging = deprecated(start_dragging)
#----------------------------------------------------------------
def drop(self, button='left', pressed=''):
"""Drop at the item"""
#self.ensure_visible()
# find the text rectangle for the item
point_to_click = self.client_rect().mid_point()
self.tree_ctrl.move_mouse_input(
coords=(point_to_click.x, point_to_click.y), pressed=pressed, absolute=False)
time.sleep(Timings.drag_n_drop_move_mouse_wait)
self.tree_ctrl.release_mouse_input(
button, coords=(point_to_click.x, point_to_click.y), pressed=pressed, absolute=False)
time.sleep(Timings.after_drag_n_drop_wait)
return self
# Non PEP-8 alias
Drop = deprecated(drop)
#----------------------------------------------------------------
def collapse(self):
"""Collapse the children of this tree view item"""
self.tree_ctrl.send_message(
win32defines.TVM_EXPAND,
win32defines.TVE_COLLAPSE,
self.elem)
return self
# Non PEP-8 alias
Collapse = deprecated(collapse)
#----------------------------------------------------------------
def expand(self):
"""Expand the children of this tree view item"""
self.tree_ctrl.send_message(
win32defines.TVM_EXPAND,
win32defines.TVE_EXPAND,
self.elem)
return self
# Non PEP-8 alias
Expand = deprecated(expand)
#----------------------------------------------------------------
def children(self):
"""Return the direct children of this control"""
if self.item().cChildren not in (0, 1):
print("##### not dealing with that TVN_GETDISPINFO stuff yet")
# No children
#if self.__item.cChildren == 0:
# pass
children_elements = []
if self.item().cChildren == 1:
# Get the first child of this element
child_elem = self.tree_ctrl.send_message(
win32defines.TVM_GETNEXTITEM,
win32defines.TVGN_CHILD,
self.elem)
if child_elem:
children_elements.append(_treeview_element(child_elem, self.tree_ctrl))
# now get all the next children
while True:
next_child = children_elements[-1].next_item()
if next_child is not None:
children_elements.append(next_child)
else:
break
else:
return []
#raise ctypes.WinError()
return children_elements
# Non PEP-8 alias
Children = deprecated(children)
#----------------------------------------------------------------
def next_item(self):
"""Return the next item"""
# get the next element
next_elem = self.tree_ctrl.send_message(
win32defines.TVM_GETNEXTITEM,
win32defines.TVGN_NEXT,
self.elem)
if next_elem:
return _treeview_element(next_elem, self.tree_ctrl)
return None
# don't raise - as it just meant that there was no
# next
#else:
# raise ctypes.WinError()
# Non PEP-8 alias
Next = deprecated(next_item, deprecated_name='Next')
#----------------------------------------------------------------
def sub_elements(self):
"""Return the list of children of this control"""
sub_elems = []
for child in self.children():
sub_elems.append(child)
sub_elems.extend(child.sub_elements())
return sub_elems
# Non PEP-8 alias
SubElements = deprecated(sub_elements)
#----------------------------------------------------------------
def get_child(self, child_spec, exact=False):
"""Return the child item of this item
Accepts either a string or an index.
If a string is passed then it returns the child item
with the best match for the string.
"""
#print child_spec
if isinstance(child_spec, six.string_types):
texts = [c.text() for c in self.children()]
if exact:
if child_spec in texts:
index = texts.index(child_spec)
else:
raise IndexError('There is no child equal to "' + str(child_spec) + '" in ' + str(texts))
else:
indices = range(0, len(texts))
index = findbestmatch.find_best_match(
child_spec, texts, indices, limit_ratio=.6)
#if len(matching) > 1 :
# raise RuntimeError(
# "There are multiple children that match that spec '%s'"%
# child_spec)
else:
index = child_spec
return self.children()[index]
# Non PEP-8 alias
GetChild = deprecated(get_child)
#----------------------------------------------------------------
def ensure_visible(self):
"""Make sure that the TreeView item is visible"""
self.tree_ctrl.send_message(
win32defines.TVM_ENSUREVISIBLE,
win32defines.TVGN_CARET,
self.elem)
win32functions.WaitGuiThreadIdle(self.tree_ctrl.handle)
return self
# Non PEP-8 alias
EnsureVisible = deprecated(ensure_visible)
#----------------------------------------------------------------
def select(self):
"""Select the TreeView item"""
# http://stackoverflow.com/questions/14111333/treeview-set-default-select-item-and-highlight-blue-this-item
# non-focused TreeView can ignore TVM_SELECTITEM
self.tree_ctrl.set_focus()
retval = self.tree_ctrl.send_message(
win32defines.TVM_SELECTITEM, # message
win32defines.TVGN_CARET, # how to select
self.elem) # item to select
if retval != win32defines.TRUE:
raise ctypes.WinError()
return self
# Non PEP-8 alias
Select = deprecated(select)
#----------------------------------------------------------------
def is_selected(self):
"""Indicate that the TreeView item is selected or not"""
return win32defines.TVIS_SELECTED == (win32defines.TVIS_SELECTED & self.state())
# Non PEP-8 alias
IsSelected = deprecated(is_selected)
#----------------------------------------------------------------
def is_expanded(self):
"""Indicate that the TreeView item is selected or not"""
return win32defines.TVIS_EXPANDED == (win32defines.TVIS_EXPANDED & self.state())
# Non PEP-8 alias
IsExpanded = deprecated(is_expanded)
#----------------------------------------------------------------
def _readitem(self):
"""Read the treeview item"""
remote_mem = RemoteMemoryBlock(self.tree_ctrl)
if is64bitprocess(self.tree_ctrl.process_id()) or not is_x64_Python():
item = win32structures.TVITEMW()
else:
item = win32structures.TVITEMW32()
item.mask = win32defines.TVIF_TEXT | \
win32defines.TVIF_HANDLE | \
win32defines.TVIF_CHILDREN | \
win32defines.TVIF_STATE
# set the address for the text
item.pszText = remote_mem.Address() + ctypes.sizeof(item) + 16
item.cchTextMax = 2000
item.hItem = self.elem
item.stateMask = wintypes.UINT(-1)
# Write the local TVITEM structure to the remote memory block
remote_mem.Write(item)
# read the entry
retval = self.tree_ctrl.send_message(
win32defines.TVM_GETITEMW,
0,
remote_mem)
text = ''
if retval:
remote_mem.Read(item)
#self.__item = item
# Read the remote text string
char_data = ctypes.create_unicode_buffer(2000)
remote_mem.Read(char_data, item.pszText)
text = char_data.value
else:
# seems that this may not always be correct
raise ctypes.WinError()
return item, text
#====================================================================
class TreeViewWrapper(hwndwrapper.HwndWrapper):
"""Class that wraps Windows TreeView common control"""
friendlyclassname = "TreeView"
windowclasses = [
"SysTreeView32", r"WindowsForms\d*\.SysTreeView32\..*", "TTreeView", "TreeList.TreeListCtrl"]
#----------------------------------------------------------------
def __init__(self, hwnd):
"""Initialise the instance"""
super(TreeViewWrapper, self).__init__(hwnd)
@property
def writable_props(self):
"""Extend default properties list."""
props = super(TreeViewWrapper, self).writable_props
props.extend(['item_count'])
return props
#----------------------------------------------------------------
def item_count(self):
"""Return the count of the items in the treeview"""
return self.send_message(win32defines.TVM_GETCOUNT)
# Non PEP-8 alias
ItemCount = deprecated(item_count)
#----------------------------------------------------------------
def texts(self):
"""Return all the text for the tree view"""
texts = [self.window_text(), ]
if self.item_count():
texts.append(self.tree_root().text())
elements = self.tree_root().sub_elements()
texts.extend([elem.text() for elem in elements])
return texts
#----------------------------------------------------------------
def tree_root(self):
"""Return the root element of the tree view"""
# get the root item:
root_elem = self.send_message(
win32defines.TVM_GETNEXTITEM,
win32defines.TVGN_ROOT)
# Sometimes there is no root element
if not root_elem:
return None
return _treeview_element(root_elem, self)
# Non PEP-8 alias
Root = deprecated(tree_root, deprecated_name='Root')
#----------------------------------------------------------------
def roots(self):
"""Get root items of the control"""
roots = []
cur_elem = self.tree_root()
while cur_elem:
roots.append(cur_elem)
cur_elem = cur_elem.next_item()
return roots
# Non PEP-8 alias
Roots = deprecated(roots)
#----------------------------------------------------------------
def get_properties(self):
"""Get the properties for the control as a dictionary"""
props = super(TreeViewWrapper, self).get_properties()
props['item_count'] = self.item_count()
return props
#----------------------------------------------------------------
def get_item(self, path, exact=False):
r"""Read the TreeView item
* **path** the path to the item to return. This can be one of
the following:
* A string separated by \\ characters. The first character must
be \\. This string is split on the \\ characters and each of
these is used to find the specific child at each level. The
\\ represents the root item - so you don't need to specify the
root itself.
* A list/tuple of strings - The first item should be the root
element.
* A list/tuple of integers - The first item the index which root
to select.
"""
# work is just based on integers for now
if not self.item_count():
return None
# Ensure the path is absolute
if isinstance(path, six.string_types):
if not path.startswith("\\"):
raise RuntimeError(
"Only absolute paths allowed - "
"please start the path with \\")
path = path.split("\\")[1:]
current_elem = None
# find the correct root elem
if isinstance(path[0], int):
current_elem = self.roots()[path[0]]
else:
roots = self.roots()
texts = [r.text() for r in roots]
#not used var: indices = range(0, len(texts))
if exact:
if path[0] in texts:
current_elem = roots[texts.index(path[0])]
else:
raise IndexError("There is no root element equal to '{0}'".format(path[0]))
else:
try:
current_elem = findbestmatch.find_best_match(
path[0], texts, roots, limit_ratio=.6)
except IndexError:
raise IndexError("There is no root element similar to '{0}'".format(path[0]))
# get the correct lowest level item
# current_elem.get_child
# for i in range(0, path[0]):
# current_elem = current_elem.next_item()
#
# if current_elem is None:
# raise IndexError("Root Item '%s' does not have %d sibling(s)"%
# (self.tree_root().window_text(), i + 1))
#
# remove the first (empty) item and the root element as we have
# dealt with it (string or integer)
path = path[1:]
# now for each of the lower levels
# just index into it's children
for child_spec in path:
# ensure that the item is expanded (as this is sometimes required
# for loading the tree view branches
current_elem.expand()
try:
current_elem = current_elem.get_child(child_spec, exact)
except IndexError:
if isinstance(child_spec, six.string_types):
raise IndexError("Item '%s' does not have a child '%s'" %
(current_elem.text(), child_spec))
else:
raise IndexError("Item '%s' does not have %d children" %
(current_elem.text(), child_spec + 1))
# self.send_message_timeout(
# win32defines.TVM_EXPAND,
# win32defines.TVE_EXPAND,
# current_elem)
return current_elem
item = get_item # this is an alias to be consistent with other content elements
# Non PEP-8 alias
Item = deprecated(item)
# Non PEP-8 alias
GetItem = deprecated(get_item)
#----------------------------------------------------------------
def select(self, path):
"""Select the treeview item"""
# http://stackoverflow.com/questions/14111333/treeview-set-default-select-item-and-highlight-blue-this-item
# non-focused TreeView can ignore TVM_SELECTITEM
self.set_focus()
elem = self.get_item(path)
retval = self.send_message(
win32defines.TVM_SELECTITEM, # message
win32defines.TVGN_CARET, # how to select
elem.elem) # item to select
if retval != win32defines.TRUE:
raise ctypes.WinError()
#win32functions.WaitGuiThreadIdle(self.handle)
#time.sleep(Timings.after_treeviewselect_wait)
# Non PEP-8 alias
Select = deprecated(select)
#-----------------------------------------------------------
def is_selected(self, path):
"""Return True if the item is selected"""
return win32defines.TVIS_SELECTED == (win32defines.TVIS_SELECTED &
self.get_item(path).state())
# Non PEP-8 alias
IsSelected = deprecated(is_selected)
#----------------------------------------------------------------
def ensure_visible(self, path):
"""Make sure that the TreeView item is visible"""
elem = self.get_item(path)
return elem.ensure_visible()
# Non PEP-8 alias
EnsureVisible = deprecated(ensure_visible)
#----------------------------------------------------------------
def print_items(self):
"""Print all items with line indents"""
self.text = self.window_text() + "\n"
def print_one_level(item, ident):
"""Get texts for the item and its children"""
self.text += " " * ident + item.text() + "\n"
for child in item.children():
print_one_level(child, ident + 1)
for root in self.roots():
print_one_level(root, 0)
return self.text
# Non PEP-8 alias
PrintItems = deprecated(print_items)
# #-----------------------------------------------------------
# def uncheck(self, path):
# """Uncheck the ListView item"""
# self.verify_actionable()
#
# elem = self.get_item(path)
#
## lvitem = win32structures.LVITEMW()
##
## lvitem.mask = win32defines.LVIF_STATE
## lvitem.state = 0x1000
## lvitem.stateMask = win32defines.LVIS_STATEIMAGEMASK
##
## remote_mem = RemoteMemoryBlock(self)
## remote_mem.Write(lvitem)
##
## self.send_message(
## win32defines.LVM_SETITEMSTATE, item, remote_mem)
##
## del remote_mem
#
#
# #-----------------------------------------------------------
# def check(self, path):
# """Check the ListView item"""
# self.verify_actionable()
#
# elem = self.get_item(path)
#
# #lvitem = win32structures.LVITEMW()
#
# lvitem.mask = win32defines.LVIF_STATE
# lvitem.state = 0x2000
# lvitem.stateMask = win32defines.LVIS_STATEIMAGEMASK
#
# remote_mem = RemoteMemoryBlock(self)
# remote_mem.Write(lvitem)
#
# self.send_message(
# win32defines.LVM_SETITEMSTATE, item, remote_mem)
#
# del remote_mem
#
# #-----------------------------------------------------------
# def is_checked(self, path):
# """Return whether the ListView item is checked or not"""
# elem = self.get_item(path)
#
# elem.state
#
# state = self.send_message(
# win32defines.LVM_GETITEMSTATE,
# item,
# win32defines.LVIS_STATEIMAGEMASK)
#
# return state & 0x2000
#====================================================================
class HeaderWrapper(hwndwrapper.HwndWrapper):
"""Class that wraps Windows ListView Header common control"""
friendlyclassname = "Header"
windowclasses = ["SysHeader32", "msvb_lib_header"]
#----------------------------------------------------------------
def __init__(self, hwnd):
"""Initialise the instance"""
super(HeaderWrapper, self).__init__(hwnd)
#----------------------------------------------------------------
def item_count(self):
"""Return the number of columns in this header"""
# get the number of items in the header...
return self.send_message(win32defines.HDM_GETITEMCOUNT)
# Non PEP-8 alias
ItemCount = deprecated(item_count)
#----------------------------------------------------------------
def get_column_rectangle(self, column_index):
"""Return the rectangle for the column specified by column_index"""
remote_mem = RemoteMemoryBlock(self)
# get the column rect
rect = win32structures.RECT()
remote_mem.Write(rect)
retval = self.send_message(
win32defines.HDM_GETITEMRECT,
column_index,
remote_mem)
if retval:
rect = remote_mem.Read(rect)
else:
raise ctypes.WinError()
del remote_mem
return rect
# Non PEP-8 alias
GetColumnRectangle = deprecated(get_column_rectangle)
#----------------------------------------------------------------
def client_rects(self):
"""Return all the client rectangles for the header control"""
rects = [self.client_rect(), ]
for col_index in range(0, self.item_count()):
rects.append(self.get_column_rectangle(col_index))
return rects
#----------------------------------------------------------------
def get_column_text(self, column_index):
"""Return the text for the column specified by column_index"""
remote_mem = RemoteMemoryBlock(self)
item = win32structures.HDITEMW()
item.mask = win32defines.HDI_FORMAT | \
win32defines.HDI_WIDTH | \
win32defines.HDI_TEXT # | HDI_ORDER
item.cchTextMax = 2000
# set up the pointer to the text
# it should be at the
item.pszText = remote_mem.Address() + ctypes.sizeof(item) + 1
# put the information in the memory that the
# other process can read/write
remote_mem.Write(item)
# ask the other process to update the information
retval = self.send_message(
win32defines.HDM_GETITEMW,
column_index,
remote_mem)
if retval:
item = remote_mem.Read(item)
# Read the remote text string
char_data = ctypes.create_unicode_buffer(2000)
remote_mem.Read(char_data, item.pszText)
return char_data.value
return None
# Non PEP-8 alias
GetColumnText = deprecated(get_column_text)
#----------------------------------------------------------------
def texts(self):
"""Return the texts of the Header control"""
texts = [self.window_text(), ]
for i in range(0, self.item_count()):
texts.append(self.get_column_text(i))
return texts
# #----------------------------------------------------------------
# def _fill_header_info(self):
# """Get the information from the header control"""
# remote_mem = RemoteMemoryBlock(self)
#
# for col_index in range(0, self.Count()):
#
# item = win32structures.HDITEMW()
# item.mask = win32defines.HDI_FORMAT | \
# win32defines.HDI_WIDTH | \
# win32defines.HDI_TEXT #| HDI_ORDER
# item.cchTextMax = 2000
#
# # set up the pointer to the text
# # it should be at the
# item.pszText = remote_mem.Address() + ctypes.sizeof(item) + 1
#
# # put the information in the memory that the
# # other process can read/write
# remote_mem.Write(item)
#
# # ask the other process to update the information
# retval = self.send_message(
# win32defines.HDM_GETITEMW,
# col_index,
# remote_mem)
#
# if retval:
# item = remote_mem.Read(item)
#
# # Read the remote text string
# charData = ctypes.create_unicode_buffer(2000)
# remote_mem.Read(charData, item.pszText)
# self._extra_texts.append(charData.value)
#====================================================================
class StatusBarWrapper(hwndwrapper.HwndWrapper):
"""Class that wraps Windows Status Bar common control"""
friendlyclassname = "StatusBar"
windowclasses = [
"msctls_statusbar32",
".*StatusBar",
r"WindowsForms\d*\.msctls_statusbar32\..*"]
#----------------------------------------------------------------
def __init__(self, hwnd):
"""Initialise the instance"""
super(StatusBarWrapper, self).__init__(hwnd)
@property
def writable_props(self):
"""Extend default properties list."""
props = super(StatusBarWrapper, self).writable_props
props.extend(['border_widths',
'part_count',
'part_right_edges',
])
return props
#----------------------------------------------------------------
def border_widths(self):
"""Return the border widths of the StatusBar
A dictionary of the 3 available widths is returned:
Horizontal - the horizontal width
Vertical - The width above and below the status bar parts
Inter - The width between parts of the status bar
"""
remote_mem = RemoteMemoryBlock(self)
# get the borders for each of the areas there can be a border.
borders = (ctypes.c_int * 3)()
remote_mem.Write(borders)
self.send_message(
win32defines.SB_GETBORDERS,
0,
remote_mem
)
borders = remote_mem.Read(borders)
borders_widths = {}
borders_widths['Horizontal'] = borders[0]
borders_widths['Vertical'] = borders[1]
borders_widths['Inter'] = borders[2]
del remote_mem
return borders_widths
# Non PEP-8 alias
BorderWidths = deprecated(border_widths)
#----------------------------------------------------------------
def part_count(self):
"""Return the number of parts"""
# get the number of parts for this status bar
return self.send_message(
win32defines.SB_GETPARTS,
0,
0)
# Non PEP-8 alias
PartCount = deprecated(part_count)
#----------------------------------------------------------------
def part_right_edges(self):
"""Return the widths of the parts"""
remote_mem = RemoteMemoryBlock(self)
# get the number of parts for this status bar
parts = (ctypes.c_int * self.part_count())()
remote_mem.Write(parts)
self.send_message(
win32defines.SB_GETPARTS,
self.part_count(),
remote_mem
)
parts = remote_mem.Read(parts)
del remote_mem
return [int(part) for part in parts]
# Non PEP-8 alias
PartRightEdges = deprecated(part_right_edges)
#----------------------------------------------------------------
def get_part_rect(self, part_index):
"""Return the rectangle of the part specified by part_index"""
if part_index >= self.part_count():
raise IndexError(
"Only {0} parts available you asked for part {1} (zero based)".format(
self.part_count(), part_index))
remote_mem = RemoteMemoryBlock(self)
# get the rectangle for this item
rect = win32structures.RECT()
remote_mem.Write(rect)
self.send_message(
win32defines.SB_GETRECT,
part_index,
remote_mem)
rect = remote_mem.Read(rect)
del remote_mem
return rect
# Non PEP-8 alias
GetPartRect = deprecated(get_part_rect)
#----------------------------------------------------------------
def client_rects(self):
"""Return the client rectangles for the control"""
rects = [self.client_rect()]
for i in range(self.part_count()):
rects.append(self.get_part_rect(i))
return rects
#----------------------------------------------------------------
def get_part_text(self, part_index):
"""Return the text of the part specified by part_index"""
if part_index >= self.part_count():
raise IndexError(
"Only {0} parts available you asked for part {1} (zero based)".format(
self.part_count(), part_index))
remote_mem = RemoteMemoryBlock(self)
textlen = self.send_message(
win32defines.SB_GETTEXTLENGTHW,
part_index,
0
)
#draw_operation = win32functions.HiWord(textlen)
textlen = win32functions.LoWord(textlen)
# get the text for this item
text = ctypes.create_unicode_buffer(textlen + ctypes.sizeof(ctypes.c_wchar))
remote_mem.Write(text)
self.send_message(
win32defines.SB_GETTEXTW,
part_index,
remote_mem
)
text = remote_mem.Read(text)
del remote_mem
return text.value
# Non PEP-8 alias
GetPartText = deprecated(get_part_text)
#----------------------------------------------------------------
def texts(self):
"""Return the texts for the control"""
texts = [self.window_text()]
for i in range(self.part_count()):
texts.append(self.get_part_text(i))
return texts
#====================================================================
class TabControlWrapper(hwndwrapper.HwndWrapper):
"""Class that wraps Windows Tab common control"""
friendlyclassname = "TabControl"
windowclasses = [
"SysTabControl32",
r"WindowsForms\d*\.SysTabControl32\..*"]
#----------------------------------------------------------------
def __init__(self, hwnd):
"""Initialise the instance"""
super(TabControlWrapper, self).__init__(hwnd)
#self.writable_props.append("TabStates")
@property
def writable_props(self):
"""Extend default properties list."""
props = super(TabControlWrapper, self).writable_props
props.extend(['tab_count'])
return props
#----------------------------------------------------------------
def row_count(self):
"""Return the number of rows of tabs"""
return self.send_message(win32defines.TCM_GETROWCOUNT)
# Non PEP-8 alias
RowCount = deprecated(row_count)
#----------------------------------------------------------------
def get_selected_tab(self):
"""Return the index of the selected tab"""
return self.send_message(win32defines.TCM_GETCURSEL)
# Non PEP-8 alias
GetSelectedTab = deprecated(get_selected_tab)
#----------------------------------------------------------------
def tab_count(self):
"""Return the number of tabs"""
return self.send_message(win32defines.TCM_GETITEMCOUNT)
# Non PEP-8 alias
TabCount = deprecated(tab_count)
#----------------------------------------------------------------
def get_tab_rect(self, tab_index):
"""Return the rectangle to the tab specified by tab_index"""
if tab_index >= self.tab_count():
raise IndexError(
"Only {0} tabs available you asked for tab {1} (zero based)".format(
self.tab_count(), tab_index))
remote_mem = RemoteMemoryBlock(self)
rect = win32structures.RECT()
remote_mem.Write(rect)
self.send_message(
win32defines.TCM_GETITEMRECT, tab_index, remote_mem)
remote_mem.Read(rect)
del remote_mem
return rect
# Non PEP-8 alias
GetTabRect = deprecated(get_tab_rect)
# #----------------------------------------------------------------
# def get_tab_state(self, tab_index):
# """Return the state of the tab"""
# if tab_index >= self.tab_count():
# raise IndexError(
# "Only %d tabs available you asked for tab %d (zero based)" % (
# self.tab_count(),
# tab_index))
#
# remote_mem = RemoteMemoryBlock(self)
#
# item = win32structures.TCITEMW()
# item.mask = win32defines.TCIF_STATE
# remote_mem.Write(item)
#
# ret = self.send_message(
# win32defines.TCM_GETITEMW, tab_index, remote_mem)
#
# remote_mem.Read(item)
# del remote_mem
#
# if not ret:
# raise ctypes.WinError()
#
# return item.dwState
# # Non PEP-8 alias
# GetTabState = deprecated(get_tab_state)
#----------------------------------------------------------------
def get_tab_text(self, tab_index):
"""Return the text of the tab"""
if tab_index >= self.tab_count():
raise IndexError(
"Only {0} tabs available you asked for tab {1} (zero based)".format(
self.tab_count(), tab_index))
remote_mem = RemoteMemoryBlock(self)
item = win32structures.TCITEMW()
item.mask = win32defines.TCIF_TEXT
item.cchTextMax = 1999
item.pszText = remote_mem.Address() + ctypes.sizeof(item)
remote_mem.Write(item)
self.send_message(
win32defines.TCM_GETITEMW, tab_index, remote_mem)
remote_mem.Read(item)
# Read the text that has been written
text = ctypes.create_unicode_buffer(2000)
text = remote_mem.Read(text, remote_mem.Address() + ctypes.sizeof(item))
return text.value
# Non PEP-8 alias
GetTabText = deprecated(get_tab_text)
#----------------------------------------------------------------
def get_properties(self):
"""Return the properties of the TabControl as a Dictionary"""
props = super(TabControlWrapper, self).get_properties()
props['tab_count'] = self.tab_count()
return props
# #----------------------------------------------------------------
# def tab_states(self):
# """Return the tab state for all the tabs"""
# states = []
# for i in range(0, self.tab_count()):
# states.append(self.GetTabState(i))
# return states
# # Non PEP-8 alias
# TabStates = deprecated(tab_states)
#----------------------------------------------------------------
def client_rects(self):
"""Return the client rectangles for the Tab Control"""
rects = [self.client_rect()]
for tab_index in range(0, self.tab_count()):
rects.append(self.get_tab_rect(tab_index))
return rects
#----------------------------------------------------------------
def texts(self):
"""Return the texts of the Tab Control"""
texts = [self.window_text()]
for i in range(0, self.tab_count()):
texts.append(self.get_tab_text(i))
return texts
#----------------------------------------------------------------
def select(self, tab):
"""Select the specified tab on the tab control"""
self.verify_actionable()
logging_tab = tab
# if it's a string then find the index of
# the tab with that text
if isinstance(tab, six.string_types):
# find the string in the tab control
best_text = findbestmatch.find_best_match(
tab, self.texts(), self.texts())
tab = self.texts().index(best_text) - 1
if tab >= self.tab_count():
raise IndexError(
"Only {0} tabs available you asked for tab {1} (zero based)".format(
self.tab_count(), tab))
if self.has_style(win32defines.TCS_BUTTONS):
# workaround for TCS_BUTTONS case
self.click(coords=self.get_tab_rect(tab))
# TCM_SETCURFOCUS changes focus, but doesn't select the tab
# TCM_SETCURSEL selects the tab, but tab content is not re-drawn
# (TODO: need to find a solution without WM_CLICK)
#self.Notify(win32defines.TCN_SELCHANGING)
#self.send_message(win32defines.TCM_SETCURSEL, tab)
#self.Notify(win32defines.TCN_SELCHANGE)
else:
self.send_message(win32defines.TCM_SETCURFOCUS, tab)
win32functions.WaitGuiThreadIdle(self.handle)
time.sleep(Timings.after_tabselect_wait)
self.actions.log('Selected tab "' + str(logging_tab) + '"')
return self
# Non PEP-8 alias
Select = deprecated(select)
#====================================================================
class _toolbar_button(object):
"""Wrapper around Toolbar button (TBBUTTONINFO) items"""
#----------------------------------------------------------------
def __init__(self, index_, tb_handle):
"""Initialize the item"""
self.toolbar_ctrl = tb_handle
self.index = index_
self.info = self.toolbar_ctrl.get_button(self.index)
#----------------------------------------------------------------
def rectangle(self):
"""Get the rectangle of a button on the toolbar"""
remote_mem = RemoteMemoryBlock(self.toolbar_ctrl)
rect = win32structures.RECT()
remote_mem.Write(rect)
self.toolbar_ctrl.send_message(win32defines.TB_GETRECT,
self.info.idCommand,
remote_mem)
rect = remote_mem.Read(rect)
if rect == win32structures.RECT(0, 0, 0, 0):
self.toolbar_ctrl.send_message(win32defines.TB_GETITEMRECT,
self.index,
remote_mem)
rect = remote_mem.Read(rect)
del remote_mem
return rect
# Non PEP-8 alias
Rectangle = deprecated(rectangle)
# #----------------------------------------------------------------
# def press(self, press = True):
# """Find where the button is and click it"""
# if press:
# press_flag = win32functions.MakeLong(0, 1)
# else:
# press_flag = 0
#
# ret = self.toolbar_ctrl.send_message_timeout(
# win32defines.TB_PRESSBUTTON,
# self.info.idCommand,
# press_flag)
#
# # Notify the parent that we are finished selecting
# #self.toolbar_ctrl.notify_parent(win32defines.TBN_TOOLBARCHANGE)
#
# win32functions.WaitGuiThreadIdle(self.toolbar_ctrl.handle)
# time.sleep(Timings.after_toobarpressbutton_wait)
# # Non PEP-8 alias
# Press = deprecated(press)
#
# #----------------------------------------------------------------
# def press(self):
# """Find where the button is and click it"""
# self.Press(press = False)
# # Non PEP-8 alias
# Press = deprecated(press)
#
# #----------------------------------------------------------------
# def check(self, check = True):
# """Find where the button is and click it"""
# if check:
# check_flag = win32functions.MakeLong(0, 1)
# else:
# check_flag = 0
#
# ret = self.toolbar_ctrl.send_message_timeout(
# win32defines.TB_CHECKBUTTON,
# self.info.idCommand,
# check_flag)
#
# # Notify the parent that we are finished selecting
# #self.toolbar_ctrl.notify_parent(win32defines.TBN_TOOLBARCHANGE)
#
# win32functions.WaitGuiThreadIdle(self.toolbar_ctrl.handle)
# time.sleep(Timings.after_toobarpressbutton_wait)
#
# #----------------------------------------------------------------
# def uncheck(self):
# self.check(check = False)
#----------------------------------------------------------------
def text(self):
"""Return the text of the button"""
return self.info.text
# Non PEP-8 alias
Text = deprecated(text)
#----------------------------------------------------------------
def style(self):
"""Return the style of the button"""
return self.toolbar_ctrl.send_message(
win32defines.TB_GETSTYLE, self.info.idCommand)
# Non PEP-8 alias
Style = deprecated(style)
#----------------------------------------------------------------
def has_style(self, style):
"""Return True if the button has the specified style"""
return self.style() & style == style
# Non PEP-8 alias
HasStyle = deprecated(has_style)
#----------------------------------------------------------------
def state(self):
"""Return the state of the button"""
return self.toolbar_ctrl.send_message(
win32defines.TB_GETSTATE, self.info.idCommand)
# Non PEP-8 alias
State = deprecated(state)
#----------------------------------------------------------------
def is_checkable(self):
"""Return if the button can be checked"""
return self.has_style(win32defines.TBSTYLE_CHECK)
# Non PEP-8 alias
IsCheckable = deprecated(is_checkable)
#----------------------------------------------------------------
def is_pressable(self):
"""Return if the button can be pressed"""
return self.has_style(win32defines.TBSTYLE_BUTTON)
# Non PEP-8 alias
IsPressable = deprecated(is_pressable)
#----------------------------------------------------------------
def is_checked(self):
"""Return if the button is in the checked state"""
return self.state() & win32defines.TBSTATE_CHECKED == win32defines.TBSTATE_CHECKED
# Non PEP-8 alias
IsChecked = deprecated(is_checked)
#----------------------------------------------------------------
def is_pressed(self):
"""Return if the button is in the pressed state"""
return self.state() & win32defines.TBSTATE_PRESSED == win32defines.TBSTATE_PRESSED
# Non PEP-8 alias
IsPressed = deprecated(is_pressed)
#----------------------------------------------------------------
def is_enabled(self):
"""Return if the button is in the pressed state"""
# make sure it has an ID
if not self.info.idCommand:
return False
return self.state() & win32defines.TBSTATE_ENABLED == win32defines.TBSTATE_ENABLED
# Non PEP-8 alias
IsEnabled = deprecated(is_enabled)
#----------------------------------------------------------------
def click(self, button="left", pressed=""):
"""Click on the Toolbar button"""
self.toolbar_ctrl.click(button=button, coords=self.rectangle(), pressed=pressed)
time.sleep(Timings.after_toobarpressbutton_wait)
# Non PEP-8 alias
Click = deprecated(click)
#----------------------------------------------------------------
def click_input(self, button="left", double=False, wheel_dist=0, pressed=""):
"""Click on the Toolbar button"""
self.toolbar_ctrl.click_input(button=button, coords=self.rectangle().mid_point(),
double=double, wheel_dist=wheel_dist, pressed=pressed)
time.sleep(Timings.after_toobarpressbutton_wait)
# Non PEP-8 alias
ClickInput = deprecated(click_input)
#====================================================================
class ToolbarWrapper(hwndwrapper.HwndWrapper):
"""Class that wraps Windows Toolbar common control"""
friendlyclassname = "Toolbar"
windowclasses = [
"ToolbarWindow32",
"TToolBar",
r"WindowsForms\d*\.ToolbarWindow32\..*",
"Afx:ToolBar:.*"]
#----------------------------------------------------------------
def __init__(self, hwnd):
"""Initialise the instance"""
super(ToolbarWrapper, self).__init__(hwnd)
@property
def writable_props(self):
"""Extend default properties list."""
props = super(ToolbarWrapper, self).writable_props
props.extend(['button_count'])
return props
#----------------------------------------------------------------
def button_count(self):
"""Return the number of buttons on the ToolBar"""
return self.send_message(win32defines.TB_BUTTONCOUNT)
# Non PEP-8 alias
ButtonCount = deprecated(button_count)
#----------------------------------------------------------------
def button(self, button_identifier, exact=True, by_tooltip=False):
"""Return the button at index button_index"""
if isinstance(button_identifier, six.string_types):
texts = self.texts()[1:]
self.actions.log('Toolbar buttons: ' + str(texts))
# one of these will be returned for the matching text
indices = [i for i in range(0, len(texts))]
if by_tooltip:
texts = self.tip_texts()
self.actions.log('Toolbar tooltips: ' + str(texts))
if exact:
try:
button_index = texts.index(button_identifier)
except ValueError:
raise findbestmatch.MatchError(items=texts, tofind=button_identifier)
else:
# find which index best matches that text
button_index = findbestmatch.find_best_match(button_identifier, texts, indices)
else:
button_index = button_identifier
return _toolbar_button(button_index, self)
# Non PEP-8 alias
Button = deprecated(button)
#----------------------------------------------------------------
def get_button_struct(self, button_index):
"""Return TBBUTTON structure on the Toolbar button"""
if button_index >= self.button_count():
raise IndexError(
"0 to {0} are acceptaple for button_index".format(self.button_count()))
remote_mem = RemoteMemoryBlock(self)
if is64bitprocess(self.process_id()) or not is_x64_Python():
button = win32structures.TBBUTTON()
else:
button = win32structures.TBBUTTON32()
remote_mem.Write(button)
ret = self.send_message(
win32defines.TB_GETBUTTON, button_index, remote_mem)
if not ret:
del remote_mem
raise RuntimeError(
"get_button failed for button index {0}".format(button_index))
remote_mem.Read(button)
del remote_mem
return button
# Non PEP-8 alias
GetButtonStruct = deprecated(get_button_struct)
#----------------------------------------------------------------
def get_button(self, button_index):
"""Return information on the Toolbar button"""
button = self.get_button_struct(button_index)
if is64bitprocess(self.process_id()) or not is_x64_Python():
button_info = win32structures.TBBUTTONINFOW()
else:
button_info = win32structures.TBBUTTONINFOW32()
button_info.cbSize = ctypes.sizeof(button_info)
button_info.dwMask = \
win32defines.TBIF_COMMAND | \
win32defines.TBIF_SIZE | \
win32defines.TBIF_STYLE | \
win32defines.TBIF_IMAGE | \
win32defines.TBIF_LPARAM | \
win32defines.TBIF_STATE | \
win32defines.TBIF_TEXT
#win32defines.TBIF_IMAGELABEL | \
button_info.cchText = 2000
remote_mem = RemoteMemoryBlock(self)
# set the text address to after the structures
button_info.pszText = remote_mem.Address() + \
ctypes.sizeof(button_info)
# fill the button_info structure
remote_mem.Write(button_info)
ret = self.send_message(
win32defines.TB_GETBUTTONINFOW,
button.idCommand,
remote_mem)
remote_mem.Read(button_info)
if ret == -1:
del remote_mem
raise RuntimeError('GetButtonInfo failed for button with command' +
' id {0}'.format(button.idCommand))
# read the text
button_info.text = ctypes.create_unicode_buffer(1999)
remote_mem.Read(button_info.text, remote_mem.Address() +
ctypes.sizeof(button_info))
button_info.text = button_info.text.value
del remote_mem
return button_info
# Non PEP-8 alias
GetButton = deprecated(get_button)
#----------------------------------------------------------------
def texts(self):
"""Return the texts of the Toolbar"""
texts = [self.window_text()]
for i in range(0, self.button_count()):
btn_text = self.get_button(i).text
lines = btn_text.split('\n')
if lines:
texts.append(lines[0])
else:
texts.append(btn_text)
return texts
#----------------------------------------------------------------
def tip_texts(self):
"""Return the tip texts of the Toolbar (without window text)"""
texts = []
for i in range(0, self.button_count()):
# it works for MFC
btn_tooltip_index = self.get_button_struct(i).iString
# usually iString == -1 for separator
# other cases if any
if not (-1 <= btn_tooltip_index < self.get_tool_tips_control().tool_count()):
btn_tooltip_index = i
btn_text = self.get_tool_tips_control().get_tip_text(btn_tooltip_index + 1)
texts.append(btn_text)
return texts
# Non PEP-8 alias
TipTexts = deprecated(tip_texts)
#----------------------------------------------------------------
def get_button_rect(self, button_index):
"""Get the rectangle of a button on the toolbar"""
return self.button(button_index).rectangle()
# Non PEP-8 alias
GetButtonRect = deprecated(get_button_rect)
#----------------------------------------------------------------
def get_tool_tips_control(self):
"""Return the tooltip control associated with this control"""
return ToolTipsWrapper(self.send_message(win32defines.TB_GETTOOLTIPS))
# Non PEP-8 alias
GetToolTipsControl = deprecated(get_tool_tips_control)
# def right_click(self, button_index, **kwargs):
# """Right click for Toolbar buttons"""
#
# win32functions.SetCapture(self)
#
# button = self.get_button(button_index)
# #print button.text
#
# rect = self.get_button_rect(button_index)
#
# x = (rect.left + rect.right) /2
# y = (rect.top + rect.bottom) /2
#
# #print x, y
#
#
# self.move_mouse_input(coords = (x, y))
# self.send_message(
# win32defines.WM_MOUSEACTIVATE,
# self.parent().parent().parent(),
# win32functions.MakeLong(
# win32defines.WM_RBUTTONDOWN,
# win32defines.HTCLIENT)
# )
#
# self.press_mouse(pressed = "right", button = "right", coords = (x, y))
#
# remote_mem = RemoteMemoryBlock(self)
#
# # now we need to notify the parent that the state has changed
# nmlv = win32structures.NMMOUSE()
# nmlv.hdr.hwndFrom = self.handle
# nmlv.hdr.idFrom = self.control_id()
# nmlv.hdr.code = win32defines.NM_RCLICK
#
#
# nmlv.dwItemSpec = button.idCommand
# #nmlv.dwItemData
#
# nmlv.pt = win32structures.POINT()
#
# remote_mem.Write(nmlv)
#
# self.send_message(
# win32defines.WM_NOTIFY,
# self.control_id(),
# remote_mem)
#
# del remote_mem
#
#
# self.release_mouse(button = "right", coords = (x, y))
#
# win32functions.ReleaseCapture()
# # Non PEP-8 alias
# Right_Click = deprecated(right_click)
#----------------------------------------------------------------
def press_button(self, button_identifier, exact=True):
"""Find where the button is and click it"""
msg = 'Clicking "' + self.window_text() + '" toolbar button "' + str(button_identifier) + '"'
self.actions.logSectionStart(msg)
self.actions.log(msg)
button = self.button(button_identifier, exact=exact)
# transliterated from
# http://source.winehq.org/source/dlls/comctl32/toolbar.c
# if the button is enabled
if button.is_enabled():
button.click_input()
else:
raise RuntimeError('Toolbar button "' + str(button_identifier) + '" is disabled! Cannot click it.')
self.actions.logSectionEnd()
# Non PEP-8 alias
PressButton = deprecated(press_button)
#----------------------------------------------------------------
def check_button(self, button_identifier, make_checked, exact=True):
"""Find where the button is and click it if it's unchecked and vice versa"""
self.actions.logSectionStart('Checking "' + self.window_text() +
'" toolbar button "' + str(button_identifier) + '"')
button = self.button(button_identifier, exact=exact)
if make_checked:
self.actions.log('Pressing down toolbar button "' + str(button_identifier) + '"')
else:
self.actions.log('Pressing up toolbar button "' + str(button_identifier) + '"')
# TODO: add waiting for a button state
if not button.is_enabled():
self.actions.log('Toolbar button is not enabled!')
raise RuntimeError("Toolbar button is not enabled!")
if button.is_checked() != make_checked:
button.click_input()
# wait while button has changed check state
#i = 0
#while button.is_checked() != make_checked:
# time.sleep(0.5)
# i += 1
# if i > 10:
# raise RuntimeError("Cannot wait button check state!")
self.actions.logSectionEnd()
# Non PEP-8 alias
CheckButton = deprecated(check_button)
#----------------------------------------------------------------
def menu_bar_click_input(self, path, app):
"""Select menu bar items by path (experimental!)
The path is specified by a list of items separated by '->' each Item
can be the zero based index of the item to return prefaced by # e.g. #1.
Example:
"#1 -> #0",
"#1->#0->#0"
"""
warnings.warn("menu_bar_click_input method is experimental. Use carefully!")
self.actions.logSectionStart('Clicking "{0}" menu bar path "{1}"'.format(self.window_text(), path))
if isinstance(path, list):
parts = path
else:
parts = path.split("->")
indices = []
for part in parts:
if isinstance(part, int):
indices.append(part)
else:
item_string = part.strip().lstrip('#')
try:
index = int(item_string)
except Exception:
raise TypeError('Path must contain integers only!')
indices.append(index)
# circle import doesn't work with current package structure
# so use the app instance as a method param
#app = Application().Connect(handle=self.handle)
current_toolbar = self
current_toolbar.set_focus() # to make sure it can be clicked immediately
for i, index in enumerate(indices):
windows_before = app.windows(visible_only=True)
current_toolbar.button(index).click_input()
if i < len(indices) - 1:
wait_until(5, 0.1, lambda: len(app.windows(visible_only=True)) > len(windows_before))
windows_after = app.windows(visible_only=True)
new_window = set(windows_after) - set(windows_before)
current_toolbar = list(new_window)[0].children()[0]
self.actions.logSectionEnd()
# Non PEP-8 alias
MenuBarClickInput = deprecated(menu_bar_click_input)
# #----------------------------------------------------------------
# def _fill_toolbar_info(self):
# """Get the information from the toolbar"""
# buttonCount = self.send_message(win32defines.TB_BUTTONCOUNT)
# self._extra_props['button_count'] = buttonCount
#
# remote_mem = RemoteMemoryBlock(self)
#
# for i in range(0, buttonCount):
#
# button = win32structures.TBBUTTON()
#
# remote_mem.Write(button)
#
# self.send_message(
# win32defines.TB_GETBUTTON, i, remote_mem)
#
# remote_mem.Read(button)
#
# buttonInfo = win32structures.TBBUTTONINFOW()
# buttonInfo.cbSize = ctypes.sizeof(buttonInfo)
# buttonInfo.dwMask = win32defines.TBIF_TEXT | \
# win32defines.TBIF_COMMAND | \
# win32defines.TBIF_SIZE | \
# win32defines.TBIF_COMMAND | \
# win32defines.TBIF_STYLE | \
# win32defines.TBIF_STATE
#
# buttonInfo.cchText = 2000
#
# # set the text address to after the structures
# buttonInfo.pszText = remote_mem.Address() + \
# ctypes.sizeof(buttonInfo)
#
# # fill the buttonInfo structure
# remote_mem.Write(buttonInfo)
# self.send_message(
# win32defines.TB_GETBUTTONINFOW,
# button.idCommand,
# remote_mem)
# remote_mem.Read(buttonInfo)
#
# # read the text
# text = ctypes.create_unicode_buffer(1999)
# remote_mem.Read(text, remote_mem.Address() + \
# ctypes.sizeof(buttonInfo))
#
# extendedStyle = self.send_message(win32defines.TB_GETEXTENDEDSTYLE)
#
# self._extra_props.setdefault('Buttons', []).append(
# dict(
# iBitMap = button.iBitmap,
# idCommand = button.idCommand,
# fsState = button.fsState,
# fsStyle = button.fsStyle,
# cx = buttonInfo.cx,
# exstyle = extendedStyle
# )
# )
# # if button.fsStyle & TBSTYLE_DROPDOWN == TBSTYLE_DROPDOWN and \
# # (extendedStyle & TBSTYLE_EX_DRAWDDARROWS) != \
# # TBSTYLE_EX_DRAWDDARROWS:
# # props['Buttons'][-1]["DROPDOWNMENU"] = 1
# #
# # self.send_message(WM_COMMAND, button.idCommand)
# #
# # print "Pressing", text.value
# # handle.send_message(TB_PRESSBUTTON, button.idCommand, 1)
# # handle.send_message(TB_PRESSBUTTON, button.idCommand, 0)
#
# self._extra_texts.append(text.value)
#
#
# RB_GETBANDBORDERS
class BandWrapper(win32structures.REBARBANDINFOW):
"""Simple wrapper around REBARBANDINFOW to allow setting new attributes"""
pass
#====================================================================
class ReBarWrapper(hwndwrapper.HwndWrapper):
"""Class that wraps Windows ReBar common control"""
friendlyclassname = "ReBar"
windowclasses = ["ReBarWindow32", ]
#----------------------------------------------------------------
def __init__(self, hwnd):
"""Initialise the instance"""
super(ReBarWrapper, self).__init__(hwnd)
@property
def writable_props(self):
"""Extend default properties list."""
props = super(ReBarWrapper, self).writable_props
props.extend(['band_count'])
return props
#----------------------------------------------------------------
def band_count(self):
"""Return the number of bands in the control"""
return self.send_message(win32defines.RB_GETBANDCOUNT)
# Non PEP-8 alias
BandCount = deprecated(band_count)
#----------------------------------------------------------------
def get_band(self, band_index):
"""Get a band of the ReBar control"""
if band_index >= self.band_count():
raise IndexError(('band_index {0} greater then number of' +
' available bands: {1}').format(band_index, self.band_count()))
remote_mem = RemoteMemoryBlock(self)
band_info = BandWrapper()
band_info.cbSize = ctypes.sizeof(band_info)
band_info.fMask = \
win32defines.RBBIM_CHILD | \
win32defines.RBBIM_CHILDSIZE | \
win32defines.RBBIM_COLORS | \
win32defines.RBBIM_HEADERSIZE | \
win32defines.RBBIM_ID | \
win32defines.RBBIM_IDEALSIZE | \
win32defines.RBBIM_SIZE | \
win32defines.RBBIM_STYLE | \
win32defines.RBBIM_TEXT
# set the pointer for the text
band_info.lpText = win32structures.LPWSTR(
remote_mem.Address() + ctypes.sizeof(band_info))
band_info.cch = 2000
# write the structure
remote_mem.Write(band_info)
# Fill the structure
self.send_message(
win32defines.RB_GETBANDINFOW,
band_index,
remote_mem)
# read it back
remote_mem.Read(band_info)
# read the text
band_info.text = ctypes.create_unicode_buffer(2000)
remote_mem.Read(band_info.text, remote_mem.Address() + ctypes.sizeof(band_info))
band_info.text = band_info.text.value
del remote_mem
return band_info
# Non PEP-8 alias
GetBand = deprecated(get_band)
#----------------------------------------------------------------
def get_tool_tips_control(self):
"""Return the tooltip control associated with this control"""
tips_handle = self.send_message(win32defines.RB_GETTOOLTIPS)
if tips_handle:
return ToolTipsWrapper(tips_handle)
# Non PEP-8 alias
GetToolTipsControl = deprecated(get_tool_tips_control)
#----------------------------------------------------------------
def texts(self):
"""Return the texts of the Rebar"""
texts = [self.window_text()]
for i in range(0, self.band_count()):
band = self.get_band(i)
lines = band.text.split('\n')
if lines:
texts.append(lines[0])
else:
texts.append(band.text)
return texts
#====================================================================
class ToolTip(object):
"""Class that Wraps a single tip from a ToolTip control"""
def __init__(self, ctrl, tip_index):
"""Read the required information"""
self.ctrl = ctrl
self.index = tip_index
remote_mem = RemoteMemoryBlock(self.ctrl)
tipinfo = win32structures.TOOLINFOW()
tipinfo.cbSize = ctypes.sizeof(tipinfo)
#tipinfo.uId = self.index
tipinfo.lpszText = remote_mem.Address() + \
ctypes.sizeof(tipinfo) + 1
remote_mem.Write(tipinfo)
self.ctrl.send_message(
win32defines.TTM_ENUMTOOLSW,
self.index,
remote_mem)
remote_mem.Read(tipinfo)
self.info = tipinfo
# now get the text
self.info.lpszText = remote_mem.Address() + \
ctypes.sizeof(self.info) + 1
remote_mem.Write(self.info)
self.ctrl.send_message(
win32defines.TTM_GETTEXTW, 160, remote_mem)
# There is no way to determine the required buffer size.
# However, tool text, as returned at the lpszText member of the TOOLINFO structure,
# has a maximum length of 80 TCHARs, including the terminating NULL.
# If the text exceeds this length, it is truncated.
# https://msdn.microsoft.com/en-us/library/windows/desktop/bb760375(v=vs.85).aspx
text = ctypes.create_unicode_buffer(80)
remote_mem.Read(text, self.info.lpszText)
self.text = text.value
del remote_mem
#====================================================================
class ToolTipsWrapper(hwndwrapper.HwndWrapper):
"""Class that wraps Windows ToolTips common control (not fully implemented)"""
# mask this class as it is not ready for prime time yet!
friendlyclassname = "ToolTips"
windowclasses = ["tooltips_class32",
".*ToolTip",
"#32774", "MS_WINNOTE", "VBBubble", ]
#----------------------------------------------------------------
def __init__(self, hwnd):
"""Initialize the instance"""
super(ToolTipsWrapper, self).__init__(hwnd)
#----------------------------------------------------------------
def get_tip(self, tip_index):
"""Return the particular tooltip"""
if tip_index >= self.tool_count():
raise IndexError(('tip_index {0} is greater than number of' +
' available tips: {1}').format(tip_index, self.tool_count()))
return ToolTip(self, tip_index)
# Non PEP-8 alias
GetTip = deprecated(get_tip)
#----------------------------------------------------------------
def tool_count(self):
"""Return the number of tooltips"""
return self.send_message(win32defines.TTM_GETTOOLCOUNT)
# Non PEP-8 alias
ToolCount = deprecated(tool_count)
#----------------------------------------------------------------
def get_tip_text(self, tip_index):
"""Return the text of the tooltip"""
return ToolTip(self, tip_index).text
# Non PEP-8 alias
GetTipText = deprecated(get_tip_text)
#----------------------------------------------------------------
def texts(self):
"""Return the text of all the tooltips"""
texts = [self.window_text(), ]
for tip_index in range(0, self.tool_count()):
texts.append(self.get_tip_text(tip_index))
return texts
#====================================================================
class UpDownWrapper(hwndwrapper.HwndWrapper):
"""Class that wraps Windows UpDown common control"""
friendlyclassname = "UpDown"
windowclasses = ["msctls_updown32", "msctls_updown", ]
#----------------------------------------------------------------
def __init__(self, hwnd):
"""Initialise the instance"""
super(UpDownWrapper, self).__init__(hwnd)
#----------------------------------------------------------------
def get_value(self):
"""Get the current value of the UpDown control"""
pos = self.send_message(
win32defines.UDM_GETPOS,
win32structures.LPARAM(0),
win32structures.WPARAM(0),
)
return win32functions.LoWord(pos)
# Non PEP-8 alias
GetValue = deprecated(get_value)
#----------------------------------------------------------------
def get_base(self):
"""Get the base the UpDown control (either 10 or 16)"""
return self.send_message(win32defines.UDM_GETBASE)
# Non PEP-8 alias
GetBase = deprecated(get_base)
#----------------------------------------------------------------
def set_base(self, base_value):
"""Get the base the UpDown control (either 10 or 16)"""
return self.send_message(win32defines.UDM_SETBASE, base_value)
# Non PEP-8 alias
SetBase = deprecated(set_base)
#----------------------------------------------------------------
def get_range(self):
"""Return the lower, upper range of the up down control"""
updown_range = self.send_message(win32defines.UDM_GETRANGE)
updown_range = (
win32functions.HiWord(updown_range),
win32functions.LoWord(updown_range)
)
return updown_range
# Non PEP-8 alias
GetRange = deprecated(get_range)
#----------------------------------------------------------------
def get_buddy_control(self):
"""Get the buddy control of the updown control"""
#from wraphandle import WrapHandle
#from HwndWrapper import WrapHandle
buddy_handle = self.send_message(win32defines.UDM_GETBUDDY)
return hwndwrapper.HwndWrapper(buddy_handle)
# Non PEP-8 alias
GetBuddyControl = deprecated(get_buddy_control)
#----------------------------------------------------------------
def set_value(self, new_pos):
"""Set the value of the of the UpDown control to some integer value"""
for _ in range(3):
result = win32structures.DWORD_PTR(0)
win32functions.SendMessageTimeout(self,
win32defines.UDM_SETPOS, 0, win32functions.MakeLong(0, new_pos),
win32defines.SMTO_NORMAL,
int(Timings.after_updownchange_wait * 1000),
ctypes.byref(result))
win32functions.WaitGuiThreadIdle(self.handle)
time.sleep(Timings.after_updownchange_wait)
if self.get_value() == new_pos:
break
# make one more attempt elsewhere
# Non PEP-8 alias
SetValue = deprecated(set_value)
#----------------------------------------------------------------
def increment(self):
"""Increment the number in the UpDown control by one"""
# hmmm - VM_SCROLL and UDN_DELTAPOS don't seem to be working for me :-(
# I will fake it for now either use click, or get_value() + 1
rect = self.client_rect()
self.click_input(coords=(rect.left + 5, rect.top + 5))
#self.set_value(self.get_value() + 1)
#win32functions.WaitGuiThreadIdle(self.handle)
#time.sleep(Timings.after_updownchange_wait)
# Non PEP-8 alias
Increment = deprecated(increment)
#----------------------------------------------------------------
def decrement(self):
"""Decrement the number in the UpDown control by one"""
rect = self.client_rect()
self.click_input(coords=(rect.left + 5, rect.bottom - 5))
#self.set_value(self.get_value() - 1)
#win32functions.WaitGuiThreadIdle(self.handle)
#time.sleep(Timings.after_updownchange_wait)
# Non PEP-8 alias
Decrement = deprecated(decrement)
#====================================================================
class TrackbarWrapper(hwndwrapper.HwndWrapper):
"""Class that wraps Windows Trackbar common control """
friendlyclassname = "Trackbar"
windowclasses = ["msctls_trackbar", ]
def get_range_min(self):
"""Get min available trackbar value"""
return self.send_message(win32defines.TBM_GETRANGEMIN)
def get_range_max(self):
"""Get max available trackbar value"""
return self.send_message(win32defines.TBM_GETRANGEMAX)
def get_position(self):
"""Get trackbar position"""
return self.send_message(win32defines.TBM_GETPOS)
def get_num_ticks(self):
"""Get trackbar num ticks"""
return self.send_message(win32defines.TBM_GETNUMTICS)
def get_channel_rect(self):
"""Get position of the bounding rectangle for a Trackbar"""
remote_mem = RemoteMemoryBlock(self)
system_rect = win32structures.RECT()
remote_mem.Write(system_rect)
self.send_message(win32defines.TBM_GETCHANNELRECT, 0, remote_mem)
remote_mem.Read(system_rect)
del remote_mem
return system_rect
def get_line_size(self):
"""Get the number of logical positions the trackbar's slider"""
return self.send_message(win32defines.TBM_GETLINESIZE)
def get_tooltips_control(self):
"""Get trackbar tooltip"""
return ToolTipsWrapper(self.send_message(win32defines.TBM_GETTOOLTIPS))
def get_page_size(self):
"""Get the number of logical positions for the trackbar's slider"""
return self.send_message(win32defines.TBM_GETPAGESIZE)
def set_range_max(self, range_max):
"""Set max available trackbar value"""
if range_max < self.get_range_min():
raise ValueError('Cannot set range max less than range min')
self.send_message(win32defines.TBM_SETRANGEMAX, True, range_max)
def set_range_min(self, range_min):
"""Set min available trackbar value"""
if range_min > self.get_range_max():
raise ValueError('Cannot set range min more than range max')
self.send_message(win32defines.TBM_SETRANGEMIN, True, range_min)
def set_position(self, pos):
"""Set trackbar position"""
if not (self.get_range_min() <= pos <= self.get_range_max()):
raise ValueError('Cannot set position out of range')
self.send_message(win32defines.TBM_SETPOS, True, pos)
def set_line_size(self, line_size):
"""Set trackbar line size"""
self.send_message(win32defines.TBM_SETLINESIZE, 0, line_size)
def set_page_size(self, page_size):
"""Set trackbar page size"""
self.send_message(win32defines.TBM_SETPAGESIZE, 0, page_size)
def set_sel(self, sel_start, sel_end):
"""Set start and end of selection"""
if not self.has_style(win32defines.TBS_ENABLESELRANGE):
raise RuntimeError('Range selection is not supported for this trackbar')
sel_start_val = win32functions.LoWord(sel_start)
sel_end_val = win32functions.HiWord(sel_end)
sel_val = win32functions.MakeLong(sel_start_val, sel_end_val)
self.send_message(win32defines.TBM_SETSAL, 0, sel_val)
def get_sel_start(self):
"""Get start of selection"""
if not self.has_style(win32defines.TBS_ENABLESELRANGE):
raise RuntimeError('Range selection is not supported for this trackbar')
return self.send_message(win32defines.TBM_GETSELSTART)
def get_sel_end(self):
"""Get end of selection"""
if not self.has_style(win32defines.TBS_ENABLESELRANGE):
raise RuntimeError('Range selection is not supported for this trackbar')
return self.send_message(win32defines.TBM_GETSELEND)
#====================================================================
class AnimationWrapper(hwndwrapper.HwndWrapper):
"""Class that wraps Windows Animation common control"""
friendlyclassname = "Animation"
windowclasses = ["SysAnimate32", ]
#====================================================================
class ComboBoxExWrapper(hwndwrapper.HwndWrapper):
"""Class that wraps Windows ComboBoxEx common control"""
friendlyclassname = "ComboBoxEx"
windowclasses = ["ComboBoxEx32", ]
has_title = False
#====================================================================
class DateTimePickerWrapper(hwndwrapper.HwndWrapper):
"""Class that wraps Windows DateTimePicker common control"""
friendlyclassname = "DateTimePicker"
windowclasses = ["SysDateTimePick32",
r"WindowsForms\d*\.SysDateTimePick32\..*", ]
has_title = False
#----------------------------------------------------------------
def get_time(self):
"""Get the currently selected time"""
remote_mem = RemoteMemoryBlock(self)
system_time = win32structures.SYSTEMTIME()
remote_mem.Write(system_time)
res = self.send_message(win32defines.DTM_GETSYSTEMTIME, 0, remote_mem)
remote_mem.Read(system_time)
del remote_mem
if res != win32defines.GDT_VALID:
raise RuntimeError('Failed to get time from Date Time Picker (result = ' + str(res) + ')')
#year = system_time.wYear
#month = system_time.wMonth
#day_of_week = system_time.wDayOfWeek
#day = system_time.wDay
#hour = system_time.wHour
#minute = system_time.wMinute
#second = system_time.wSecond
#milliseconds = system_time.wMilliseconds
#return (year, month, day_of_week, day, hour, minute, second, milliseconds)
return system_time
# Non PEP-8 alias
GetTime = deprecated(get_time)
#----------------------------------------------------------------
def set_time(self, year=0, month=0, day_of_week=0, day=0, hour=0, minute=0, second=0, milliseconds=0):
"""Set the currently selected time"""
remote_mem = RemoteMemoryBlock(self)
system_time = win32structures.SYSTEMTIME()
system_time.wYear = year
system_time.wMonth = month
system_time.wDayOfWeek = day_of_week
system_time.wDay = day
system_time.wHour = hour
system_time.wMinute = minute
system_time.wSecond = second
system_time.wMilliseconds = milliseconds
remote_mem.Write(system_time)
res = self.send_message(win32defines.DTM_SETSYSTEMTIME, win32defines.GDT_VALID, remote_mem)
del remote_mem
if res == 0:
raise RuntimeError('Failed to set time in Date Time Picker')
# Non PEP-8 alias
SetTime = deprecated(set_time)
#====================================================================
class HotkeyWrapper(hwndwrapper.HwndWrapper):
"""Class that wraps Windows Hotkey common control"""
friendlyclassname = "Hotkey"
windowclasses = ["msctls_hotkey32", ]
has_title = False
#====================================================================
class IPAddressWrapper(hwndwrapper.HwndWrapper):
"""Class that wraps Windows IPAddress common control"""
friendlyclassname = "IPAddress"
windowclasses = ["SysIPAddress32", ]
has_title = False
#====================================================================
class CalendarWrapper(hwndwrapper.HwndWrapper):
"""Class that wraps Windows Calendar common control"""
friendlyclassname = "Calendar"
windowclasses = ["SysMonthCal32", ]
has_title = False
place_in_calendar = {
'background': win32defines.MCSC_BACKGROUND,
'month_background': win32defines.MCSC_MONTHBK,
'text': win32defines.MCSC_TEXT,
'title_background': win32defines.MCSC_TITLEBK,
'title_text': win32defines.MCSC_TITLETEXT,
'trailing_text': win32defines.MCSC_TRAILINGTEXT
}
#----------------------------------------------------------------
def __init__(self, hwnd):
"""Initialise the instance"""
super(CalendarWrapper, self).__init__(hwnd)
#----------------------------------------------------------------
def get_current_date(self):
"""Get the currently selected date"""
remote_mem = RemoteMemoryBlock(self)
system_date = win32structures.SYSTEMTIME()
remote_mem.Write(system_date)
res = self.send_message(win32defines.MCM_GETCURSEL , 0, remote_mem)
remote_mem.Read(system_date)
del remote_mem
if res == 0:
raise RuntimeError('Failed to get the currently selected date in Calendar')
return system_date
#----------------------------------------------------------------
def set_current_date(self, year, month, day_of_week, day):
"""Set the currently selected date"""
remote_mem = RemoteMemoryBlock(self)
system_time = win32structures.SYSTEMTIME()
system_time.wYear = year
system_time.wMonth = month
system_time.wDayOfWeek = day_of_week
system_time.wDay = day
system_time.wHour = 0
system_time.wMinute = 0
system_time.wSecond = 0
system_time.wMilliseconds = 0
remote_mem.Write(system_time)
res = self.send_message(win32defines.MCM_SETCURSEL, win32defines.GDT_VALID, remote_mem)
del remote_mem
if res == 0:
raise RuntimeError('Failed to set the currently selected date in Calendar')
#----------------------------------------------------------------
def get_border(self):
"""Get the calendar border"""
return self.send_message(win32defines.MCM_GETCALENDARBORDER, 0, 0)
#----------------------------------------------------------------
def set_border(self, border):
"""Set the calendar border"""
self.send_message(win32defines.MCM_SETCALENDARBORDER, True, border)
#----------------------------------------------------------------
def count(self):
"""Get the calendars count"""
return self.send_message(win32defines.MCM_GETCALENDARCOUNT, 0, 0)
#----------------------------------------------------------------
def get_view(self):
"""Get the calendar view"""
return self.send_message(win32defines.MCM_GETCURRENTVIEW, 0, 0)
#----------------------------------------------------------------
def set_view(self, viewType):
"""Set the calendar view"""
res = self.send_message(win32defines.MCM_SETCURRENTVIEW, 0, viewType)
if res == 0:
raise RuntimeError('Failed to set view in Calendar')
#----------------------------------------------------------------
def set_day_states(self, month_states):
"""Sets the day states for all months that are currently visible"""
remote_mem = RemoteMemoryBlock(self)
day_states = (wintypes.DWORD * len(month_states))(*month_states)
remote_mem.Write(day_states)
res = self.send_message(win32defines.MCM_SETDAYSTATE, len(day_states), remote_mem)
del remote_mem
if res == 0:
raise RuntimeError('Failed to set the day states in Calendar')
return res
#----------------------------------------------------------------
def calc_min_rectangle(self, left, top, right, bottom):
"""Calculates the minimum size that a rectangle needs to be to fit that number of calendars"""
remote_mem = RemoteMemoryBlock(self)
minimized_rect = win32structures.RECT()
minimized_rect.left = left
minimized_rect.top = top
minimized_rect.right = right
minimized_rect.bottom = bottom
remote_mem.Write(minimized_rect)
self.send_message(win32defines.MCM_SIZERECTTOMIN, 0, remote_mem)
remote_mem.Read(minimized_rect)
del remote_mem
return minimized_rect
#----------------------------------------------------------------
def hit_test(self, x, y):
"""Determines which portion of a month calendar control is at a given point on the screen"""
remote_mem = RemoteMemoryBlock(self)
hit_test_info = win32structures.MCHITTESTINFO()
point = win32structures.POINT()
point.x = x
point.y = y
hit_test_info.pt = point
hit_test_info.cbSize = ctypes.sizeof(hit_test_info)
remote_mem.Write(hit_test_info)
res = self.send_message(win32defines.MCM_HITTEST, 0, remote_mem)
del remote_mem
return res
# ----------------------------------------------------------------
def set_id(self, ID):
"""
Set the calendar type.
Receive only one parameter, which takes variants below:
'gregorian', 'gregorian_us', 'japan', 'taiwan', 'korea',
'hijri', 'thai', 'hebrew', 'gregorian_me_french',
'gregorian_arabic', 'gregorian_english_xlit',
'gregorian_french_xlit', 'umalqura'
"""
dict_types = {
'gregorian': win32defines.CAL_GREGORIAN,
'gregorian_us': win32defines.CAL_GREGORIAN_US,
'japan': win32defines.CAL_JAPAN,
'taiwan': win32defines.CAL_TAIWAN,
'korea': win32defines.CAL_KOREA,
'hijri': win32defines.CAL_HIJRI,
'thai': win32defines.CAL_THAI,
'hebrew': win32defines.CAL_HEBREW,
'gregorian_me_french': win32defines.CAL_GREGORIAN_ME_FRENCH,
'gregorian_arabic': win32defines.CAL_GREGORIAN_ARABIC,
'gregorian_english_xlit': win32defines.CAL_GREGORIAN_XLIT_ENGLISH,
'gregorian_french_xlit': win32defines.CAL_GREGORIAN_XLIT_FRENCH,
'umalqura': win32defines.CAL_UMALQURA
}
if ID in dict_types:
self.send_message(win32defines.MCM_SETCALID, dict_types[ID], 0)
else:
raise ValueError('Incorrect calendar ID (use one of {0})'.format(dict_types.keys()))
# ----------------------------------------------------------------
def get_id(self):
"""Get type of calendar"""
return self.send_message(win32defines.MCM_GETCALID, 0, 0)
# ----------------------------------------------------------------
def set_color(self, place_of_color, red, green, blue):
"""
Set some color in some place of calendar which you specify.
Receive four parameters:
- The first parameter may take few variants below:
'background', 'month_background', 'text', 'title_background',
'title_text', 'trailing_text' ;
- All other parameters should be integer from 0 to 255.
"""
if not (0 <= red <= 255):
raise RuntimeError('Incorrect range of red color, must be from 0 to 255')
if not (0 <= green <= 255):
raise RuntimeError('Incorrect range of green color, must be from 0 to 255')
if not (0 <= blue <= 255):
raise RuntimeError('Incorrect range of blue color, must be from 0 to 255')
color = (red << 16) | (green << 8) | blue
if place_of_color in self.place_in_calendar:
result = self.send_message(win32defines.MCM_SETCOLOR, self.place_in_calendar[place_of_color], color)
else:
raise ValueError('Incorrect calendar place ID (use one of {0})'.format(self.place_in_calendar.keys()))
if result == -1:
raise RuntimeError('Incorrect color')
return result
# ----------------------------------------------------------------
#TODO create method get_color in future
'''
def get_color(self, place_of_color):
"""
Return color of place in calendar, which you specify.
Receive only one parameter, which takes variants below:
'background', 'month_background', 'text', 'title_background', 'title_text', 'trailing_text'
"""
if place_of_color in self.place_in_calendar:
return self.send_message(win32defines.MCM_GETCOLOR, self.place_in_calendar[place_of_color], 0)
else:
raise ValueError('Incorrect calendar place ID (use one of {0})'.format(self.place_in_calendar.keys()))
'''
def set_today(self, year, month, day):
"""Set today date"""
remote_mem = RemoteMemoryBlock(self)
system_time = win32structures.SYSTEMTIME()
system_time.wYear = year
system_time.wMonth = month
system_time.wDay = day
system_time.wHour = 0
system_time.wMinute = 0
system_time.wSecond = 0
system_time.wMilliseconds = 0
remote_mem.Write(system_time)
res = self.send_message(win32defines.MCM_SETTODAY, 0, remote_mem)
del remote_mem
if res == 0:
raise RuntimeError('Failed to set today date in Calendar')
# ----------------------------------------------------------------
def get_today(self):
"""Get today date"""
remote_mem = RemoteMemoryBlock(self)
system_date = win32structures.SYSTEMTIME()
remote_mem.Write(system_date)
res = self.send_message(win32defines.MCM_GETTODAY, 0, remote_mem)
remote_mem.Read(system_date)
del remote_mem
if res == 0:
raise RuntimeError('Failed to get today date in Calendar')
return system_date
# ----------------------------------------------------------------
def set_first_weekday(self, dayNum):
"""Set first day of the week"""
self.send_message(win32defines.MCM_SETFIRSTDAYOFWEEK, 0, dayNum)
# ----------------------------------------------------------------
def get_first_weekday(self):
"""Get is not in current locale and if so first day of the week"""
res = self.send_message(win32defines.MCM_GETFIRSTDAYOFWEEK, 0, 0)
return (win32functions.HiWord(res), win32functions.LoWord(res))
# ----------------------------------------------------------------
def get_month_delta(self):
"""Retrieves the scroll rate for a month calendar control"""
return self.send_message(win32defines.MCM_GETMONTHDELTA, 0, 0)
# ----------------------------------------------------------------
def set_month_delta(self, delta):
"""Sets the scroll rate for a month calendar control."""
if (delta < 0):
raise ValueError("Month delta must be greater than 0")
self.send_message(win32defines.MCM_SETMONTHDELTA, delta, 0)
# ----------------------------------------------------------------
def get_month_range(self, scope_of_range):
"""Retrieves date information that represents the high and low limits of a month calendar control's display."""
if scope_of_range not in [win32defines.GMR_DAYSTATE, win32defines.GMR_VISIBLE]:
raise ValueError("scope_of_range value must be one of the following: GMR_DAYSTATE or GMR_VISIBLE")
remote_mem = RemoteMemoryBlock(self)
system_date_arr = (win32structures.SYSTEMTIME * 2)()
system_date_arr[0] = win32structures.SYSTEMTIME()
system_date_arr[1] = win32structures.SYSTEMTIME()
remote_mem.Write(system_date_arr)
res = self.send_message(win32defines.MCM_GETMONTHRANGE, scope_of_range, remote_mem)
remote_mem.Read(system_date_arr)
del remote_mem
return (res, system_date_arr)
#====================================================================
class PagerWrapper(hwndwrapper.HwndWrapper):
"""Class that wraps Windows Pager common control"""
friendlyclassname = "Pager"
windowclasses = ["SysPager", ]
#----------------------------------------------------------------
def get_position(self):
"""Return the current position of the pager"""
self._ensure_enough_privileges('PGM_GETPOS')
return self.send_message(win32defines.PGM_GETPOS)
# Non PEP-8 alias
GetPosition = deprecated(get_position)
#----------------------------------------------------------------
def set_position(self, pos):
"""Set the current position of the pager"""
self._ensure_enough_privileges('PGM_SETPOS')
return self.send_message(win32defines.PGM_SETPOS, pos)
# Non PEP-8 alias
SetPosition = deprecated(set_position)
#====================================================================
class ProgressWrapper(hwndwrapper.HwndWrapper):
"""Class that wraps Windows Progress common control"""
friendlyclassname = "Progress"
windowclasses = ["msctls_progress", "msctls_progress32", ]
has_title = False
#----------------------------------------------------------------
def get_position(self):
"""Return the current position of the progress bar"""
self._ensure_enough_privileges('PBM_GETPOS')
return self.send_message(win32defines.PBM_GETPOS)
# Non PEP-8 alias
GetPosition = deprecated(get_position)
#----------------------------------------------------------------
def set_position(self, pos):
"""Set the current position of the progress bar"""
self._ensure_enough_privileges('PBM_SETPOS')
return self.send_message(win32defines.PBM_SETPOS, pos)
# Non PEP-8 alias
SetPosition = deprecated(set_position)
#----------------------------------------------------------------
def get_state(self):
"""Get the state of the progress bar
State will be one of the following constants:
* PBST_NORMAL
* PBST_ERROR
* PBST_PAUSED
"""
self._ensure_enough_privileges('PBM_GETSTATE')
return self.send_message(win32defines.PBM_GETSTATE)
# Non PEP-8 alias
GetState = deprecated(get_state)
#----------------------------------------------------------------
def get_step(self):
"""Get the step size of the progress bar"""
self._ensure_enough_privileges('PBM_GETSTEP')
return self.send_message(win32defines.PBM_GETSTEP)
# Non PEP-8 alias
GetStep = deprecated(get_step)
#----------------------------------------------------------------
def step_it(self):
"""Move the progress bar one step size forward"""
self._ensure_enough_privileges('PBM_STEPIT')
return self.send_message(win32defines.PBM_STEPIT)
# Non PEP-8 alias
StepIt = deprecated(step_it)
#
##
###hwndwrapper._HwndWrappers["ComboBoxEx32"] = ComboBoxEx
##
###====================================================================
##class ComboBoxEx(Controls_Standard.ComboBox):
## #----------------------------------------------------------------
## def __init__(self, hwndOrXML):
# Window.__init__(self, hwndOrXML)
##
# if isinstance(hwndOrXML, (int, long)):
## comboCntrl = send_message(
## hwndOrXML,
## CBEM_GETCOMBOCONTROL,
## 0,
## 0)
##
## print "--"*20, comboCntrl
## Controls_Standard.ComboBox.__init__(self, comboCntrl)
## print self.dropped_rect
##
##
##
## droppedRect = win32structures.RECT()
##
## send_message(
## self,
## CB_GETDROPPEDCONTROLRECT,
## 0,
## ctypes.byref(droppedRect))
##
## props['dropped_rect'] = droppedRect
#
#
#
#
#
#
# # find out how many text items are in the combobox
# numItems = send_message(
# self,
# CB_GETCOUNT,
# 0,
# 0)
#
# print "*"*20, numItems
## remote_mem = RemoteMemoryBlock(self)
##
##
## # get the text for each item in the combobox
## while True:
## item = COMBOBOXEXITEMW()
##
## item.mask = CBEIF_TEXT
## item.cchTextMax = 4000
## item.pszText = remote_mem.Address() + ctypes.sizeof(item) + 1
##
## remote_mem.Write(item)
##
## retval = send_message (
## self,
## CBEM_GETITEMW,
## 0,
## remote_mem
## )
##
## if retval:
## item = remote_mem.Read(item)
##
## # Read the remote text string
## charData = ctypes.create_unicode_buffer(4000)
## remote_mem.Read(charData, item.pszText)
## self.Titles.append(charData.value)
## else:
## break
##
#
# else:
#
# # get the dropped Rect form
# droppedRect = XMLToRect(hwndOrXML.find("DROPPEDRECT"))
# props['dropped_rect'] = droppedRect