bump product version to 7.2.5.1
[LibreOffice.git] / test / source / screenshot_test.cxx
bloba79d53a0d87a947116f32a2b61d33d3f209ddce1
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
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 */
10 #include <sal/config.h>
12 #include <iostream>
14 #include <test/screenshot_test.hxx>
16 #include <com/sun/star/frame/Desktop.hpp>
17 #include <comphelper/processfactory.hxx>
18 #include <vcl/abstdlg.hxx>
19 #include <vcl/pngwrite.hxx>
20 #include <vcl/svapp.hxx>
21 #include <vcl/virdev.hxx>
22 #include <vcl/weld.hxx>
23 #include <tools/stream.hxx>
26 namespace {
27 void splitHelpId( const OString& rHelpId, OUString& rDirname, OUString &rBasename )
29 sal_Int32 nIndex = rHelpId.lastIndexOf( '/' );
31 if( nIndex > 0 )
32 rDirname = OStringToOUString( rHelpId.subView( 0, nIndex ), RTL_TEXTENCODING_UTF8 );
34 if( rHelpId.getLength() > nIndex+1 )
35 rBasename= OStringToOUString( rHelpId.subView( nIndex+1 ), RTL_TEXTENCODING_UTF8 );
39 using namespace css;
40 using namespace css::uno;
42 /// the target directory for screenshots
43 constexpr OUStringLiteral g_aScreenshotDirectory(u"screenshots");
45 ScreenshotTest::ScreenshotTest()
46 : maKnownDialogs()
47 , maParent(nullptr, "vcl/ui/screenshotparent.ui", "ScreenShot")
48 , mxParentWidget(maParent.getDialog()->weld_content_area())
50 if (auto const env = getenv("LO_TEST_LOCALE")) {
51 maCurrentLanguage = OUString::fromUtf8(env);
55 ScreenshotTest::~ScreenshotTest()
59 void ScreenshotTest::setUp()
61 test::BootstrapFixture::setUp();
63 mxDesktop = css::frame::Desktop::create( comphelper::getComponentContext(getMultiServiceFactory()) );
64 CPPUNIT_ASSERT_MESSAGE("no desktop!", mxDesktop.is());
66 osl::Directory::create( m_directories.getURLFromWorkdir( g_aScreenshotDirectory)) ;
68 // initialize maKnownDialogs
69 if (maKnownDialogs.empty())
71 registerKnownDialogsByID(maKnownDialogs);
75 void ScreenshotTest::implSaveScreenshot(const BitmapEx& rScreenshot, const OString& rScreenshotId)
77 OUString aDirname, aBasename;
78 splitHelpId(rScreenshotId, aDirname, aBasename);
79 aDirname = g_aScreenshotDirectory + "/" + aDirname +
80 ( (maCurrentLanguage == "en-US") ? OUString() : "/" + maCurrentLanguage );
82 auto const dirUrl = m_directories.getURLFromWorkdir(aDirname);
83 auto const e = osl::Directory::createPath(dirUrl);
84 if (e != osl::FileBase::E_EXIST) {
85 CPPUNIT_ASSERT_EQUAL_MESSAGE(
86 OString("Failed to create " + OUStringToOString(dirUrl, RTL_TEXTENCODING_UTF8))
87 .getStr(),
88 osl::FileBase::E_None, e);
91 auto const pngUrl = OUString(dirUrl + "/" + aBasename + ".png");
92 SvFileStream aNew(pngUrl, StreamMode::WRITE | StreamMode::TRUNC);
93 CPPUNIT_ASSERT_MESSAGE(OString("Failed to open <" + OUStringToOString(pngUrl, RTL_TEXTENCODING_UTF8) + ">: " + OString::number(sal_uInt32(aNew.GetErrorCode()))).getStr(), aNew.IsOpen());
95 std::cout << "saving " << pngUrl << ":\n";
96 vcl::PNGWriter aPNGWriter(rScreenshot);
97 aPNGWriter.Write(aNew);
100 void ScreenshotTest::saveScreenshot(VclAbstractDialog const & rDialog)
102 const BitmapEx aScreenshot(rDialog.createScreenshot());
104 if (!aScreenshot.IsEmpty())
106 const OString aScreenshotId = rDialog.GetScreenshotId();
108 if (!aScreenshotId.isEmpty())
110 implSaveScreenshot(aScreenshot, aScreenshotId);
115 void ScreenshotTest::saveScreenshot(weld::Window& rDialog)
117 VclPtr<VirtualDevice> xDialogSurface(rDialog.screenshot());
118 const BitmapEx aScreenshot(xDialogSurface->GetBitmapEx(Point(), xDialogSurface->GetOutputSizePixel()));
120 if (!aScreenshot.IsEmpty())
122 const OString aScreenshotId = rDialog.get_help_id();
123 assert(!aScreenshotId.isEmpty());
124 implSaveScreenshot(aScreenshot, aScreenshotId);
128 VclPtr<VclAbstractDialog> ScreenshotTest::createDialogByName(const OString& rName)
130 const mapType::const_iterator aHit = maKnownDialogs.find(rName);
132 if (aHit != maKnownDialogs.end())
134 return createDialogByID((*aHit).second);
137 return VclPtr<VclAbstractDialog>();
140 void ScreenshotTest::dumpDialogToPath(VclAbstractDialog& rDialog)
142 const std::vector<OString> aPageDescriptions(rDialog.getAllPageUIXMLDescriptions());
144 if (!aPageDescriptions.empty())
146 for (size_t a(0); a < aPageDescriptions.size(); a++)
148 if (rDialog.selectPageByUIXMLDescription(aPageDescriptions[a]))
150 saveScreenshot(rDialog);
152 else
154 CPPUNIT_ASSERT(false);
158 else
160 saveScreenshot(rDialog);
164 void ScreenshotTest::dumpDialogToPath(weld::Builder& rBuilder)
166 std::unique_ptr<weld::Window> xDialog(rBuilder.create_screenshot_window());
168 auto xTabCtrl = rBuilder.weld_notebook("tabcontrol");
170 int nPages = xTabCtrl ? xTabCtrl->get_n_pages() : 0;
171 if (nPages)
173 for (int i = 0; i < nPages; ++i)
175 OString sIdent(xTabCtrl->get_page_ident(i));
176 xTabCtrl->set_current_page(sIdent);
177 if (xTabCtrl->get_current_page_ident() == sIdent)
179 OString sOrigHelpId(xDialog->get_help_id());
180 // skip empty pages
181 weld::Container* pPage = xTabCtrl->get_page(sIdent);
182 OString sBuildableName(pPage->get_buildable_name());
183 if (!sBuildableName.isEmpty() && !sBuildableName.startsWith("__"))
184 xDialog->set_help_id(pPage->get_help_id());
185 saveScreenshot(*xDialog);
186 xDialog->set_help_id(sOrigHelpId);
188 else
190 CPPUNIT_ASSERT(false);
194 else
196 saveScreenshot(*xDialog);
200 void ScreenshotTest::dumpDialogToPath(std::string_view rUIXMLDescription)
202 if (rUIXMLDescription.empty())
203 return;
205 bool bNonConforming = rUIXMLDescription == "modules/swriter/ui/sidebarstylepresets.ui" ||
206 rUIXMLDescription == "modules/swriter/ui/sidebartheme.ui" ||
207 rUIXMLDescription == "modules/swriter/ui/notebookbar.ui" ||
208 rUIXMLDescription == "modules/scalc/ui/sidebaralignment.ui" ||
209 rUIXMLDescription == "modules/scalc/ui/sidebarcellappearance.ui" ||
210 rUIXMLDescription == "modules/scalc/ui/sidebarnumberformat.ui" ||
211 rUIXMLDescription == "sfx/ui/helpbookmarkpage.ui" ||
212 rUIXMLDescription == "sfx/ui/helpcontentpage.ui" ||
213 rUIXMLDescription == "sfx/ui/helpindexpage.ui" ||
214 rUIXMLDescription == "sfx/ui/helpsearchpage.ui" ||
215 rUIXMLDescription == "sfx/ui/startcenter.ui" ||
216 rUIXMLDescription == "svx/ui/datanavigator.ui" ||
217 rUIXMLDescription == "svx/ui/xformspage.ui" ||
218 rUIXMLDescription == "modules/dbreport/ui/conditionwin.ui";
219 if (bNonConforming) // skip these broken ones
220 return;
221 std::unique_ptr<weld::Builder> xBuilder(Application::CreateBuilder(mxParentWidget.get(), OStringToOUString(rUIXMLDescription, RTL_TEXTENCODING_UTF8)));
222 dumpDialogToPath(*xBuilder);
225 void ScreenshotTest::processAllKnownDialogs()
227 for (const auto& rDialog : getKnownDialogs())
229 ScopedVclPtr<VclAbstractDialog> pDlg(createDialogByID(rDialog.second));
231 if (pDlg)
233 // known dialog, dump screenshot to path
234 dumpDialogToPath(*pDlg);
236 else
238 // unknown dialog, should not happen in this basic loop.
239 // You have probably forgotten to add a case and
240 // implementation to createDialogByID, please do this
245 void ScreenshotTest::processDialogBatchFile(std::u16string_view rFile)
247 test::Directories aDirectories;
248 const OUString aURL(aDirectories.getURLFromSrc(rFile));
249 SvFileStream aStream(aURL, StreamMode::READ);
250 OString aNextUIFile;
251 const OString aComment("#");
253 while (aStream.ReadLine(aNextUIFile))
255 if (!aNextUIFile.isEmpty() && !aNextUIFile.startsWith(aComment))
257 std::cout << "processing " << aNextUIFile << ":\n";
259 // first check if it's a known dialog
260 ScopedVclPtr<VclAbstractDialog> pDlg(createDialogByName(aNextUIFile));
262 if (pDlg)
264 // known dialog, dump screenshot to path
265 dumpDialogToPath(*pDlg);
267 else
269 // unknown dialog, try fallback to generic created
270 // Builder-generated instance. Keep in mind that Dialogs
271 // using this mechanism will probably not be layouted well
272 // since the setup/initialization part is missing. Thus,
273 // only use for fallback when only the UI file is available.
274 dumpDialogToPath(aNextUIFile);
280 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */