comphelper/source/misc/lok.cxx              |   19 ++++++++++
 desktop/qa/desktop_lib/test_desktop_lib.cxx |    4 +-
 desktop/source/lib/init.cxx                 |   49 ++++++++++++++++++++++++++++
 include/LibreOfficeKit/LibreOfficeKit.h     |    3 +
 include/LibreOfficeKit/LibreOfficeKit.hxx   |   11 ++++++
 include/comphelper/lok.hxx                  |    3 +
 include/sfx2/lokhelper.hxx                  |   11 ++++++
 include/sfx2/viewsh.hxx                     |   17 +++++++++
 sc/source/ui/view/viewfun6.cxx              |   19 ++++++++++
 sfx2/source/view/lokhelper.cxx              |   42 ++++++++++++++++++++++++
 sfx2/source/view/viewsh.cxx                 |    4 ++
 11 files changed, 181 insertions(+), 1 deletion(-)

New commits:
commit e2d646665c4cb4c7eeb0a73cb5f460838589bef0
Author:     Ashod Nakashian <ashod.nakash...@collabora.co.uk>
AuthorDate: Fri Dec 23 13:02:57 2022 -0500
Commit:     Andras Timar <andras.ti...@collabora.com>
CommitDate: Sun Jan 29 13:22:28 2023 +0000

    lok: support per-user timezone
    
    This adds support for user-specific timezone.
    
    When none is provided during loading, the
    system default is used.
    
    Signed-off-by: Ashod Nakashian <ashod.nakash...@collabora.co.uk>
    Change-Id: Ie863450687eb82bc475268a09c9112e9fd50020f
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/144816
    Tested-by: Jenkins CollaboraOffice <jenkinscollaboraoff...@gmail.com>
    Reviewed-by: Jan Holesovsky <ke...@collabora.com>
    (cherry picked from commit abaf8c0af1c6c7fe01276fdf2ae62419c7b0f654)
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/146211
    Tested-by: Jenkins
    Reviewed-by: Andras Timar <andras.ti...@collabora.com>

diff --git a/comphelper/source/misc/lok.cxx b/comphelper/source/misc/lok.cxx
index b11bf4e83582..1f07cd2614eb 100644
--- a/comphelper/source/misc/lok.cxx
+++ b/comphelper/source/misc/lok.cxx
@@ -8,6 +8,7 @@
  */
 
 #include <comphelper/lok.hxx>
+#include <osl/process.h>
 #include <i18nlangtag/languagetag.hxx>
 #include <sal/log.hxx>
 
@@ -255,6 +256,24 @@ bool isAllowlistedLanguage(const OUString& lang)
 #endif
 }
 
+void setTimezone(bool isSet, const OUString& rTimezone)
+{
+    if (isSet)
+    {
+        // Set the given timezone, even if empty.
+        osl_setEnvironment(OUString("TZ").pData, rTimezone.pData);
+    }
+    else
+    {
+        // Unset and empty aren't the same.
+        // When unset, it means default to the system configured timezone.
+        osl_clearEnvironment(OUString("TZ").pData);
+    }
+
+    // Update the timezone data.
+    ::tzset();
+}
+
 static void (*pStatusIndicatorCallback)(void *data, 
statusIndicatorCallbackType type, int percent, const char* pText)(nullptr);
 static void *pStatusIndicatorCallbackData(nullptr);
 
diff --git a/desktop/qa/desktop_lib/test_desktop_lib.cxx 
b/desktop/qa/desktop_lib/test_desktop_lib.cxx
index 98c734c8190a..a5560dd6be8d 100644
--- a/desktop/qa/desktop_lib/test_desktop_lib.cxx
+++ b/desktop/qa/desktop_lib/test_desktop_lib.cxx
@@ -3629,10 +3629,12 @@ void DesktopLOKTest::testABI()
     CPPUNIT_ASSERT_EQUAL(documentClassOffset(65), offsetof(struct 
_LibreOfficeKitDocumentClass, getSelectionTypeAndText));
     CPPUNIT_ASSERT_EQUAL(documentClassOffset(66), offsetof(struct 
_LibreOfficeKitDocumentClass, getDataArea));
     CPPUNIT_ASSERT_EQUAL(documentClassOffset(67), offsetof(struct 
_LibreOfficeKitDocumentClass, getEditMode));
+    CPPUNIT_ASSERT_EQUAL(documentClassOffset(68),
+                         offsetof(struct _LibreOfficeKitDocumentClass, 
setViewTimezone));
 
     // Extending is fine, update this, and add new assert for the offsetof the
     // new method
