LibreOffice Module test (master) 1
screenshot_test.cxx
Go to the documentation of this file.
1/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2/*
3 * This file is part of the LibreOffice project.
4 *
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 */
9
10#include <sal/config.h>
11
12#include <iostream>
13
15
16#include <com/sun/star/frame/Desktop.hpp>
18#include <vcl/abstdlg.hxx>
20#include <vcl/svapp.hxx>
21#include <vcl/virdev.hxx>
22#include <vcl/weld.hxx>
23#include <tools/stream.hxx>
24
25
26namespace {
27 void splitHelpId( const OUString& rHelpId, OUString& rDirname, OUString &rBasename )
28 {
29 sal_Int32 nIndex = rHelpId.lastIndexOf( '/' );
30
31 if( nIndex > 0 )
32 rDirname = rHelpId.subView( 0, nIndex );
33
34 if( rHelpId.getLength() > nIndex+1 )
35 rBasename = rHelpId.subView( nIndex+1 );
36 }
37}
38
39using namespace css;
40using namespace css::uno;
41
43constexpr OUStringLiteral g_aScreenshotDirectory(u"screenshots");
44
46 : maParent(nullptr, "vcl/ui/screenshotparent.ui", "ScreenShot")
47 , mxParentWidget(maParent.getDialog()->weld_content_area())
48{
49 if (auto const env = getenv("LO_TEST_LOCALE")) {
50 maCurrentLanguage = OUString::fromUtf8(env);
51 }
52}
53
55{
56}
57
59{
61
62 mxDesktop = css::frame::Desktop::create( comphelper::getComponentContext(getMultiServiceFactory()) );
63 CPPUNIT_ASSERT_MESSAGE("no desktop!", mxDesktop.is());
64
65 osl::Directory::create( m_directories.getURLFromWorkdir( g_aScreenshotDirectory)) ;
66
67 // initialize maKnownDialogs
68 if (maKnownDialogs.empty())
69 {
71 }
72}
73
74void ScreenshotTest::implSaveScreenshot(const BitmapEx& rScreenshot, const OUString& rScreenshotId)
75{
76 OUString aDirname, aBasename;
77 splitHelpId(rScreenshotId, aDirname, aBasename);
78 aDirname = g_aScreenshotDirectory + "/" + aDirname +
79 ( (maCurrentLanguage == "en-US") ? OUString() : "/" + maCurrentLanguage );
80
81 auto const dirUrl = m_directories.getURLFromWorkdir(aDirname);
82 auto const e = osl::Directory::createPath(dirUrl);
83 if (e != osl::FileBase::E_EXIST) {
84 CPPUNIT_ASSERT_EQUAL_MESSAGE(
85 OString("Failed to create " + OUStringToOString(dirUrl, RTL_TEXTENCODING_UTF8))
86 .getStr(),
87 osl::FileBase::E_None, e);
88 }
89
90 auto const pngUrl = OUString(dirUrl + "/" + aBasename + ".png");
91 SvFileStream aNew(pngUrl, StreamMode::WRITE | StreamMode::TRUNC);
92 CPPUNIT_ASSERT_MESSAGE(OString("Failed to open <" + OUStringToOString(pngUrl, RTL_TEXTENCODING_UTF8) + ">: " + OString::number(sal_uInt32(aNew.GetErrorCode()))).getStr(), aNew.IsOpen());
93
94 std::cout << "saving " << pngUrl << ":\n";
95 vcl::PngImageWriter aPNGWriter(aNew);
96 aPNGWriter.write(rScreenshot);
97}
98
100{
101 const BitmapEx aScreenshot(rDialog.createScreenshot());
102
103 if (!aScreenshot.IsEmpty())
104 {
105 const OUString aScreenshotId = rDialog.GetScreenshotId();
106
107 if (!aScreenshotId.isEmpty())
108 {
109 implSaveScreenshot(aScreenshot, aScreenshotId);
110 }
111 }
112}
113
115{
116 VclPtr<VirtualDevice> xDialogSurface(rDialog.screenshot());
117 const BitmapEx aScreenshot(xDialogSurface->GetBitmapEx(Point(), xDialogSurface->GetOutputSizePixel()));
118
119 if (!aScreenshot.IsEmpty())
120 {
121 const OUString aScreenshotId = rDialog.get_help_id();
122 assert(!aScreenshotId.isEmpty());
123 implSaveScreenshot(aScreenshot, aScreenshotId);
124 }
125}
126
128{
129 const mapType::const_iterator aHit = maKnownDialogs.find(rName);
130
131 if (aHit != maKnownDialogs.end())
132 {
133 return createDialogByID((*aHit).second);
134 }
135
137}
138
140{
141 const std::vector<OUString> aPageDescriptions(rDialog.getAllPageUIXMLDescriptions());
142
143 if (!aPageDescriptions.empty())
144 {
145 for (size_t a(0); a < aPageDescriptions.size(); a++)
146 {
147 if (rDialog.selectPageByUIXMLDescription(aPageDescriptions[a]))
148 {
149 saveScreenshot(rDialog);
150 }
151 else
152 {
153 CPPUNIT_ASSERT(false);
154 }
155 }
156 }
157 else
158 {
159 saveScreenshot(rDialog);
160 }
161}
162
164{
165 std::unique_ptr<weld::Window> xDialog(rBuilder.create_screenshot_window());
166
167 auto xTabCtrl = rBuilder.weld_notebook("tabcontrol");
168
169 int nPages = xTabCtrl ? xTabCtrl->get_n_pages() : 0;
170 if (nPages)
171 {
172 for (int i = 0; i < nPages; ++i)
173 {
174 OUString sIdent(xTabCtrl->get_page_ident(i));
175 xTabCtrl->set_current_page(sIdent);
176 if (xTabCtrl->get_current_page_ident() == sIdent)
177 {
178 OUString sOrigHelpId(xDialog->get_help_id());
179 // skip empty pages
180 weld::Container* pPage = xTabCtrl->get_page(sIdent);
181 OUString sBuildableName(pPage->get_buildable_name());
182 if (!sBuildableName.isEmpty() && !sBuildableName.startsWith("__"))
183 xDialog->set_help_id(pPage->get_help_id());
184 saveScreenshot(*xDialog);
185 xDialog->set_help_id(sOrigHelpId);
186 }
187 else
188 {
189 CPPUNIT_ASSERT(false);
190 }
191 }
192 }
193 else
194 {
195 saveScreenshot(*xDialog);
196 }
197}
198
199void ScreenshotTest::dumpDialogToPath(std::string_view rUIXMLDescription)
200{
201 if (rUIXMLDescription.empty())
202 return;
203
204 bool bNonConforming = rUIXMLDescription == "modules/swriter/ui/sidebarstylepresets.ui" ||
205 rUIXMLDescription == "modules/swriter/ui/sidebartheme.ui" ||
206 rUIXMLDescription == "modules/swriter/ui/notebookbar.ui" ||
207 rUIXMLDescription == "modules/scalc/ui/sidebaralignment.ui" ||
208 rUIXMLDescription == "modules/scalc/ui/sidebarcellappearance.ui" ||
209 rUIXMLDescription == "modules/scalc/ui/sidebarnumberformat.ui" ||
210 rUIXMLDescription == "sfx/ui/helpbookmarkpage.ui" ||
211 rUIXMLDescription == "sfx/ui/helpcontentpage.ui" ||
212 rUIXMLDescription == "sfx/ui/helpindexpage.ui" ||
213 rUIXMLDescription == "sfx/ui/helpsearchpage.ui" ||
214 rUIXMLDescription == "sfx/ui/startcenter.ui" ||
215 rUIXMLDescription == "svx/ui/datanavigator.ui" ||
216 rUIXMLDescription == "svx/ui/xformspage.ui" ||
217 rUIXMLDescription == "modules/dbreport/ui/conditionwin.ui";
218 if (bNonConforming) // skip these broken ones
219 return;
220 std::unique_ptr<weld::Builder> xBuilder(Application::CreateBuilder(mxParentWidget.get(), OStringToOUString(rUIXMLDescription, RTL_TEXTENCODING_UTF8)));
221 dumpDialogToPath(*xBuilder);
222}
223
225{
226 for (const auto& rDialog : getKnownDialogs())
227 {
229
230 if (pDlg)
231 {
232 // known dialog, dump screenshot to path
233 dumpDialogToPath(*pDlg);
234 }
235 else
236 {
237 // unknown dialog, should not happen in this basic loop.
238 // You have probably forgotten to add a case and
239 // implementation to createDialogByID, please do this
240 }
241 }
242}
243
244void ScreenshotTest::processDialogBatchFile(std::u16string_view rFile)
245{
246 test::Directories aDirectories;
247 const OUString aURL(aDirectories.getURLFromSrc(rFile));
248 SvFileStream aStream(aURL, StreamMode::READ);
249 OString aNextUIFile;
250 static constexpr OStringLiteral aComment("#");
251
252 while (aStream.ReadLine(aNextUIFile))
253 {
254 if (!aNextUIFile.isEmpty() && !aNextUIFile.startsWith(aComment))
255 {
256 std::cout << "processing " << aNextUIFile << ":\n";
257
258 // first check if it's a known dialog
260
261 if (pDlg)
262 {
263 // known dialog, dump screenshot to path
264 dumpDialogToPath(*pDlg);
265 }
266 else
267 {
268 // unknown dialog, try fallback to generic created
269 // Builder-generated instance. Keep in mind that Dialogs
270 // using this mechanism will probably not be layouted well
271 // since the setup/initialization part is missing. Thus,
272 // only use for fallback when only the UI file is available.
273 dumpDialogToPath(aNextUIFile);
274 }
275 }
276 }
277}
278
279/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
static std::unique_ptr< weld::Builder > CreateBuilder(weld::Widget *pParent, const OUString &rUIFile, bool bMobile=false, sal_uInt64 nLOKWindowId=0)
bool IsEmpty() const
void implSaveScreenshot(const BitmapEx &rScreenshot, const OUString &rScreenshotId)
helpers
mapType maKnownDialogs
the set of known dialogs and their ID for usage in createDialogByID
virtual void setUp() override
void processDialogBatchFile(std::u16string_view rFile)
helper to process an input file containing the UXMLDescriptions of the dialogs to dump.
void saveScreenshot(VclAbstractDialog const &rDialog)
virtual VclPtr< VclAbstractDialog > createDialogByID(sal_uInt32 nID)=0
dialog creation for known dialogs by ID.
std::unique_ptr< weld::Container > mxParentWidget
void dumpDialogToPath(weld::Builder &rDialog)
helper method to create and dump a dialog based on Builder contents.
virtual ~ScreenshotTest() override
void processAllKnownDialogs()
helper to process all known dialogs
virtual void registerKnownDialogsByID(mapType &rKnownDialogs)=0
helper method to populate maKnownDialogs, called in setUp().
VclPtr< VclAbstractDialog > createDialogByName(const OString &rName)
Dialog creation for known dialogs by Name (path and UIXMLDescription, *.ui file).
const mapType & getKnownDialogs() const
const access to known dialogs
OUString maCurrentLanguage
The current UI language.
bool IsOpen() const
bool ReadLine(OStringBuffer &rStr, sal_Int32 nMaxBytesToRead=0xFFFE)
ErrCode const & GetErrorCode() const
virtual OUString GetScreenshotId() const
virtual std::vector< OUString > getAllPageUIXMLDescriptions() const
virtual bool selectPageByUIXMLDescription(const OUString &rUIXMLDescription)
virtual BitmapEx createScreenshot() const
const css::uno::Reference< css::lang::XMultiServiceFactory > & getMultiServiceFactory() const
virtual void setUp() override
OUString getURLFromWorkdir(std::u16string_view rPath) const
OUString getURLFromSrc(std::u16string_view rPath) const
css::uno::Reference< css::frame::XDesktop2 > mxDesktop
bool write(const BitmapEx &rBitmap)
virtual std::unique_ptr< Notebook > weld_notebook(const OUString &id)=0
virtual std::unique_ptr< Window > create_screenshot_window()=0
virtual OUString get_buildable_name() const=0
virtual OUString get_help_id() const=0
virtual VclPtr< VirtualDevice > screenshot()=0
URL aURL
sal_Int32 nIndex
uno_Any a
const css::uno::Reference< css::xml::crypto::XSecurityEnvironment > & env
Reference< XComponentContext > getComponentContext(Reference< XMultiServiceFactory > const &factory)
int i
OString OUStringToOString(std::u16string_view str, ConnectionSettings const *settings)
constexpr OUStringLiteral g_aScreenshotDirectory(u"screenshots")
the target directory for screenshots