Repository.mk                                                  |    1 
 cui/Library_cui.mk                                             |    1 
 cui/UIConfig_cui.mk                                            |    1 
 cui/inc/whatsnew.hrc                                           |   42 ++
 cui/source/dialogs/whatsnew.cxx                                |  172 
++++++++++
 cui/source/factory/dlgfact.cxx                                 |   13 
 cui/source/factory/dlgfact.hxx                                 |    2 
 cui/source/inc/whatsnew.hxx                                    |   75 ++++
 cui/uiconfig/ui/whatsnewdialog.ui                              |  131 +++++++
 desktop/source/app/app.cxx                                     |    2 
 extras/source/whatsnew/Community.png                           |binary
 extras/source/whatsnew/Configurability.png                     |binary
 extras/source/whatsnew/LibreOffice.gif                         |binary
 extras/source/whatsnew/ODF.png                                 |binary
 extras/source/whatsnew/whatsnew1.png                           |binary
 include/sfx2/sfxdlg.hxx                                        |    2 
 include/sfx2/sfxsids.hrc                                       |    5 
 include/sfx2/strings.hrc                                       |    2 
 include/sfx2/viewfrm.hxx                                       |    1 
 include/unotools/VersionConfig.hxx                             |   24 -
 officecfg/registry/schema/org/openoffice/Office/UI/Infobar.xcs |    6 
 officecfg/registry/schema/org/openoffice/Setup.xcs             |    8 
 sfx2/sdi/appslots.sdi                                          |    4 
 sfx2/sdi/sfx.sdi                                               |   16 
 sfx2/source/appl/appserv.cxx                                   |   10 
 sfx2/source/dialog/infobar.cxx                                 |    2 
 sfx2/source/view/viewfrm.cxx                                   |   43 +-
 vcl/Module_vcl.mk                                              |    1 
 vcl/Package_whatsnew.mk                                        |   20 +
 29 files changed, 533 insertions(+), 51 deletions(-)

New commits:
commit dd889b290304b73f96a9a8e6e0f144d3aa2ba7e1
Author:     Heiko Tietze <tietze.he...@gmail.com>
AuthorDate: Thu Feb 22 12:56:01 2024 +0100
Commit:     Heiko Tietze <heiko.tie...@documentfoundation.org>
CommitDate: Wed Mar 27 09:41:44 2024 +0100

    Resolves tdf#159573 and tdf#137931 - WhatsNew or Welcome dialog
    
    To test the new dialog, change org.openoffice.Setup > Product > 
ooSetupLastVersion to some lesser value for the WhatsNew dialog or clear the 
entry for the Welcome version.
    
    Change-Id: Iec6de50edba0e5430e82f1db85e61d1e4501771d
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/163739
    Reviewed-by: Michael Weghorn <m.wegh...@posteo.de>
    Tested-by: Jenkins
    Reviewed-by: Heiko Tietze <heiko.tie...@documentfoundation.org>