-    CPPUNIT_ASSERT_EQUAL(documentClassOffset(68), sizeof(struct 
_LibreOfficeKitDocumentClass));
+    CPPUNIT_ASSERT_EQUAL(documentClassOffset(69), sizeof(struct 
_LibreOfficeKitDocumentClass));
 }
 
 CPPUNIT_TEST_SUITE_REGISTRATION(DesktopLOKTest);
diff --git a/desktop/source/lib/init.cxx b/desktop/source/lib/init.cxx
index 97d74bc4682d..db9a9632e4c3 100644
--- a/desktop/source/lib/init.cxx
+++ b/desktop/source/lib/init.cxx
@@ -7,6 +7,7 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
  */
 
+#include <sfx2/lokhelper.hxx>
 #include <config_buildconfig.h>
 #include <config_features.h>
 
@@ -1203,6 +1204,8 @@ static bool 
doc_renderSearchResult(LibreOfficeKitDocument* pThis,
 
 static void doc_sendContentControlEvent(LibreOfficeKitDocument* pThis, const 
char* pArguments);
 
+static void doc_setViewTimezone(LibreOfficeKitDocument* pThis, int nId, const 
char* timezone);
+
 } // extern "C"
 
 namespace {
@@ -1353,6 +1356,8 @@ LibLODocument_Impl::LibLODocument_Impl(uno::Reference 
<css::lang::XComponent> xC
 
         m_pDocumentClass->sendContentControlEvent = 
doc_sendContentControlEvent;
 
+        m_pDocumentClass->setViewTimezone = doc_setViewTimezone;
+
         gDocumentClass = m_pDocumentClass;
     }
     pClass = m_pDocumentClass.get();
@@ -2600,6 +2605,27 @@ static LibreOfficeKitDocument* 
lo_documentLoadWithOptions(LibreOfficeKit* pThis,
             SvNumberFormatter::resetTheCurrencyTable();
         }
 
+        // Set the timezone, if not empty.
+        const OUString aTimezone = extractParameter(aOptions, u"Timezone");
+        if (!aTimezone.isEmpty())
+        {
+            SfxLokHelper::setDefaultTimezone(true, aTimezone);
+        }
+        else
+        {
+            // Default to the TZ envar, if set.
+            const char* tz = ::getenv("TZ");
+            if (tz)
+            {
+                SfxLokHelper::setDefaultTimezone(true,
+                                                 OStringToOUString(tz, 
RTL_TEXTENCODING_UTF8));
+            }
+            else
+            {
+                SfxLokHelper::setDefaultTimezone(false, OUString());
+            }
+        }
+
         const OUString aDeviceFormFactor = extractParameter(aOptions, 
u"DeviceFormFactor");
         SfxLokHelper::setDeviceFormFactor(aDeviceFormFactor);
 
@@ -6598,6 +6624,22 @@ static void 
doc_sendContentControlEvent(LibreOfficeKitDocument* pThis, const cha
     pDoc->executeContentControlEvent(aMap);
 }
 
+static void doc_setViewTimezone(SAL_UNUSED_PARAMETER LibreOfficeKitDocument* 
/*pThis*/, int nId,
+                                const char* pTimezone)
+{
+    comphelper::ProfileZone aZone("doc_setViewTimezone");
+
+    SolarMutexGuard aGuard;
+    SetLastExceptionMsg();
+
+    // Leave the default if we get a null timezone.
+    if (pTimezone)
+    {
+        OUString sTimezone = OStringToOUString(pTimezone, 
RTL_TEXTENCODING_UTF8);
+        SfxLokHelper::setViewTimezone(nId, true, sTimezone);
+    }
+}
+
 static char* lo_getError (LibreOfficeKit *pThis)
 {
     comphelper::ProfileZone aZone("lo_getError");
@@ -7065,8 +7107,15 @@ static int lo_initialize(LibreOfficeKit* pThis, const 
char* pAppPath, const char
     comphelper::ProfileZone aZone("lok-init");
 
     if (eStage == PRE_INIT)
+    {
         rtl_alloc_preInit(true);
 
+        // Set the default timezone to the TZ envar, if set.
+        const char* tz = ::getenv("TZ");
+        SfxLokHelper::setDefaultTimezone(!!tz, tz ? OStringToOUString(tz, 
RTL_TEXTENCODING_UTF8)
+                                                  : OUString());
+    }
+
     if (eStage != SECOND_INIT)
         comphelper::LibreOfficeKit::setActive();
 
diff --git a/include/LibreOfficeKit/LibreOfficeKit.h 
b/include/LibreOfficeKit/LibreOfficeKit.h
index 61a68f632209..74c2100ab18c 100644
--- a/include/LibreOfficeKit/LibreOfficeKit.h
+++ b/include/LibreOfficeKit/LibreOfficeKit.h
@@ -493,6 +493,9 @@ struct _LibreOfficeKitDocumentClass
     /// @see lok::Document::getEditMode().
     int (*getEditMode) (LibreOfficeKitDocument* pThis);
 
+    /// @see lok::Document::setViewTimezone().
+    void (*setViewTimezone) (LibreOfficeKitDocument* pThis, int nId, const 
char* timezone);
+
 #endif // defined LOK_USE_UNSTABLE_API || defined LIBO_INTERNAL_ONLY
 };
 
diff --git a/include/LibreOfficeKit/LibreOfficeKit.hxx 
b/include/LibreOfficeKit/LibreOfficeKit.hxx
index d70e4eb44d39..2ac398edd497 100644
--- a/include/LibreOfficeKit/LibreOfficeKit.hxx
+++ b/include/LibreOfficeKit/LibreOfficeKit.hxx
@@ -875,6 +875,17 @@ public:
         mpDoc->pClass->sendContentControlEvent(mpDoc, pArguments);
     }
 
+    /**
+     * Set the timezone of the window with the specified nId.
+     *
+     * @param nId a view ID, returned by createView().
+     * @param timezone a timezone in the tzfile(5) format (e.g. 
Pacific/Auckland).
+     */
+    void setViewTimezone(int nId, const char* timezone)
+    {
+        mpDoc->pClass->setViewTimezone(mpDoc, nId, timezone);
+    }
+
 #endif // defined LOK_USE_UNSTABLE_API || defined LIBO_INTERNAL_ONLY
 };
 
diff --git a/include/comphelper/lok.hxx b/include/comphelper/lok.hxx
index 66784e8e4892..4cfdb70a09d3 100644
--- a/include/comphelper/lok.hxx
+++ b/include/comphelper/lok.hxx
@@ -102,6 +102,9 @@ COMPHELPER_DLLPUBLIC const LanguageTag& getLanguageTag();
 /// If the language name should be used for this LOK instance.
 COMPHELPER_DLLPUBLIC bool isAllowlistedLanguage(const OUString& lang);
 
+/// Update the current LOK's timezone.
+COMPHELPER_DLLPUBLIC void setTimezone(bool isSet, const OUString& rTimezone);
+
 // Status indicator handling. Even if in theory there could be several status 
indicators active at
 // the same time, in practice there is only one at a time, so we don't handle 
any identification of
 // status indicator in this API.
diff --git a/include/sfx2/lokhelper.hxx b/include/sfx2/lokhelper.hxx
index c3b05b7927e5..90ddd52d01a4 100644
--- a/include/sfx2/lokhelper.hxx
+++ b/include/sfx2/lokhelper.hxx
@@ -91,6 +91,17 @@ public:
     /// Set the device form factor that should be used for a new view.
     static void setDeviceFormFactor(std::u16string_view rDeviceFormFactor);
 
