# 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. """Wrap""" from .win32structures import RECT, LOGFONTW from . import deprecated #==================================================================== class FuncWrapper(object): """Little class to allow attribute access to return a callable object""" def __init__(self, value): self.value = value def __call__(self, *args, **kwargs): """Return the saved value""" return self.value #==================================================================== class ControlProps(dict): """Wrap controls read from a file to resemble hwnd controls""" def __init__(self, *args, **kwargs): dict.__init__(self, *args, **kwargs) self.ref = None #self.menu_items = [] def __getattr__(self, attr): # if the key is not in the dictionary but the plural is if attr not in self and attr + "s" in self: # return the first element of the possible list item return FuncWrapper(self[attr+'s'][0]) return FuncWrapper(self[attr]) #def friendly_class_name(self): # print "sdafafasdfafasdfasdf", # try: # print "---", self['friendly_class_name'] # except Exception as e: # print "fffffffffffffffffffff" # print `e` # return self['friendly_class_name'] def window_text(self): return self['texts'][0] # Non PEP-8 alias WindowText = deprecated(window_text) def has_style(self, style): return self['style'] & style == style # Non PEP-8 alias HasStyle = deprecated(has_style) def has_exstyle(self, exstyle): return self['exstyle'] & exstyle == exstyle # Non PEP-8 alias HasExStyle = deprecated(has_exstyle, deprecated_name="HasExStyle") #==================================================================== def GetMenuBlocks(ctrls): allMenuBlocks = [] for ctrl in ctrls: if 'menu_items' in ctrl.keys(): # we need to get all the separate menu blocks! menuBlocks = MenuBlockAsControls(ctrl.menu_items()) allMenuBlocks.extend(menuBlocks) return allMenuBlocks #==================================================================== def MenuBlockAsControls(menuItems, parentage = None): if parentage is None: parentage = [] blocks = [] curBlock = [] for item in menuItems: # do a bit of conversion first :-) itemAsCtrl = MenuItemAsControl(item) # update the friendly_class_name to contain the 'path' to # this particular item # TODO: CHECK - as itemPath is currently unused! if parentage: itemPath = "%s->%s" % ("->".join(parentage), item['text']) else: itemPath = item['text'] #append the item to the current menu block curBlock.append(itemAsCtrl) # If the item has a sub menu if 'menu_items' in item.keys(): # add the current item the path parentage.append(item['text']) # Get the block for the SubMenu, and add it to the list of # blocks we have found blocks.extend( MenuBlockAsControls( item['menu_items']['menu_items'], parentage)) # and seeing as we are dong with that sub menu remove the current # item from the path del(parentage[-1]) # add the current block to the list of blocks blocks.append(curBlock) return blocks #==================================================================== def MenuItemAsControl(menuItem): """Make a menu item look like a control for tests""" itemAsCtrl = ControlProps() itemAsCtrl["texts"] = [menuItem['text'], ] itemAsCtrl["control_id"] = menuItem['id'] itemAsCtrl["type"] = menuItem['type'] itemAsCtrl["state"] = menuItem['state'] itemAsCtrl["class_name"] = "MenuItem" itemAsCtrl["friendly_class_name"] = "MenuItem" # as most of these don't matter - just set them up with default stuff itemAsCtrl["rectangle"] = RECT(0, 0, 999, 999) itemAsCtrl["fonts"] = [LOGFONTW(), ] itemAsCtrl["client_rects"] = [RECT(0, 0, 999, 999), ] itemAsCtrl["context_help_id"] = 0 itemAsCtrl["user_data"] = 0 itemAsCtrl["style"] = 0 itemAsCtrl["exstyle"] = 0 itemAsCtrl["is_visible"] = 1 return itemAsCtrl #==================================================================== def SetReferenceControls(controls, refControls): """Set the reference controls for the controls passed in This does some minor checking as following: * test that there are the same number of reference controls as controls - fails with an exception if there are not * test if all the ID's are the same or not """ # numbers of controls must be the same (though in future I could imagine # relaxing this constraint) if len(controls) != len(refControls): raise RuntimeError( "Numbers of controls on ref. dialog does not match Loc. dialog") # set the controls for i, ctrl in enumerate(controls): ctrl.ref = refControls[i] toRet = 1 allIDsSameFlag = 2 allClassesSameFlag = 4 # find if all the control id's match if [ctrl.control_id() for ctrl in controls] == \ [ctrl.control_id() for ctrl in refControls]: toRet += allIDsSameFlag # check if the control classes match if [ctrl.class_name() for ctrl in controls] == \ [ctrl.class_name() for ctrl in refControls]: toRet += allClassesSameFlag return toRet ##==================================================================== #class ControlProps(dict): # #---------------------------------------------------------------- # def __init__(self, props = {}): # # default to having menuItems for all things # self.menu_items = [] # # self.update(props) # #for x in props: # #self[x] = props[x] # # if hasattr(props, "handle"): # self.__dict__['handle'] = props.handle # else: # self.__dict__['handle'] = None # # self.__dict__['ref'] = None # # #---------------------------------------------------------------- # # handles attribute access for dictionary items and # # for plurals (e.g. if self.fonts = [4, 2] then self.font = 4) # def __getattr__(self, key): # # # if the key is not in the dictionary but the plural is # if key not in self and key + "s" in self: # # # try to get the first element of the possible list item # try: # return self[key + "s"][0] # except TypeError as e: # pass # # if key in self: # return self[key] # # return self.__dict__[key] # # #---------------------------------------------------------------- # def __setattr__(self, key, value): # if key in self.__dict__: # self.__dict__[key] = value # else: # self[key] = value # # #---------------------------------------------------------------- # def has_style(self, flag): # return self.style & flag == flag # # #---------------------------------------------------------------- # def has_exstyle(self, flag): # return self.exstyle & flag == flag # #