/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
* This file is part of the LibreOffice project.
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
#include <config_folders.h>
#include <vcl/uitest/logger.hxx>
#include <rtl/bootstrap.hxx>
#include <rtl/ustrbuf.hxx>
#include <osl/file.hxx>
#include <vcl/ctrl.hxx>
#include <vcl/event.hxx>
#include <vcl/uitest/uiobject.hxx>
#include <vcl/uitest/eventdescription.hxx>
#include <svdata.hxx>
#include <com/sun/star/beans/PropertyValue.hpp>
#include <memory>
namespace
{
bool isDialogWindow(vcl::Window
const * pWindow)
{
WindowType eType = pWindow->GetType();
if (eType == WindowType::DIALOG || eType == WindowType::MODELESSDIALOG)
return true ;
// MESSBOX, INFOBOX, WARNINGBOX, ERRORBOX, QUERYBOX
if (eType >= WindowType::MESSBOX && eType <= WindowType::QUERYBOX)
return true ;
if (eType == WindowType::TABDIALOG)
return true ;
return false ;
}
bool isTopWindow(vcl::Window
const * pWindow)
{
WindowType eType = pWindow->GetType();
if (eType == WindowType::FLOATINGWINDOW)
{
return pWindow->GetStyle() & WB_SYSTEMFLOATWIN;
}
return false ;
}
vcl::Window* get_top_parent(vcl::Window* pWindow)
{
if (isDialogWindow(pWindow) || isTopWindow(pWindow))
return pWindow;
vcl::Window* pParent = pWindow->GetParent();
if (!pParent)
return pWindow;
return get_top_parent(pParent);
}
}
UITestLogger::UITestLogger()
: mbValid(
false )
{
static const char * pFile = std::getenv(
"LO_COLLECT_UIINFO" );
if (pFile)
{
OUString aDirPath(u
"${$BRAND_BASE_DIR/" LIBO_ETC_FOLDER
"/" SAL_CONFIGFILE(
"bootstrap" )
":UserInstallation}/uitest/" _ustr);
rtl::Bootstrap::expandMacros(aDirPath);
osl::Directory::createPath(aDirPath);
OUString aFilePath = aDirPath + OUString::fromUtf8(pFile);
maStream.Open(aFilePath, StreamMode::READWRITE | StreamMode::TRUNC);
mbValid =
true ;
}
}
namespace
{
// most likely this should be recursive
bool child_windows_have_focus(VclPtr<vcl::Window>
const & xUIElement)
{
sal_Int32 nCount = xUIElement->GetChildCount();
for (sal_Int32 i = 0; i < nCount; ++i)
{
vcl::Window* pChild = xUIElement->GetChild(i);
if (pChild->HasFocus())
{
return true ;
}
if (child_windows_have_focus(VclPtr<vcl::Window>(pChild)))
return true ;
}
return false ;
}
}
void UITestLogger::logAction(VclPtr<Control>
const & xUIElement, VclEventId nEvent)
{
if (!mbValid)
return ;
if (xUIElement->get_id().isEmpty())
return ;
std::unique_ptr<UIObject> pUIObject = xUIElement->GetUITestFactory()(xUIElement.get())
;
OUString aAction = pUIObject->get_action(nEvent);
if (!xUIElement->HasFocus() && !child_windows_have_focus(xUIElement))
{
return ;
}
if (!aAction.isEmpty())
maStream.WriteLine(OUStringToOString(aAction, RTL_TEXTENCODING_UTF8));
}
void UITestLogger::logAction(vcl::Window* const & xUIWin, VclEventId nEvent)
{
if (!mbValid)
return ;
if (xUIWin->get_id().isEmpty())
return ;
std::unique_ptr<UIObject> pUIObject = xUIWin->GetUITestFactory()(xUIWin);
OUString aAction = pUIObject->get_action(nEvent);
if (!aAction.isEmpty())
maStream.WriteLine(OUStringToOString(aAction, RTL_TEXTENCODING_UTF8));
}
void UITestLogger::log(std::u16string_view rString)
{
if (!mbValid)
return ;
if (rString.empty())
return ;
maStream.WriteLine(OUStringToOString(rString, RTL_TEXTENCODING_UTF8));
}
void UITestLogger::logKeyInput(VclPtr<vcl::Window> const & xUIElement, const KeyEvent& rEvent)
{
if (!mbValid)
return ;
//We need to check for Parent's ID in case the UI Element is SubEdit of Combobox/SpinField
const OUString& rID
= xUIElement->get_id().isEmpty() ? xUIElement->GetParent()->get_id() : xUIElement->get_id();
if (rID.isEmpty())
return ;
sal_Unicode nChar = rEvent.GetCharCode();
sal_uInt16 nKeyCode = rEvent.GetKeyCode().GetCode();
bool bShift = rEvent.GetKeyCode().IsShift();
bool bMod1 = rEvent.GetKeyCode().IsMod1();
bool bMod2 = rEvent.GetKeyCode().IsMod2();
bool bMod3 = rEvent.GetKeyCode().IsMod3();
std::map<OUString, sal_uInt16> aKeyMap
= { { "ESC" , KEY_ESCAPE }, { "TAB" , KEY_TAB }, { "DOWN" , KEY_DOWN },
{ "UP" , KEY_UP }, { "LEFT" , KEY_LEFT }, { "RIGHT" , KEY_RIGHT },
{ "DELETE" , KEY_DELETE }, { "INSERT" , KEY_INSERT }, { "BACKSPACE" , KEY_BACKSPACE },
{ "RETURN" , KEY_RETURN }, { "HOME" , KEY_HOME }, { "END" , KEY_END },
{ "PAGEUP" , KEY_PAGEUP }, { "PAGEDOWN" , KEY_PAGEDOWN } };
OUString aFound;
for (const auto & itr : aKeyMap)
{
if (itr.second == nKeyCode)
{
aFound = itr.first;
break ;
}
}
OUString aKeyCode;
if (!aFound.isEmpty() || bShift || bMod1 || bMod2 || bMod3)
{
aKeyCode = "{\" KEYCODE\": \" ";
if (bShift)
aKeyCode += "SHIFT+" ;
if (bMod1)
aKeyCode += "CTRL+" ;
if (bMod2)
aKeyCode += "ALT+" ;
if (aFound.isEmpty())
aKeyCode += OUStringChar(nChar) + "\" }";
else
aKeyCode += aFound + "\" }";
}
else
{
aKeyCode = "{\" TEXT\": \" " + OUStringChar(nChar) + " \"}" ;
}
std::unique_ptr<UIObject> pUIObject = xUIElement->GetUITestFactory()(xUIElement.get());
VclPtr<vcl::Window> pParent = xUIElement->GetParent();
while (pParent && !pParent->IsTopWindow())
{
pParent = pParent->GetParent();
}
OUString aParentID = pParent ? pParent->get_id() : OUString();
OUString aContent;
if (pUIObject->get_type() == "EditUIObject" )
{
if (aParentID.isEmpty())
{
VclPtr<vcl::Window> pParent_top = get_top_parent(xUIElement);
aParentID = pParent_top->get_id();
}
if (aParentID.isEmpty())
{
aContent += "Type on '" + rID + "' " + aKeyCode;
}
else
{
aContent += "Type on '" + rID + "' " + aKeyCode + " from " + aParentID;
}
}
else if (pUIObject->get_type() == "SwEditWinUIObject" && rID == "writer_edit" )
{
aContent = "Type on writer " + aKeyCode;
}
else if (pUIObject->get_type() == "ScGridWinUIObject" && rID == "grid_window" )
{
aContent = "Type on current cell " + aKeyCode;
}
else if (pUIObject->get_type() == "ImpressWindowUIObject" && rID == "impress_win" )
{
aContent = "Type on impress " + aKeyCode;
}
else if (pUIObject->get_type() == "WindowUIObject" && rID == "math_edit" )
{
aContent = "Type on math " + aKeyCode;
}
else if (rID == "draw_win" )
{
aContent = "Type on draw " + aKeyCode;
}
else
{
if (aParentID.isEmpty())
{
VclPtr<vcl::Window> pParent_top = get_top_parent(xUIElement);
aParentID = pParent_top->get_id();
}
if (aParentID.isEmpty())
{
aContent = "Type on '" + rID + "' " + aKeyCode;
}
else
{
aContent = "Type on '" + rID + "' " + aKeyCode + " from " + aParentID;
}
}
maStream.WriteLine(OUStringToOString(aContent, RTL_TEXTENCODING_UTF8));
}
namespace
{
OUString StringMapToOUString(const std::map<OUString, OUString>& rParameters)
{
if (rParameters.empty())
return u"" _ustr;
OUStringBuffer aParameterString(static_cast <int >(rParameters.size() * 32));
aParameterString.append(" {" );
for (std::map<OUString, OUString>::const_iterator itr = rParameters.begin();
itr != rParameters.end(); ++itr)
{
if (itr != rParameters.begin())
aParameterString.append(", " );
aParameterString.append("\" " + itr->first + " \": \" " + itr->second + " \"" );
}
aParameterString.append("}" );
return aParameterString.makeStringAndClear();
}
const OUString& GetValueInMapWithIndex(const std::map<OUString, OUString>& rParameters,
sal_Int32 index)
{
sal_Int32 j = 0;
std::map<OUString, OUString>::const_iterator itr = rParameters.begin();
for (; itr != rParameters.end() && j < index; ++itr, ++j)
;
assert(itr != rParameters.end());
return itr->second;
}
const OUString& GetKeyInMapWithIndex(const std::map<OUString, OUString>& rParameters,
sal_Int32 index)
{
sal_Int32 j = 0;
std::map<OUString, OUString>::const_iterator itr = rParameters.begin();
for (; itr != rParameters.end() && j < index; ++itr, ++j)
;
assert(itr != rParameters.end());
return itr->first;
}
}
void UITestLogger::logEvent(const EventDescription& rDescription)
{
OUString aParameterString = StringMapToOUString(rDescription.aParameters);
//here we will customize our statements depending on the caller of this function
OUString aLogLine;
//first check on general commands
if (rDescription.aAction == "SET" )
{
aLogLine = "Set Zoom to " + GetValueInMapWithIndex(rDescription.aParameters, 0);
}
else if (rDescription.aAction == "SIDEBAR" )
{
aLogLine = "From SIDEBAR Choose " + aParameterString;
}
else if (rDescription.aKeyWord == "ValueSet" )
{
aLogLine = "Choose element with position "
+ GetValueInMapWithIndex(rDescription.aParameters, 0) + " in '"
+ rDescription.aID + "' from '" + rDescription.aParent + "'" ;
}
else if (rDescription.aAction == "SELECT" && rDescription.aID.isEmpty())
{
aLogLine = "Select " + aParameterString;
}
else if (rDescription.aID == "writer_edit" )
{
if (rDescription.aAction == "GOTO" )
{
aLogLine = "GOTO page number " + GetValueInMapWithIndex(rDescription.aParameters, 0);
}
else if (rDescription.aAction == "SELECT" )
{
OUString to = GetValueInMapWithIndex(rDescription.aParameters, 0);
OUString from = GetValueInMapWithIndex(rDescription.aParameters, 1);
aLogLine = "Select from Pos " + from + " to Pos " + to;
}
else if (rDescription.aAction == "CREATE_TABLE" )
{
OUString size = GetValueInMapWithIndex(rDescription.aParameters, 0);
aLogLine = "Create Table with " + size;
;
}
else if (rDescription.aAction == "COPY" )
{
aLogLine = "Copy the Selected Text" ;
}
else if (rDescription.aAction == "CUT" )
{
aLogLine = "Cut the Selected Text" ;
}
else if (rDescription.aAction == "PASTE" )
{
aLogLine = "Paste in the Current Cursor Location" ;
}
else if (rDescription.aAction == "BREAK_PAGE" )
{
aLogLine = "Insert Break Page" ;
}
}
else if (rDescription.aID == "grid_window" )
{
if (rDescription.aAction == "SELECT" )
{
OUString type = GetKeyInMapWithIndex(rDescription.aParameters, 0);
if (type == "CELL" || type == "RANGE" )
{
aLogLine = "Select from calc" + aParameterString;
}
else if (type == "TABLE" )
{
aLogLine = "Switch to sheet number "
+ GetValueInMapWithIndex(rDescription.aParameters, 0);
}
}
else if (rDescription.aAction == "LAUNCH" )
{
aLogLine = "Launch" + GetKeyInMapWithIndex(rDescription.aParameters, 2) + " from Col "
+ GetValueInMapWithIndex(rDescription.aParameters, 2) + " and Row "
+ GetValueInMapWithIndex(rDescription.aParameters, 1);
}
else if (rDescription.aAction == "DELETE_CONTENT" )
{
aLogLine = "Remove Content from This " + aParameterString;
}
else if (rDescription.aAction == "DELETE_CELLS" )
{
aLogLine = "Delete The Cells in" + aParameterString;
}
else if (rDescription.aAction == "INSERT_CELLS" )
{
aLogLine = "Insert Cell around the " + aParameterString;
}
else if (rDescription.aAction == "CUT" )
{
aLogLine = "CUT the selected " + aParameterString;
}
else if (rDescription.aAction == "COPY" )
{
aLogLine = "COPY the selected " + aParameterString;
}
else if (rDescription.aAction == "PASTE" )
{
aLogLine = "Paste in the " + aParameterString;
}
else if (rDescription.aAction == "MERGE_CELLS" )
{
aLogLine = "Merge " + aParameterString;
}
else if (rDescription.aAction == "UNMERGE_CELL" )
{
aLogLine = "Delete the merged " + aParameterString;
}
else if (rDescription.aAction == "Rename_Sheet" )
{
aLogLine = "Rename The Selected Tab to \" "
+ GetValueInMapWithIndex(rDescription.aParameters, 0) + "\" ";
}
else if (rDescription.aAction == "InsertTab" )
{
aLogLine = "Insert New Tab " ;
}
else if (rDescription.aAction == "COMMENT" )
{
OUString type = GetKeyInMapWithIndex(rDescription.aParameters, 0);
if (type == "OPEN" )
{
aLogLine = "Open Comment" ;
}
else if (type == "CLOSE" )
{
aLogLine = "Close Comment" ;
}
}
}
else if (rDescription.aID == "impress_win_or_draw_win" )
{
if (rDescription.aAction == "Insert_New_Page_or_Slide" )
{
if (UITestLogger::getInstance().getAppName() == "impress" )
{
aLogLine = "Insert New Slide at Position "
+ GetValueInMapWithIndex(rDescription.aParameters, 0);
}
else if (UITestLogger::getInstance().getAppName() == "draw" )
{
aLogLine = "Insert New Page at Position "
+ GetValueInMapWithIndex(rDescription.aParameters, 0);
}
}
else if (rDescription.aAction == "Delete_Slide_or_Page" )
{
if (UITestLogger::getInstance().getAppName() == "impress" )
{
aLogLine
= "Delete Slide number " + GetValueInMapWithIndex(rDescription.aParameters, 0);
}
else if (UITestLogger::getInstance().getAppName() == "draw" )
{
aLogLine
= "Delete Page number " + GetValueInMapWithIndex(rDescription.aParameters, 0);
}
}
else if (rDescription.aAction == "Duplicate" )
{
aLogLine = "Duplicate The Selected Slide " ;
}
else if (rDescription.aAction == "RENAME" )
{
if (UITestLogger::getInstance().getAppName() == "impress" )
{
aLogLine = "Rename The Selected Slide from \" "
+ GetValueInMapWithIndex(rDescription.aParameters, 1) + "\" to \""
+ GetValueInMapWithIndex(rDescription.aParameters, 0) + "\" ";
}
else if (UITestLogger::getInstance().getAppName() == "draw" )
{
aLogLine = "Rename The Selected Page from \" "
+ GetValueInMapWithIndex(rDescription.aParameters, 1) + "\" to \""
+ GetValueInMapWithIndex(rDescription.aParameters, 0) + "\" ";
}
}
}
else if (rDescription.aKeyWord == "SwEditWinUIObject" )
{
if (rDescription.aAction == "LEAVE" )
{
aLogLine = "Leave '" + rDescription.aID + "'" ;
}
else if (rDescription.aAction == "SHOW" )
{
aLogLine = "Show '" + rDescription.aID + "'" ;
}
else if (rDescription.aAction == "HIDE" )
{
aLogLine = "Hide '" + rDescription.aID + "'" ;
}
else if (rDescription.aAction == "DELETE" )
{
aLogLine = "Delete '" + rDescription.aID + "'" ;
}
else if (rDescription.aAction == "SETRESOLVED" )
{
aLogLine = "Resolve '" + rDescription.aID + "'" ;
}
}
else if (rDescription.aParent == "element_selector" )
{
aLogLine = "Select element no " + rDescription.aID + " From " + rDescription.aParent;
}
else if (rDescription.aKeyWord == "MenuButton" )
{
if (rDescription.aAction == "OPENLIST" )
{
aLogLine = "Open List From " + rDescription.aID;
}
else if (rDescription.aAction == "CLOSELIST" )
{
aLogLine = "Close List From " + rDescription.aID;
}
else if (rDescription.aAction == "OPENFROMLIST" )
{
aLogLine = "Select item no " + GetValueInMapWithIndex(rDescription.aParameters, 0)
+ " From List of " + rDescription.aID;
}
}
else if (rDescription.aKeyWord == "VerticalTab" )
{
aLogLine = "Choose Tab number " + GetValueInMapWithIndex(rDescription.aParameters, 0)
+ " in '" + rDescription.aID + "'" ;
}
else
{
aLogLine = rDescription.aKeyWord + " Action:" + rDescription.aAction + " Id:"
+ rDescription.aID + " Parent:" + rDescription.aParent + aParameterString;
}
log(aLogLine);
}
UITestLogger& UITestLogger::getInstance()
{
ImplSVData* const pSVData = ImplGetSVData();
assert(pSVData);
if (!pSVData->maFrameData.m_pUITestLogger)
{
pSVData->maFrameData.m_pUITestLogger.reset(new UITestLogger);
}
return *pSVData->maFrameData.m_pUITestLogger;
}
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
Messung V0.5 C=92 H=97 G=94
¤ Dauer der Verarbeitung: 0.3 Sekunden
(vorverarbeitet)
¤
*© Formatika GbR, Deutschland