+    /// Set timezone of the given view.
+    /// @isSet true to use @rTimezone, even if it's empty. Otherwise, no 
timezone.
+    /// @rTimezone the value to set (which could be empty).
+    static void setDefaultTimezone(bool isSet, const OUString& rTimezone);
+    /// Get timezone of the given view. See @setDefaultTimezone.
+    static std::pair<bool, OUString> getDefaultTimezone();
+    /// Set the timezone of the given view.
+    static void setViewTimezone(int nId, bool isSet, const OUString& 
rTimezone);
+    /// Get the timezone of the given view.
+    static std::pair<bool, OUString> getViewTimezone(int nId);
+
     /// Iterate over any view shell, except pThisViewShell, passing it to the 
f function.
     template<typename ViewShellType, typename FunctionType>
     static void forEachOtherView(ViewShellType* pThisViewShell, FunctionType 
f);
diff --git a/include/sfx2/viewsh.hxx b/include/sfx2/viewsh.hxx
index 8efa98a13e4f..a948f0f5baea 100644
--- a/include/sfx2/viewsh.hxx
+++ b/include/sfx2/viewsh.hxx
@@ -171,6 +171,8 @@ friend class SfxPrinterController;
     LanguageTag                 maLOKLocale;
     LOKDeviceFormFactor         maLOKDeviceFormFactor;
     std::unordered_set<OUString>    mvLOKBlockedCommandList;
+    OUString maLOKTimezone;
+    bool maLOKIsTimezoneSet;
 
     /// Used to set the DocId at construction time. See SetCurrentDocId.
     static ViewShellDocId       mnCurrentDocId;
@@ -403,6 +405,21 @@ public:
     /// Get the LibreOfficeKit language of this view.
     const LanguageTag& GetLOKLanguageTag() const { return maLOKLanguageTag; }
 
+    /// Get the LibreOfficeKit timezone of this view. See @SetLOKTimezone.
+    std::pair<bool, OUString> GetLOKTimezone() const
+    {
+        return { maLOKIsTimezoneSet, maLOKTimezone };
+    }
+
+    /// Set the LibreOfficeKit timezone of this view.
+    /// @isSet true to use @rTimezone, even if it's empty. Otherwise, no 
timezone.
+    /// @rTimezone the value to set (which could be empty).
+    void SetLOKTimezone(bool isSet, const OUString& rTimezone)
+    {
+        maLOKIsTimezoneSet = isSet;
+        maLOKTimezone = rTimezone;
+    }
+
     /// Set the LibreOfficeKit locale of this view.
     void SetLOKLocale(const OUString& rBcp47LanguageTag);
     /// Get the LibreOfficeKit locale of this view.
diff --git a/sc/source/ui/view/viewfun6.cxx b/sc/source/ui/view/viewfun6.cxx
index 160ee6ce5882..2a68f730b9bf 100644
--- a/sc/source/ui/view/viewfun6.cxx
+++ b/sc/source/ui/view/viewfun6.cxx
@@ -21,6 +21,7 @@
 #include <svx/svdocapt.hxx>
 #include <sfx2/bindings.hxx>
 #include <sfx2/dispatch.hxx>
+#include <sfx2/lokhelper.hxx>
 #include <svl/stritem.hxx>
 #include <svl/numformat.hxx>
 #include <svl/zforlist.hxx>
@@ -47,6 +48,7 @@
 #include <tabvwsh.hxx>
 #include <scmod.hxx>
 #include <postit.hxx>
+#include <comphelper/scopeguard.hxx>
 
 #include <vector>
 