diff --git a/Repository.mk b/Repository.mk
index 5b60bd66cfcc..9317a29975df 100644
--- a/Repository.mk
+++ b/Repository.mk
@@ -925,6 +925,7 @@ $(eval $(call gb_Helper_register_packages_for_install,sdk,\
 ifneq ($(ENABLE_WASM_STRIP_PINGUSER),TRUE)
 $(eval $(call gb_Helper_register_packages_for_install,ooo,\
        tipoftheday_images \
+       whatsnew_images \
 ))
 endif
 
diff --git a/cui/Library_cui.mk b/cui/Library_cui.mk
index e01e33ecb4ec..3ee744e32d0f 100644
--- a/cui/Library_cui.mk
+++ b/cui/Library_cui.mk
@@ -114,6 +114,7 @@ $(eval $(call gb_Library_add_exception_objects,cui,\
     cui/source/customize/SvxNotebookbarConfigPage \
     cui/source/customize/CustomNotebookbarGenerator \
     cui/source/dialogs/about \
+    cui/source/dialogs/whatsnew \
     $(call gb_Helper_optional,EXTENSIONS, \
         cui/source/dialogs/AdditionsDialog) \
     cui/source/dialogs/colorpicker \
diff --git a/cui/UIConfig_cui.mk b/cui/UIConfig_cui.mk
index 10acd83c8c39..79ff7696a93a 100644
--- a/cui/UIConfig_cui.mk
+++ b/cui/UIConfig_cui.mk
@@ -18,6 +18,7 @@ endif
 ifneq ($(ENABLE_WASM_STRIP_PINGUSER),TRUE)
 $(eval $(call gb_UIConfig_add_uifiles,cui,\
        cui/uiconfig/ui/tipofthedaydialog \
+       cui/uiconfig/ui/whatsnewdialog \
 ))
 endif
 
diff --git a/cui/inc/whatsnew.hrc b/cui/inc/whatsnew.hrc
new file mode 100644
index 000000000000..e155a597bcf2
--- /dev/null
+++ b/cui/inc/whatsnew.hrc
@@ -0,0 +1,42 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; 
fill-column: 100 -*- */
+/*
+ * 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/.
+ */
+
+#pragma once
+
+#define NC_(Context, String) TranslateId(Context, u8##String)
+
+#include <rtl/ustring.hxx>
+#include <config_python.h>
+#include <tuple>
+#include <unotools/resmgr.hxx>
+
+/*
+ * std:tuple consists of <text, image>
+ * image:
+   * place new images at extra/source/whatsnew
+   * do not forget to add the files to vcl/Package_whatsnew.mk
+   * images are cut-off at 600x400px
+*/
+
+const std::tuple<TranslateId, OUString> WELCOME_STRINGARRAY[] =
+{
+     { NC_("RID_CUI_WHATSNEW", "%PRODUCTNAME is a powerful and free office 
suite, used by millions of people around the world."), "LibreOffice.gif"},
+     { NC_("RID_CUI_WHATSNEW", "%PRODUCTNAME uses the reliable and trustworthy 
standard open document format."), "ODF.png"},
+     { NC_("RID_CUI_WHATSNEW", "%PRODUCTNAME blends into every operation 
system and provides full customization."), "Configurability.png"},
+     { NC_("RID_CUI_WHATSNEW", "%PRODUCTNAME is open source: Your project, 
your data, your freedom."), "Community.png"},
+};
+
+const std::tuple<TranslateId, OUString> WHATSNEW_STRINGARRAY[] =
+{
+     { NC_("RID_CUI_WHATSNEW", "Version 24.8 brings a shiny WhatsNew dialog 
:-)"), "whatsnew1.png"},
+};
+
+#define STR_WELCOME       NC_("STR_WELCOME", "Welcome to %PRODUCTNAME!")
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s 
cinkeys+=0=break: */
\ No newline at end of file
diff --git a/cui/source/dialogs/whatsnew.cxx b/cui/source/dialogs/whatsnew.cxx
new file mode 100644
index 000000000000..31ad380d8cf9
--- /dev/null
+++ b/cui/source/dialogs/whatsnew.cxx
@@ -0,0 +1,172 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; 
fill-column: 100 -*- */
+/*
+ * 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 <whatsnew.hxx>
+#include <whatsnew.hrc>
+
+#include <dialmgr.hxx>
+#include <comphelper/DirectoryHelper.hxx>
+#include <rtl/bootstrap.hxx>
+#include <vcl/graphicfilter.hxx>
+#include <vcl/svapp.hxx>
+#include <vcl/gdimtf.hxx>
+
+constexpr tools::Long TEXT_HEIGHT(120);
+constexpr tools::Long PROGRESS_DOTSIZE(24);
+constexpr tools::Long PROGRESS_DOTSPACING(4);
+
+WhatsNewDialog::WhatsNewDialog(weld::Window* pParent, const bool bWelcome)
+    : GenericDialogController(pParent, "cui/ui/whatsnewdialog.ui", 
"WhatsNewDialog")
+    , m_bWelcome(bWelcome)
+    , m_aPreview()
+    , m_aProgress()
+    , m_pPrevBtn(m_xBuilder->weld_button("btnPrev"))
+    , m_pNextBtn(m_xBuilder->weld_button("btnNext"))
+    , m_pProgress(new weld::CustomWeld(*m_xBuilder, "imProgress", m_aProgress))
+    , m_pImage(new weld::CustomWeld(*m_xBuilder, "imNews", m_aPreview))
+{
+    if (m_bWelcome)
+        m_xDialog->set_title(CuiResId(STR_WELCOME));
+    m_pPrevBtn->set_sensitive(false);
+
+    m_pPrevBtn->connect_clicked(LINK(this, WhatsNewDialog, OnPrevClick));
+    m_pNextBtn->connect_clicked(LINK(this, WhatsNewDialog, OnNextClick));
+
+    m_nNumberOfNews = m_bWelcome ? std::size(WELCOME_STRINGARRAY) : 
std::size(WHATSNEW_STRINGARRAY);
+    m_nCurrentNews = 0;
+    m_pNextBtn->set_sensitive(m_nNumberOfNews > 1);
+    m_pProgress->set_size_request(m_nNumberOfNews * (PROGRESS_DOTSIZE + 
PROGRESS_DOTSPACING),
+                                  PROGRESS_DOTSIZE + 1);
+
+    LoadImage();
+}
+
+WhatsNewDialog::~WhatsNewDialog() {}
+
+void WhatsNewDialog::LoadImage()
+{
+    if (m_nCurrentNews < m_nNumberOfNews)
+    {
+        auto[sText, sImage] = m_bWelcome ? WELCOME_STRINGARRAY[m_nCurrentNews]
+                                         : 
WHATSNEW_STRINGARRAY[m_nCurrentNews];
+        OUString aURL("$BRAND_BASE_DIR/$BRAND_SHARE_SUBDIR/whatsnew/");
+        rtl::Bootstrap::expandMacros(aURL);
+
+        const bool bFileExists = comphelper::DirectoryHelper::fileExists(aURL 
+ sImage);
+        if (!sImage.isEmpty() && bFileExists)
+            m_aPreview.Update(aURL + sImage, CuiResId(sText));
+
+        m_aProgress.Update(m_nCurrentNews, m_nNumberOfNews);
+    }
+}
+
+IMPL_LINK_NOARG(WhatsNewDialog, OnPrevClick, weld::Button&, void)
+{
+    m_nCurrentNews--;
+    if (m_nCurrentNews == 0)
+        m_pPrevBtn->set_sensitive(false);
+    m_pNextBtn->set_sensitive(true);
+    LoadImage();
+}
+
+IMPL_LINK_NOARG(WhatsNewDialog, OnNextClick, weld::Button&, void)
+{
+    m_nCurrentNews++;
+    if (m_nCurrentNews == m_nNumberOfNews - 1)
+        m_pNextBtn->set_sensitive(false);
+    m_pPrevBtn->set_sensitive(true);
+    LoadImage();
+}
+
+void WhatsNewImg::Paint(vcl::RenderContext& rRenderContext, const 
tools::Rectangle&)
+{
+    const StyleSettings 
rSettings(Application::GetSettings().GetStyleSettings());
+
+    //clear
+    rRenderContext.SetBackground(Wallpaper(rSettings.GetDialogColor()));
+    rRenderContext.Erase();
+
+    //background image
+    Graphic aGraphic;
+    GraphicFilter::LoadGraphic(m_sImage, OUString(), aGraphic);
+    const Size aGraphicSize(aGraphic.GetSizePixel());
+
+    if (aGraphic.IsAnimated())
+        aGraphic.StartAnimation(rRenderContext, Point(), aGraphicSize);
+    else
+        aGraphic.Draw(rRenderContext, Point(), aGraphicSize);
+
+    tools::Rectangle aRect(Point(0, aGraphicSize.Height() - TEXT_HEIGHT),
+                           Size(aGraphicSize.Width(), TEXT_HEIGHT));
+
+    //transparent text background
+    ScopedVclPtrInstance<VirtualDevice> aVDev;
+    GDIMetaFile aMetafile;
+
+    aMetafile.Record(aVDev.get());
+    aMetafile.SetPrefSize(aRect.GetSize());
+    aVDev->SetOutputSize(aRect.GetSize());
+    aVDev->SetBackground(Color(0x10, 0x68, 0x02));
+    aVDev->Erase();
+    aMetafile.Stop();
+
+    Gradient aVCLGradient;
+    aVCLGradient.SetStyle(css::awt::GradientStyle_LINEAR);
+    aVCLGradient.SetStartColor(COL_GRAY);
+    aVCLGradient.SetEndColor(COL_GRAY);
+    aVCLGradient.SetStartIntensity(33);
+    aVCLGradient.SetEndIntensity(66);
+
+    rRenderContext.DrawTransparent(aMetafile, aRect.TopLeft(), 
aRect.GetSize(), aVCLGradient);
+
+    //text
+    vcl::Font aFont = rRenderContext.GetFont();
+    const Size aFontSize = aFont.GetFontSize();
+    aFont.SetFontSize(Size(0, 24));
+    aFont.SetColor(COL_WHITE);
+    aFont.SetWeight(WEIGHT_BOLD);
+    rRenderContext.SetFont(aFont);
+
+    DrawTextFlags nDrawTextStyle(DrawTextFlags::MultiLine | 
DrawTextFlags::WordBreak
+                                 | DrawTextFlags::EndEllipsis);
+    const bool bIsRTL = rRenderContext.GetTextIsRTL(m_sText, 0, 
m_sText.getLength());
+    if (bIsRTL)
+        nDrawTextStyle |= DrawTextFlags::Right;
+
+    aRect.shrink(6);
+    aRect.setWidth(rRenderContext.GetOutputSizePixel().Width() - 12);
+    rRenderContext.DrawText(aRect, m_sText, nDrawTextStyle);
+
+    aFont.SetFontSize(aFontSize);
+    aFont.SetWeight(WEIGHT_NORMAL);
+    rRenderContext.SetFont(aFont);
+}
+
+void WhatsNewProgress::Paint(vcl::RenderContext& rRenderContext, const 
tools::Rectangle&)
+{
+    const StyleSettings 
rSettings(Application::GetSettings().GetStyleSettings());
+    rRenderContext.SetBackground(rSettings.GetDialogColor());
+    rRenderContext.Erase();
+    rRenderContext.SetAntialiasing(AntialiasingFlags::Enable);
+
+    tools::Rectangle aRect(Point(0, 0), Size(PROGRESS_DOTSIZE, 
PROGRESS_DOTSIZE));
+    for (sal_Int32 i = 0; i < m_nTotal; i++)
+    {
+        if (i == m_nCurrent)
+            rRenderContext.SetFillColor(rSettings.GetAccentColor());
+        else
+            rRenderContext.SetFillColor(COL_WHITE);
+        rRenderContext.DrawEllipse(aRect);
+
+        aRect.AdjustLeft(PROGRESS_DOTSIZE + PROGRESS_DOTSPACING);
+        aRect.AdjustRight(PROGRESS_DOTSIZE + PROGRESS_DOTSPACING);
+    }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s 
cinkeys+=0=break: */
\ No newline at end of file
diff --git a/cui/source/factory/dlgfact.cxx b/cui/source/factory/dlgfact.cxx
index b25ce9c9359b..2a71808ae59d 100644
--- a/cui/source/factory/dlgfact.cxx
+++ b/cui/source/factory/dlgfact.cxx
@@ -24,6 +24,7 @@
 #include "dlgfact.hxx"
 
 #include <about.hxx>
+#include <whatsnew.hxx>
 #include <sfx2/app.hxx>
 #include <sfx2/basedlgs.hxx>
 #include <sfx2/pageids.hxx>
@@ -1531,6 +1532,18 @@ 
AbstractDialogFactory_Impl::CreateAboutDialog(weld::Window* pParent)
         std::make_shared<AboutDialog>(pParent));
 }
 
+VclPtr<VclAbstractDialog>
+AbstractDialogFactory_Impl::CreateWhatsNewDialog(weld::Window* pParent, const 
bool bWelcome)
+{
+#if !ENABLE_WASM_STRIP_PINGUSER
+    return VclPtr<CuiAbstractControllerAsync_Impl>::Create(
+        std::make_shared<WhatsNewDialog>(pParent, bWelcome));
+#else
+    (void) pParent;
+    return nullptr;
+#endif
+}
+
 VclPtr<VclAbstractDialog>
 AbstractDialogFactory_Impl::CreateTipOfTheDayDialog(weld::Window* pParent)
 {
diff --git a/cui/source/factory/dlgfact.hxx b/cui/source/factory/dlgfact.hxx
index fc83403cb24d..6b4a548fe3fc 100644
--- a/cui/source/factory/dlgfact.hxx
+++ b/cui/source/factory/dlgfact.hxx
@@ -619,6 +619,8 @@ public:
 
     virtual VclPtr<VclAbstractDialog> CreateAboutDialog(weld::Window* pParent) 
override;
 
+    virtual VclPtr<VclAbstractDialog> CreateWhatsNewDialog(weld::Window* 
pParent, const bool bWelcome) override;
+
     virtual VclPtr<VclAbstractDialog> CreateTipOfTheDayDialog(weld::Window* 
pParent) override;
 
     virtual VclPtr<VclAbstractDialog> CreateWidgetTestDialog(weld::Window* 
pParent) override;
diff --git a/cui/source/inc/whatsnew.hxx b/cui/source/inc/whatsnew.hxx
new file mode 100644
index 000000000000..76a3a2d4d63d
--- /dev/null
+++ b/cui/source/inc/whatsnew.hxx
@@ -0,0 +1,75 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; 
fill-column: 100 -*- */
+/*
+ * 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/.
+ */
+
+#pragma once
+
+#include <vcl/customweld.hxx>
+#include <vcl/weld.hxx>
+#include "cuigrfflt.hxx"
+
+class WhatsNewImg : public weld::CustomWidgetController
+{
+    OUString m_sImage;
+    OUString m_sText;
+    virtual void Paint(vcl::RenderContext& rRenderContext, const 
tools::Rectangle&) override;
+
+public:
+    WhatsNewImg(){};
+    void Update(const OUString& sImage, const OUString& sText)
+    {
+        m_sImage = sImage;
+        m_sText = sText;
+        SetAccessibleName(m_sText);
+        Invalidate();
+    };
+};
+
+class WhatsNewProgress : public weld::CustomWidgetController
+{
+    sal_Int32 m_nTotal;
+    sal_Int32 m_nCurrent;
+    virtual void Paint(vcl::RenderContext& rRenderContext, const 
tools::Rectangle&) override;
+
+public:
+    WhatsNewProgress(){};
+    void Update(const sal_Int32 nCurrent, const sal_Int32 nTotal)
+    {
+        m_nTotal = nTotal;
+        m_nCurrent = nCurrent;
+        Invalidate();
+    };
+};
+
+class WhatsNewDialog : public weld::GenericDialogController
+{
+private:
+    const bool m_bWelcome;
+
+    WhatsNewImg m_aPreview;
+    WhatsNewProgress m_aProgress;
+
+    std::unique_ptr<weld::Button> m_pPrevBtn;
+    std::unique_ptr<weld::Button> m_pNextBtn;
+    std::unique_ptr<weld::CustomWeld> m_pProgress;
+    std::unique_ptr<weld::CustomWeld> m_pImage;
+
+    DECL_LINK(OnPrevClick, weld::Button&, void);
+    DECL_LINK(OnNextClick, weld::Button&, void);
+
+    void LoadImage(); // loads WHATSNEW_STRINGARRAY[m_nCurrentNews]
+
+    sal_Int32 m_nNumberOfNews;
+    sal_Int32 m_nCurrentNews;
+
+public:
+    WhatsNewDialog(weld::Window* pParent, const bool bWelcome);
+    virtual ~WhatsNewDialog() override;
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s 
cinkeys+=0=break: */
diff --git a/cui/uiconfig/ui/whatsnewdialog.ui 
b/cui/uiconfig/ui/whatsnewdialog.ui
new file mode 100644
index 000000000000..0a4949c398bf
--- /dev/null
+++ b/cui/uiconfig/ui/whatsnewdialog.ui
@@ -0,0 +1,131 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Generated with glade 3.40.0 -->
+<interface domain="cui">
+  <requires lib="gtk+" version="3.20"/>
+  <object class="GtkDialog" id="WhatsNewDialog">
+    <property name="can-focus">False</property>
+    <property name="border-width">6</property>
+    <property name="title" translatable="yes" 
context="whatsnewdialog|WhatsNewDialog">What's new in %PRODUCTVERSION</property>
+    <property name="resizable">False</property>
+    <property name="modal">True</property>
+    <property name="window-position">center-on-parent</property>
+    <property name="type-hint">dialog</property>
+    <child internal-child="vbox">
+      <object class="GtkBox">
+        <property name="can-focus">False</property>
+        <property name="orientation">vertical</property>
+        <property name="spacing">12</property>
+        <child internal-child="action_area">
+          <object class="GtkButtonBox">
+            <property name="can-focus">False</property>
+            <property name="margin-top">12</property>
+            <property name="hexpand">True</property>
+            <property name="layout-style">end</property>
+            <child>
+              <object class="GtkButton" id="btnClose">
+                <property name="label" translatable="yes" 
context="stock">_Close</property>
+                <property name="visible">True</property>
+                <property name="can-focus">True</property>
+                <property name="receives-default">True</property>
+                <property name="use-underline">True</property>
+              </object>
+              <packing>
+                <property name="expand">True</property>
+                <property name="fill">True</property>
+                <property name="pack-type">end</property>
+                <property name="position">3</property>
+              </packing>
+            </child>
+          </object>
+          <packing>
+            <property name="expand">False</property>
+            <property name="fill">True</property>
+            <property name="pack-type">end</property>
+            <property name="position">0</property>
+          </packing>
+        </child>
+        <child>
+          <!-- n-columns=3 n-rows=2 -->
+          <object class="GtkGrid" id="grid">
+            <property name="visible">True</property>
+            <property name="can-focus">False</property>
+            <child>
+              <object class="GtkDrawingArea" id="imNews">
+                <property name="width-request">600</property>
+                <property name="height-request">400</property>
+                <property name="visible">True</property>
+                <property name="can-focus">False</property>
+                <child internal-child="accessible">
+                  <object class="AtkObject" id="imNews-atkobject">
+                    <property name="AtkObject::accessible-description" 
translatable="yes" context="whatsnewdialog|extended_tip|news">Picture 
illustrating what is new</property>
+                  </object>
+                </child>
+              </object>
+              <packing>
+                <property name="left-attach">0</property>
+                <property name="top-attach">0</property>
+                <property name="width">3</property>
+              </packing>
+            </child>
+            <child>
+              <object class="GtkButton" id="btnPrev">
+                <property name="label" translatable="yes" 
context="whatsnewdialog|prev">Previous</property>
+                <property name="visible">True</property>
+                <property name="can-focus">True</property>
+                <property name="receives-default">True</property>
+                <property name="halign">end</property>
+                <property name="valign">center</property>
+                <property name="use-underline">True</property>
+              </object>
+              <packing>
+                <property name="left-attach">0</property>
+                <property name="top-attach">1</property>
+              </packing>
+            </child>
+            <child>
+              <object class="GtkButton" id="btnNext">
+                <property name="label" translatable="yes" 
context="whatsnewdialog|next">Next</property>
+                <property name="visible">True</property>
+                <property name="can-focus">True</property>
+                <property name="receives-default">True</property>
+                <property name="halign">start</property>
+                <property name="valign">center</property>
+                <property name="use-underline">True</property>
+                <property name="image-position">right</property>
+              </object>
+              <packing>
+                <property name="left-attach">2</property>
+                <property name="top-attach">1</property>
+              </packing>
+            </child>
+            <child>
+              <object class="GtkDrawingArea" id="imProgress">
+                <property name="visible">True</property>
+                <property name="can-focus">False</property>
+                <property name="halign">center</property>
+                <property name="valign">center</property>
+                <child internal-child="accessible">
+                  <object class="AtkObject" id="imProgress-atkobject">
+                    <property name="AtkObject::accessible-description" 
translatable="yes" context="whatsnewdialog|extended_tip|progress">Progress of 
news</property>
+                  </object>
+                </child>
+              </object>
+              <packing>
+                <property name="left-attach">1</property>
+                <property name="top-attach">1</property>
+              </packing>
+            </child>
+          </object>
+          <packing>
+            <property name="expand">False</property>
+            <property name="fill">True</property>
+            <property name="position">1</property>
+          </packing>
+        </child>
+      </object>
+    </child>
+    <action-widgets>
+      <action-widget response="-7">btnClose</action-widget>
+    </action-widgets>
+  </object>
+</interface>
diff --git a/desktop/source/app/app.cxx b/desktop/source/app/app.cxx
index d99b7995ed93..d59855e58b03 100644
--- a/desktop/source/app/app.cxx
+++ b/desktop/source/app/app.cxx
@@ -347,7 +347,7 @@ void runGraphicsRenderTests()
     if (comphelper::LibreOfficeKit::isActive())
         return;
 #if !ENABLE_WASM_STRIP_PINGUSER
-    if (!utl::isProductVersionUpgraded(false))
+    if (!utl::isProductVersionUpgraded())
     {
         return;
     }
diff --git a/extras/source/whatsnew/Community.png 
b/extras/source/whatsnew/Community.png
new file mode 100644
index 000000000000..ae3169885705
Binary files /dev/null and b/extras/source/whatsnew/Community.png differ
diff --git a/extras/source/whatsnew/Configurability.png 
b/extras/source/whatsnew/Configurability.png
new file mode 100644
index 000000000000..2ca9094ebf70
Binary files /dev/null and b/extras/source/whatsnew/Configurability.png differ
diff --git a/extras/source/whatsnew/LibreOffice.gif 
b/extras/source/whatsnew/LibreOffice.gif
new file mode 100644
index 000000000000..1d5643091a6b
Binary files /dev/null and b/extras/source/whatsnew/LibreOffice.gif differ
diff --git a/extras/source/whatsnew/ODF.png b/extras/source/whatsnew/ODF.png
new file mode 100644
index 000000000000..04e23d7021d6
Binary files /dev/null and b/extras/source/whatsnew/ODF.png differ
diff --git a/extras/source/whatsnew/whatsnew1.png 
b/extras/source/whatsnew/whatsnew1.png
new file mode 100644
index 000000000000..bce0be6b970c
Binary files /dev/null and b/extras/source/whatsnew/whatsnew1.png differ
diff --git a/include/sfx2/sfxdlg.hxx b/include/sfx2/sfxdlg.hxx
index 31bd0c3108ad..c4db62792f14 100644
--- a/include/sfx2/sfxdlg.hxx
+++ b/include/sfx2/sfxdlg.hxx
@@ -147,6 +147,8 @@ public:
 
     virtual VclPtr<VclAbstractDialog> CreateAboutDialog(weld::Window* 
_pParent) = 0;
 
+    virtual VclPtr<VclAbstractDialog> CreateWhatsNewDialog(weld::Window* 
_pParent, const bool bWelcome) = 0;
+
     virtual VclPtr<VclAbstractDialog> CreateTipOfTheDayDialog(weld::Window* 
_pParent) = 0;
 
     virtual VclPtr<VclAbstractDialog> CreateToolbarmodeDialog(weld::Window* 
_pParent) = 0;
diff --git a/include/sfx2/sfxsids.hrc b/include/sfx2/sfxsids.hrc
index e2fafac7321a..f863d7cb3233 100644
--- a/include/sfx2/sfxsids.hrc
+++ b/include/sfx2/sfxsids.hrc
@@ -117,8 +117,9 @@ class SvxZoomItem;
 #define SID_DOCUMENTATION                   (SID_SFX_START + 423)
 #define SID_DONATION                        (SID_SFX_START + 424)
 #define SID_GETINVOLVED                     (SID_SFX_START + 425)
-#define SID_WHATSNEW                        (SID_SFX_START + 426)
-#define SID_HYPHENATIONMISSING              (SID_SFX_START + 427)
+#define SID_WHATSNEW                        (SID_SFX_START + 426) // open 
ReleaseNotesURL
+#define SID_WHATSNEWDLG                     (SID_SFX_START + 427) // show 
WhatsNewDlg
+#define SID_HYPHENATIONMISSING              (SID_SFX_START + 428)
 
 #define SID_SHOW_LICENSE                    (SID_SFX_START + 1683)
 #define SID_SHOW_CREDITS                    (SID_SFX_START + 1711)
diff --git a/include/sfx2/strings.hrc b/include/sfx2/strings.hrc
index 1c3fafa074c0..a269b5335a36 100644
--- a/include/sfx2/strings.hrc
+++ b/include/sfx2/strings.hrc
@@ -260,8 +260,6 @@
 #define STR_GET_INVOLVED_BUTTON                 NC_("STR_GET_INVOLVED_BUTTON", 
"Get involved")
 #define STR_DONATE_TEXT                         NC_("STR_DONATE_TEXT", "Your 
donations support our worldwide community.")
 #define STR_DONATE_BUTTON                       NC_("STR_DONATE_BUTTON", 
"Donate")
-#define STR_WHATSNEW_TEXT                       NC_("STR_WHATSNEW", "You are 
running version %PRODUCTVERSION of %PRODUCTNAME for the first time. Do you want 
to learn what's new?")
-#define STR_WHATSNEW_BUTTON                     NC_("STR_WHATSNEW_BUTTON", 
"Release Notes")
 #define STR_READONLY_DOCUMENT                   NC_("STR_READONLY_DOCUMENT", 
"This document is open in read-only mode.")
 #define STR_READONLY_PDF                        NC_("STR_READONLY_PDF", "This 
PDF is open in read-only mode to allow signing the existing file.")
 #define STR_CLASSIFIED_DOCUMENT                 NC_("STR_CLASSIFIED_DOCUMENT", 
"The classification label of this document is %1.")
diff --git a/include/sfx2/viewfrm.hxx b/include/sfx2/viewfrm.hxx
index 7e038e9d6b96..1e3d4e55ab47 100644
--- a/include/sfx2/viewfrm.hxx
+++ b/include/sfx2/viewfrm.hxx
@@ -63,7 +63,6 @@ class SFX2_DLLPUBLIC SfxViewFrame final : public SfxShell, 
public SfxListener
     virtual void            Notify( SfxBroadcaster& rBC, const SfxHint& rHint 
) override;
     DECL_DLLPRIVATE_LINK(GetInvolvedHandler, weld::Button&, void);
     DECL_DLLPRIVATE_LINK(DonationHandler, weld::Button&, void);
-    DECL_DLLPRIVATE_LINK(WhatsNewHandler, weld::Button&, void);
     DECL_DLLPRIVATE_LINK(MacroButtonHandler, weld::Button&, void);
     DECL_DLLPRIVATE_LINK(SecurityButtonHandler, weld::Button&, void);
     DECL_DLLPRIVATE_LINK(EventButtonHandler, weld::Button&, void);
diff --git a/include/unotools/VersionConfig.hxx 
b/include/unotools/VersionConfig.hxx
index 5e40b0af8756..3918dfd2e514 100644
--- a/include/unotools/VersionConfig.hxx
+++ b/include/unotools/VersionConfig.hxx
@@ -25,7 +25,7 @@ namespace utl
     @param aUpdateVersion This variable is used to determine if
     LibreOffice's previous version should be updated.
  */
-static bool isProductVersionUpgraded(bool aUpdateVersion)
+static bool isProductVersionUpgraded()
 {
     OUString sSetupVersion = utl::ConfigManager::getProductVersion();
     sal_Int32 iCurrent = o3tl::toInt32(o3tl::getToken(sSetupVersion, 0, '.')) 
* 10
@@ -33,26 +33,6 @@ static bool isProductVersionUpgraded(bool aUpdateVersion)
     OUString sLastVersion = 
officecfg::Setup::Product::ooSetupLastVersion::get().value_or("0.0");
     sal_Int32 iLast = o3tl::toInt32(o3tl::getToken(sLastVersion, 0, '.')) * 10
                       + o3tl::toInt32(o3tl::getToken(sLastVersion, 1, '.'));
-    if (iCurrent > iLast)
-    {
-        if (aUpdateVersion)
-        { //update lastversion
-            try
-            {
-                std::shared_ptr<comphelper::ConfigurationChanges> batch(
-                    comphelper::ConfigurationChanges::create());
-                
officecfg::Setup::Product::ooSetupLastVersion::set(sSetupVersion, batch);
-                batch->commit();
-            }
-            catch (css::lang::IllegalArgumentException&)
-            { //If the value was readOnly.
-                SAL_WARN("desktop.updater", "Updating property 
ooSetupLastVersion to version "
-                                                << sSetupVersion
-                                                << " failed (read-only 
property?)");
-            }
-        }
-        return true;
-    }
-    return false;
+    return (iCurrent > iLast);
 }
 }
diff --git a/officecfg/registry/schema/org/openoffice/Office/UI/Infobar.xcs 
b/officecfg/registry/schema/org/openoffice/Office/UI/Infobar.xcs
index 6235c575c5d0..0fc4c38230af 100644
--- a/officecfg/registry/schema/org/openoffice/Office/UI/Infobar.xcs
+++ b/officecfg/registry/schema/org/openoffice/Office/UI/Infobar.xcs
@@ -48,12 +48,6 @@
         </info>
         <value>true</value>
       </prop>
-      <prop oor:name="WhatsNew" oor:type="xs:boolean" oor:nillable="false">
-        <info>
-          <desc>Whether an Infobar is shown when the major version number has 
changed</desc>
-        </info>
-        <value>true</value>
-      </prop>
       <prop oor:name="HiddenTrackChanges" oor:type="xs:boolean" 
oor:nillable="false">
         <info>
           <desc>Whether an Infobar is shown when hidden Track Changes settings 
or data are there in a document</desc>
diff --git a/officecfg/registry/schema/org/openoffice/Setup.xcs 
b/officecfg/registry/schema/org/openoffice/Setup.xcs
index 82e23f0d8d9f..44640c71797a 100644
--- a/officecfg/registry/schema/org/openoffice/Setup.xcs
+++ b/officecfg/registry/schema/org/openoffice/Setup.xcs
@@ -301,7 +301,13 @@
           </info>
           <value>0</value>
       </prop>
-    </group>
+      <prop oor:name="WhatsNew" oor:type="xs:boolean" oor:nillable="false">
+        <info>
+            <desc>Set to false to not show the WhatsNew dialog on major 
updates.</desc>
+        </info>
+        <value>true</value>
+    </prop>
+  </group>
     <group oor:name="Office">
       <!--The default must be written by the setup.-->
       <info>
diff --git a/sfx2/sdi/appslots.sdi b/sfx2/sdi/appslots.sdi
index b8d75480fef5..4b2e0a5357bf 100644
--- a/sfx2/sdi/appslots.sdi
+++ b/sfx2/sdi/appslots.sdi
@@ -147,6 +147,10 @@ interface Application
     [
         ExecMethod = MiscExec_Impl ;
     ]
+    SID_WHATSNEWDLG
+    [
+        ExecMethod = MiscExec_Impl ;
+    ]
     SID_HYPHENATIONMISSING
     [
         ExecMethod = MiscExec_Impl ;
diff --git a/sfx2/sdi/sfx.sdi b/sfx2/sdi/sfx.sdi
index 5d26a161c817..21894391ef51 100644
--- a/sfx2/sdi/sfx.sdi
+++ b/sfx2/sdi/sfx.sdi
@@ -5144,6 +5144,22 @@ SfxVoidItem WhatsNew SID_WHATSNEW
     MenuConfig = TRUE,
     GroupId = SfxGroupId::Application;
 ]
+SfxVoidItem WhatsNewDlg SID_WHATSNEWDLG
+()
+[
+    AutoUpdate = FALSE,
+    FastCall = FALSE,
+    ReadOnlyDoc = TRUE,
+    Toggle = FALSE,
+    Container = FALSE,
+    RecordAbsolute = FALSE,
+    RecordPerSet;
+
+    AccelConfig = FALSE,
+    MenuConfig = FALSE,
+    ToolBoxConfig = FALSE,
+    GroupId = SfxGroupId::Application;
+]
 SfxVoidItem HyphenationMissing SID_HYPHENATIONMISSING
 ()
 [
diff --git a/sfx2/source/appl/appserv.cxx b/sfx2/source/appl/appserv.cxx
index ecd290c4940b..5dd93dc54a25 100644
--- a/sfx2/source/appl/appserv.cxx
+++ b/sfx2/source/appl/appserv.cxx
@@ -105,6 +105,7 @@
 
 #include <comphelper/types.hxx>
 #include <officecfg/Office/Common.hxx>
+#include <officecfg/Setup.hxx>
 #include <unotools/confignode.hxx>
 #include <memory>
 
@@ -711,6 +712,15 @@ void SfxApplication::MiscExec_Impl( SfxRequest& rReq )
             bDone = true;
             break;
         }
+        case SID_WHATSNEWDLG:
+        {
+            const bool bWelcome = 
!officecfg::Setup::Product::ooSetupLastVersion::get().has_value();
+            SfxAbstractDialogFactory* pFact = 
SfxAbstractDialogFactory::Create();
+            ScopedVclPtr<VclAbstractDialog> 
pDlg(pFact->CreateWhatsNewDialog(rReq.GetFrameWeld(), bWelcome));
+            pDlg->StartExecuteAsync(nullptr);
+            bDone = true;
+            break;
+        }
 #endif
         // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
         case SID_WIDGET_TEST_DIALOG:
diff --git a/sfx2/source/dialog/infobar.cxx b/sfx2/source/dialog/infobar.cxx
index 26dfc0af26c0..58beb3892518 100644
--- a/sfx2/source/dialog/infobar.cxx
+++ b/sfx2/source/dialog/infobar.cxx
@@ -436,8 +436,6 @@ bool 
SfxInfoBarContainerWindow::isInfobarEnabled(std::u16string_view sId)
         return officecfg::Office::UI::Infobar::Enabled::GetInvolved::get();
     if (sId == u"hyphenationmissing")
         return 
officecfg::Office::UI::Infobar::Enabled::HyphenationMissing::get();
-    if (sId == u"whatsnew")
-        return officecfg::Office::UI::Infobar::Enabled::WhatsNew::get();
     if (sId == u"hiddentrackchanges")
         return 
officecfg::Office::UI::Infobar::Enabled::HiddenTrackChanges::get();
     if (sId == u"macro")
diff --git a/sfx2/source/view/viewfrm.cxx b/sfx2/source/view/viewfrm.cxx
index 20e56a6c4076..222eb0ff96ec 100644
--- a/sfx2/source/view/viewfrm.cxx
+++ b/sfx2/source/view/viewfrm.cxx
@@ -1615,23 +1615,43 @@ void SfxViewFrame::Notify( SfxBroadcaster& /*rBC*/, 
const SfxHint& rHint )
 
 #if !ENABLE_WASM_STRIP_PINGUSER
                 bool bIsHeadlessOrUITest = 
SfxApplication::IsHeadlessOrUITest(); //uitest.uicheck fails when the dialog is 
open
+                bool bIsWhatsNewShown = false; //suppress tipoftheday if 
whatsnew is shown
 
-                //what's new infobar
-                if (!bIsInfobarShown && utl::isProductVersionUpgraded(true) && 
!bIsHeadlessOrUITest)
+                //what's new dialog
+                if (utl::isProductVersionUpgraded())
                 {
-                    VclPtr<SfxInfoBarWindow> pInfoBar = 
AppendInfoBar("whatsnew", "", SfxResId(STR_WHATSNEW_TEXT), InfobarType::INFO);
-                    bIsInfobarShown = true;
-                    if (pInfoBar)
+                    const bool bShowWhatsNew = 
officecfg::Setup::Product::WhatsNew::get();
+                    const bool bIsUnitTestMode = getenv("LO_TESTNAME") != 
nullptr;
+
+                    if (!bIsHeadlessOrUITest && !bIsUnitTestMode && 
bShowWhatsNew)
+                    {
+                        const auto xCurrentFrame = 
GetFrame().GetFrameInterface();
+                        SfxUnoFrameItem aDocFrame(SID_FILLFRAME, 
xCurrentFrame);
+                        GetDispatcher()->ExecuteList(SID_WHATSNEWDLG, 
SfxCallMode::SLOT, {},
+                                                    { &aDocFrame });
+                        bIsWhatsNewShown = true;
+                    }
+
+                    //update lastversion
+                    OUString sSetupVersion = 
utl::ConfigManager::getProductVersion();
+                    try
                     {
-                        weld::Button& rWhatsNewButton = pInfoBar->addButton();
-                        
rWhatsNewButton.set_label(SfxResId(STR_WHATSNEW_BUTTON));
-                        rWhatsNewButton.connect_clicked(LINK(this, 
SfxViewFrame, WhatsNewHandler));
+                        std::shared_ptr<comphelper::ConfigurationChanges> 
batch(
+                            comphelper::ConfigurationChanges::create());
+                        
officecfg::Setup::Product::ooSetupLastVersion::set(sSetupVersion, batch);
+                        batch->commit();
+                    }
+                    catch (css::lang::IllegalArgumentException&)
+                    { //If the value was readOnly.
+                        SAL_WARN("desktop.updater", "Updating property 
ooSetupLastVersion to version "
+                                                        << sSetupVersion
+                                                        << " failed (read-only 
property?)");
                     }
                 }
 
                 // show tip-of-the-day dialog if it due, but not if there is 
the impress modal template dialog
                 // open where SdModule::ExecuteNewDocument will launch it 
instead when that dialog is dismissed
-                if (SfxApplication::IsTipOfTheDayDue() && !bIsHeadlessOrUITest 
&& !IsInModalMode())
+                if (SfxApplication::IsTipOfTheDayDue() && !bIsHeadlessOrUITest 
&& !IsInModalMode() && !bIsWhatsNewShown)
                 {
                     bool bIsBaseFormOpen = false;
 
@@ -1804,11 +1824,6 @@ void SfxViewFrame::Notify( SfxBroadcaster& /*rBC*/, 
const SfxHint& rHint )
 }
 
 #if !ENABLE_WASM_STRIP_PINGUSER
-IMPL_LINK_NOARG(SfxViewFrame, WhatsNewHandler, weld::Button&, void)
-{
-    GetDispatcher()->Execute(SID_WHATSNEW);
-}
-
 IMPL_LINK_NOARG(SfxViewFrame, GetInvolvedHandler, weld::Button&, void)
 {
     GetDispatcher()->Execute(SID_GETINVOLVED);
diff --git a/vcl/Module_vcl.mk b/vcl/Module_vcl.mk
index 35c6427b4ed1..5f627722e78f 100644
--- a/vcl/Module_vcl.mk
+++ b/vcl/Module_vcl.mk
@@ -22,6 +22,7 @@ $(eval $(call gb_Module_Module,vcl))
 ifneq ($(ENABLE_WASM_STRIP_PINGUSER),TRUE)
 $(eval $(call gb_Module_add_targets,vcl,\
     Package_tipoftheday \
+    Package_whatsnew \
 ))
 endif
 
diff --git a/vcl/Package_whatsnew.mk b/vcl/Package_whatsnew.mk
new file mode 100644
index 000000000000..6e1add206628
--- /dev/null
+++ b/vcl/Package_whatsnew.mk
@@ -0,0 +1,20 @@
+# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t; fill-column: 
100 -*-
+#
+# 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/.
+#
+
+$(eval $(call 
gb_Package_Package,whatsnew_images,$(SRCDIR)/extras/source/whatsnew))
+
+$(eval $(call 
gb_Package_add_files_with_dir,whatsnew_images,$(LIBO_SHARE_FOLDER)/whatsnew,\
+       LibreOffice.gif \
+       ODF.png \
+       Configurability.png \
+       Community.png \
+       whatsnew1.png \
+))
+
+# vim: set noet sw=4 ts=4:
\ No newline at end of file

Reply via email to