@@ -286,6 +288,23 @@ void ScViewFunc::InsertCurrentTime(SvNumFormatType 
nReqFmt, const OUString& rUnd
     const SvNumFormatType nCurNumFormatType = (pCurNumFormatEntry ?
             pCurNumFormatEntry->GetMaskedType() : SvNumFormatType::UNDEFINED);
 
+    const int nView(comphelper::LibreOfficeKit::isActive() ? 
SfxLokHelper::getView() : -1);
+    if (nView >= 0)
+    {
+        const auto [isTimezoneSet, aTimezone] = 
SfxLokHelper::getViewTimezone(nView);
+        comphelper::LibreOfficeKit::setTimezone(isTimezoneSet, aTimezone);
+    }
+
+    comphelper::ScopeGuard aAutoUserTimezone(
+        [nView]()
+        {
+            if (nView >= 0)
+            {
+                const auto [isTimezoneSet, aTimezone] = 
SfxLokHelper::getDefaultTimezone();
+                comphelper::LibreOfficeKit::setTimezone(isTimezoneSet, 
aTimezone);
+            }
+        });
+
     if (bInputMode)
     {
         double fVal = 0.0;
diff --git a/sfx2/source/view/lokhelper.cxx b/sfx2/source/view/lokhelper.cxx
index 794dcc00b300..53c2abace8b5 100644
--- a/sfx2/source/view/lokhelper.cxx
+++ b/sfx2/source/view/lokhelper.cxx
@@ -76,6 +76,8 @@ namespace
 LanguageTag g_defaultLanguageTag("en-US", true);
 LanguageTag g_loadLanguageTag("en-US", true); //< The language used to load.
 LOKDeviceFormFactor g_deviceFormFactor = LOKDeviceFormFactor::UNKNOWN;
+bool g_isDefaultTimezoneSet = false;
+OUString g_DefaultTimezone;
 }
 
 int SfxLokHelper::createView(SfxViewFrame* pViewFrame, ViewShellDocId docId)
@@ -339,6 +341,46 @@ void SfxLokHelper::setDeviceFormFactor(std::u16string_view 
rDeviceFormFactor)
         g_deviceFormFactor = LOKDeviceFormFactor::UNKNOWN;
 }
 
+void SfxLokHelper::setDefaultTimezone(bool isSet, const OUString& rTimezone)
+{
+    g_isDefaultTimezoneSet = isSet;
+    g_DefaultTimezone = rTimezone;
+}
+
+std::pair<bool, OUString> SfxLokHelper::getDefaultTimezone()
+{
+    return { g_isDefaultTimezoneSet, g_DefaultTimezone };
+}
+
+void SfxLokHelper::setViewTimezone(int nId, bool isSet, const OUString& 
rTimezone)
+{
+    std::vector<SfxViewShell*>& rViewArr = SfxGetpApp()->GetViewShells_Impl();
+
+    for (SfxViewShell* pViewShell : rViewArr)
+    {
+        if (pViewShell->GetViewShellId() == ViewShellId(nId))
+        {
+            pViewShell->SetLOKTimezone(isSet, rTimezone);
+            return;
+        }
+    }
+}
+
+std::pair<bool, OUString> SfxLokHelper::getViewTimezone(int nId)
+{
+    std::vector<SfxViewShell*>& rViewArr = SfxGetpApp()->GetViewShells_Impl();
+
+    for (SfxViewShell* pViewShell : rViewArr)
+    {
+        if (pViewShell->GetViewShellId() == ViewShellId(nId))
+        {
+            return pViewShell->GetLOKTimezone();
+        }
+    }
+
+    return {};
+}
+
 /*
 * Used for putting a whole JSON string into a string value
 * e.g { key: "{JSON}" }
diff --git a/sfx2/source/view/viewsh.cxx b/sfx2/source/view/viewsh.cxx
index 1d494878a0a2..cd4ffe676f2b 100644
--- a/sfx2/source/view/viewsh.cxx
+++ b/sfx2/source/view/viewsh.cxx
@@ -1083,6 +1083,10 @@ SfxViewShell::SfxViewShell
         maLOKLanguageTag = SfxLokHelper::getDefaultLanguage();
         maLOKLocale = SfxLokHelper::getDefaultLanguage();
 
+        const auto [isTimezoneSet, aTimezone] = 
SfxLokHelper::getDefaultTimezone();
+        maLOKIsTimezoneSet = isTimezoneSet;
+        maLOKTimezone = aTimezone;
+
         maLOKDeviceFormFactor = SfxLokHelper::getDeviceFormFactor();
 
         vcl::Window* pFrameWin = pViewFrame->GetWindow().GetFrameWindow();

Reply via email to