[Libreoffice-commits] core.git: Branch 'private/jmux/scheduler-fixes' - 6 commits - connectivity/source sc/qa sc/source svx/source sw/source vcl/inc vcl/osx vcl/source vcl/win

Jan-Marek Glogowski glogow at fbihome.de
Fri Oct 6 20:20:48 UTC 2017


Rebased ref, commits from common ancestor:
commit de21edd69c985de4be8ee637cc61824e87e53d2a
Author: Jan-Marek Glogowski <glogow at fbihome.de>
Date:   Fri Sep 29 22:24:15 2017 +0200

    WIP Fix unprocessed shutdown events
    
    DO NOT MERGE!
    
    This is just a test patch, since I can't reproduce the
    Jenkins failures locally. It's not "make check" tested,
    just "make vcl".
    
    This fixes multiple problems, which I missed.
    
    We're not interested in WM_TIMER events, but in active
    SAL_MSG_TIMER_CALLBACK, which is indicated by PollForMessage().
    
    This includes a revert of "tdf#38915: don't wait on message queue
    if application already has quit.", which is commited as
    f054b9187155bc32b7d06808aea87127cb0a3a4f.
    
    We can't ignore the wait flag, just because the application will
    quit, as we have to deliver the expected event announced by
    pTimer->PollForMessage().
    
    And we don't try to "clean" the message queue, as invalid events
    are simply identified by there version ID.
    
    On Mac we can probably drop the workaround. We can't wait for a
    timer event in a redirected dispatch_async, for whatever reason.
    
    Change-Id: If806d41c6fcfce10b0c4c7fdcf1df5df6ac16a1d

diff --git a/vcl/inc/win/saltimer.h b/vcl/inc/win/saltimer.h
index 5ad6a1718f19..532765e050f0 100644
--- a/vcl/inc/win/saltimer.h
+++ b/vcl/inc/win/saltimer.h
@@ -34,7 +34,7 @@ class WinSalTimer final : public SalTimer, protected VersionedEvent
 
     void ImplStart( sal_uIntPtr nMS );
     void ImplStop();
-    void ImplEmitTimerCallback();
+    void ImplHandleTimerEvent( WPARAM aWPARAM );
 
 public:
     WinSalTimer();
@@ -43,16 +43,9 @@ public:
     virtual void Start(sal_uIntPtr nMS) override;
     virtual void Stop() override;
 
-    inline bool IsValidWPARAM( WPARAM wParam ) const;
-
     inline bool PollForMessage() const;
 };
 
-inline bool WinSalTimer::IsValidWPARAM( WPARAM aWPARAM ) const
-{
-    return IsValidEventVersion( static_cast<sal_Int32>( aWPARAM ) );
-}
-
 inline bool WinSalTimer::PollForMessage() const
 {
     return m_bPollForMessage;
diff --git a/vcl/osx/salinst.cxx b/vcl/osx/salinst.cxx
index d475f30275b0..0334087f57cf 100644
--- a/vcl/osx/salinst.cxx
+++ b/vcl/osx/salinst.cxx
@@ -570,10 +570,10 @@ bool AquaSalInstance::DoYield(bool bWait, bool bHandleAllCurrentEvents)
         // handle available events
         NSEvent* pEvent = nil;
         NSTimeInterval now = [[NSProcessInfo processInfo] systemUptime];
+        AquaSalInstance *pInst = GetSalData()->mpInstance;
         do
         {
             SolarMutexReleaser aReleaser;
-
 SAL_WNODEPRECATED_DECLARATIONS_PUSH
     // 'NSAnyEventMask' is deprecated: first deprecated in macOS 10.12
             pEvent = [NSApp nextEventMatchingMask: NSAnyEventMask
@@ -591,6 +591,8 @@ SAL_WNODEPRECATED_DECLARATIONS_POP
 
             [NSApp updateWindows];
 
+            if ( AquaSalInstance::AnyInput( VclInputFlags::TIMER ) && !pInst->mbNoYieldLock && !bHadEvent )
+                continue;
             if ( !bHandleAllCurrentEvents || !pEvent || now < [pEvent timestamp] )
                 break;
         }
@@ -618,7 +620,7 @@ SAL_WNODEPRECATED_DECLARATIONS_POP
         }
 
         // collect update rectangles
-        for( auto pSalFrame : GetSalData()->mpInstance->getFrames() )
+        for( auto pSalFrame : pInst->getFrames() )
         {
             AquaSalFrame* pFrame = static_cast<AquaSalFrame*>( pSalFrame );
             if( pFrame->mbShown && ! pFrame->maInvalidRect.IsEmpty() )
diff --git a/vcl/osx/saltimer.cxx b/vcl/osx/saltimer.cxx
index 877fdfae85b5..e6336fbedd6e 100644
--- a/vcl/osx/saltimer.cxx
+++ b/vcl/osx/saltimer.cxx
@@ -44,30 +44,8 @@ SAL_WNODEPRECATED_DECLARATIONS_POP
                                subtype: nEventId
                                data1: nUserData
                                data2: 0];
-    assert( pEvent );
     if ( nil == pEvent )
-        return;
-    if ( NO == bAtStart )
-    {
-        // nextEventMatchingMask has to run in the main thread!
-        assert([NSThread isMainThread]);
-
-        // Posting an event to the end of an empty queue fails,
-        // so we peek the queue and post to the start, if empty.
-        // Some Qt bugs even indicate nextEvent without dequeue
-        // sometimes blocks, so we dequeue and re-add the event.
-SAL_WNODEPRECATED_DECLARATIONS_PUSH
-// 'NSAnyEventMask' is deprecated: first deprecated in macOS 10.12
-        NSEvent* pPeekEvent = [NSApp nextEventMatchingMask: NSAnyEventMask
-SAL_WNODEPRECATED_DECLARATIONS_POP
-                               untilDate: nil
-                               inMode: NSDefaultRunLoopMode
-                               dequeue: YES];
-        if ( nil == pPeekEvent )
-            bAtStart = YES;
-        else
-            [NSApp postEvent: pPeekEvent atStart: YES];
-    }
+        std::abort();
     [NSApp postEvent: pEvent atStart: bAtStart];
 }
 
diff --git a/vcl/source/app/scheduler.cxx b/vcl/source/app/scheduler.cxx
index 8fd26ec79a55..5fe9e0b302ab 100644
--- a/vcl/source/app/scheduler.cxx
+++ b/vcl/source/app/scheduler.cxx
@@ -172,7 +172,7 @@ void Scheduler::ImplDeInitScheduler()
     SAL_INFO( "vcl.schedule.deinit", "DeInit the scheduler - finished" );
     SAL_WARN_IF( 0 != nActiveTasks, "vcl.schedule.deinit", "DeInit active tasks: "
         << nActiveTasks << " (ignored: " << nIgnoredTasks << ")" );
-//    assert( nIgnoredTasks == nActiveTasks );
+    assert( nIgnoredTasks == nActiveTasks );
 #endif
 
     rSchedCtx.mpFirstSchedulerData = nullptr;
diff --git a/vcl/win/app/salinst.cxx b/vcl/win/app/salinst.cxx
index a0a323b2d037..1eb8b4a04bfb 100644
--- a/vcl/win/app/salinst.cxx
+++ b/vcl/win/app/salinst.cxx
@@ -514,8 +514,7 @@ static bool ImplSalYield( bool bWait, bool bHandleAllCurrentEvents )
     if ( bHandleAllCurrentEvents )
         nLastTicks = nCurTicks;
 
-    // Also check that we don't wait when application already has quit
-    if ( bWait && !bWasMsg && !pSVData->maAppData.mbAppQuit )
+    if ( bWait && !bWasMsg )
     {
         if ( GetMessageW( &aMsg, nullptr, 0, 0 ) )
         {
@@ -540,8 +539,6 @@ bool WinSalInstance::DoYield(bool bWait, bool bHandleAllCurrentEvents)
     SolarMutexReleaser aReleaser;
     if ( !IsMainThread() )
     {
-        // If you change the SendMessageW function, you might need to update
-        // the PeekMessage( ... PM_QS_POSTMESSAGE) calls!
         bDidWork = SendMessageW( mhComWnd, SAL_MSG_THREADYIELD,
                                  (WPARAM) false, (LPARAM) bHandleAllCurrentEvents );
         if ( !bDidWork && bWait )
@@ -659,17 +656,7 @@ LRESULT CALLBACK SalComWndProc( HWND, UINT nMsg, WPARAM wParam, LPARAM lParam, i
         {
             WinSalTimer *const pTimer = static_cast<WinSalTimer*>( ImplGetSVData()->maSchedCtx.mpSalTimer );
             assert( pTimer != nullptr );
-            MSG aMsg;
-            bool bValidMSG = pTimer->IsValidWPARAM( wParam );
-            // PM_QS_POSTMESSAGE is needed, so we don't process the SendMessage from DoYield!
-            while ( PeekMessageW(&aMsg, pInst->mhComWnd, SAL_MSG_TIMER_CALLBACK,
-                                 SAL_MSG_TIMER_CALLBACK, PM_REMOVE | PM_NOYIELD | PM_QS_POSTMESSAGE) )
-            {
-                assert( !bValidMSG && "Unexpected non-last valid message" );
-                bValidMSG = pTimer->IsValidWPARAM( aMsg.wParam );
-            }
-            if ( bValidMSG )
-                pTimer->ImplEmitTimerCallback();
+            pTimer->ImplHandleTimerEvent( wParam );
             break;
         }
     }
@@ -700,6 +687,13 @@ bool WinSalInstance::AnyInput( VclInputFlags nType )
 {
     MSG aMsg;
 
+    if ( nType & VclInputFlags::TIMER )
+    {
+        const WinSalTimer* pTimer = static_cast<WinSalTimer*>( ImplGetSVData()->maSchedCtx.mpSalTimer );
+        if ( pTimer && pTimer->PollForMessage() )
+            return true;
+    }
+
     if ( (nType & VCL_INPUT_ANY) == VCL_INPUT_ANY )
     {
         // revert bugfix for #108919# which never reported timeouts when called from the timer handler
@@ -756,15 +750,6 @@ bool WinSalInstance::AnyInput( VclInputFlags nType )
                 return true;
         }
 
-        if ( nType & VclInputFlags::TIMER )
-        {
-            // Test for timer input
-            if ( PeekMessageW( &aMsg, nullptr, WM_TIMER, WM_TIMER,
-                                  PM_NOREMOVE | PM_NOYIELD ) )
-                return true;
-
-        }
-
         if ( nType & VclInputFlags::OTHER )
         {
             // Test for any input
diff --git a/vcl/win/app/saltimer.cxx b/vcl/win/app/saltimer.cxx
index 93b93fbb832f..8354886fbcd6 100644
--- a/vcl/win/app/saltimer.cxx
+++ b/vcl/win/app/saltimer.cxx
@@ -50,12 +50,6 @@ void WinSalTimer::ImplStop()
     // Keep both after DeleteTimerQueueTimer, because they are set in SalTimerProc
     InvalidateEvent();
     m_bPollForMessage = false;
-
-    // remove as many pending SAL_MSG_TIMER_CALLBACK messages as possible
-    // PM_QS_POSTMESSAGE is needed, so we don't process the SendMessage from DoYield!
-    MSG aMsg;
-    while ( PeekMessageW(&aMsg, pInst->mhComWnd, SAL_MSG_TIMER_CALLBACK,
-                         SAL_MSG_TIMER_CALLBACK, PM_REMOVE | PM_NOYIELD | PM_QS_POSTMESSAGE) );
 }
 
 void WinSalTimer::ImplStart( sal_uLong nMS )
@@ -75,9 +69,7 @@ void WinSalTimer::ImplStart( sal_uLong nMS )
     // probably WT_EXECUTEONLYONCE is not needed, but it enforces Period
     // to be 0 and should not hurt; also see
     // https://www.microsoft.com/msj/0499/pooling/pooling.aspx
-    CreateTimerQueueTimer(&m_nTimerId, nullptr, SalTimerProc,
-                          reinterpret_cast<void*>(
-                              sal_IntPtr(GetNextEventVersion())),
+    CreateTimerQueueTimer(&m_nTimerId, nullptr, SalTimerProc, this,
                           nMS, 0, WT_EXECUTEINTIMERTHREAD | WT_EXECUTEONLYONCE);
 }
 
@@ -126,12 +118,11 @@ void CALLBACK SalTimerProc(PVOID data, BOOLEAN)
 {
     __try
     {
-        // always post message when the timer fires, we will remove the ones
-        // that happened during execution of the callback later directly from
-        // the message queue
-        BOOL const ret = PostMessageW(GetSalData()->mpInstance->mhComWnd,
-                                      SAL_MSG_TIMER_CALLBACK,
-                                      reinterpret_cast<WPARAM>(data), 0);
+        WinSalTimer *pTimer = reinterpret_cast<WinSalTimer*>( data );
+        pTimer->m_bPollForMessage = true;
+        BOOL const ret = PostMessageW(
+            GetSalData()->mpInstance->mhComWnd, SAL_MSG_TIMER_CALLBACK,
+            static_cast<WPARAM>(pTimer->GetNextEventVersion()), 0 );
 #if OSL_DEBUG_LEVEL > 0
         if (0 == ret) // SEH prevents using SAL_WARN here?
             fputs("ERROR: PostMessage() failed!\n", stderr);
@@ -142,8 +133,12 @@ void CALLBACK SalTimerProc(PVOID data, BOOLEAN)
     }
 }
 
-void WinSalTimer::ImplEmitTimerCallback()
+void WinSalTimer::ImplHandleTimerEvent( WPARAM aWPARAM )
 {
+    assert( aWPARAM <= SAL_MAX_INT32 );
+    if ( !IsValidEventVersion( static_cast<sal_Int32>( aWPARAM ) ) )
+        return;
+
     // Test for MouseLeave
     SalTestMouseLeave();
 
commit ad439ded005cffd525ffe874f535fca7a4da1f49
Author: Tamás Zolnai <tamas.zolnai at collabora.com>
Date:   Fri Oct 6 20:35:54 2017 +0200

    tdf#112946: Pivot table: Missing selector for a row field after RT in Calc
    
    We need to explicitly set compact flags to false, since true is
    the default. It seems MSO prefers compact mode, when the file
    contains colliding mode flags.
    
    Change-Id: Ib311f1cf44345be294e6c6607c227c2baa0fb693
    Reviewed-on: https://gerrit.libreoffice.org/43210
    Tested-by: Jenkins <ci at libreoffice.org>
    Reviewed-by: Tamás Zolnai <tamas.zolnai at collabora.com>

diff --git a/sc/qa/unit/data/xlsx/pivottable_outline_mode.xlsx b/sc/qa/unit/data/xlsx/pivottable_outline_mode.xlsx
new file mode 100755
index 000000000000..6b575c0af7b3
Binary files /dev/null and b/sc/qa/unit/data/xlsx/pivottable_outline_mode.xlsx differ
diff --git a/sc/qa/unit/subsequent_export-test.cxx b/sc/qa/unit/subsequent_export-test.cxx
index d0596bdf06ef..21837ff11152 100644
--- a/sc/qa/unit/subsequent_export-test.cxx
+++ b/sc/qa/unit/subsequent_export-test.cxx
@@ -226,6 +226,7 @@ public:
     void testPivotTableBoolFieldFilterXLSX();
     void testPivotTableRowColPageFieldFilterXLSX();
     void testPivotTableErrorItemFilterXLSX();
+    void testPivotTableOutlineModeXLSX();
 
     CPPUNIT_TEST_SUITE(ScExportTest);
     CPPUNIT_TEST(test);
@@ -346,6 +347,7 @@ public:
     CPPUNIT_TEST(testPivotTableBoolFieldFilterXLSX);
     CPPUNIT_TEST(testPivotTableRowColPageFieldFilterXLSX);
     CPPUNIT_TEST(testPivotTableErrorItemFilterXLSX);
+    CPPUNIT_TEST(testPivotTableOutlineModeXLSX);
 
     CPPUNIT_TEST_SUITE_END();
 
@@ -5251,6 +5253,23 @@ void ScExportTest::testPivotTableErrorItemFilterXLSX()
     xDocSh->DoClose();
 }
 
+void ScExportTest::testPivotTableOutlineModeXLSX()
+{
+    ScDocShellRef xShell = loadDoc("pivottable_outline_mode.", FORMAT_XLSX);
+    CPPUNIT_ASSERT(xShell.is());
+
+    std::shared_ptr<utl::TempFile> pXPathFile = ScBootstrapFixture::exportTo(&(*xShell), FORMAT_XLSX);
+    xmlDocPtr pTable = XPathHelper::parseExport(pXPathFile, m_xSFactory, "xl/pivotTables/pivotTable1.xml");
+    CPPUNIT_ASSERT(pTable);
+
+    // Next to the outline flags, compact flags also should be set (true is the default)
+    assertXPath(pTable, "/x:pivotTableDefinition", "outline", "1");
+    assertXPath(pTable, "/x:pivotTableDefinition", "outlineData", "1");
+    assertXPath(pTable, "/x:pivotTableDefinition", "compact", "0");
+    assertXPath(pTable, "/x:pivotTableDefinition", "compactData", "0");
+    assertXPath(pTable, "/x:pivotTableDefinition/x:pivotFields/x:pivotField[1]", "compact", "0");
+}
+
 CPPUNIT_TEST_SUITE_REGISTRATION(ScExportTest);
 
 CPPUNIT_PLUGIN_IMPLEMENT();
diff --git a/sc/source/filter/excel/xepivotxml.cxx b/sc/source/filter/excel/xepivotxml.cxx
index 9bc8836a57f4..6f9f7106f997 100644
--- a/sc/source/filter/excel/xepivotxml.cxx
+++ b/sc/source/filter/excel/xepivotxml.cxx
@@ -674,6 +674,8 @@ void XclExpXmlPivotTables::SavePivotTableXml( XclExpXmlStream& rStrm, const ScDP
         XML_indent, ToPsz10(false),
         XML_outline, ToPsz10(true),
         XML_outlineData, ToPsz10(true),
+        XML_compact, ToPsz10(false),
+        XML_compactData, ToPsz10(false),
         FSEND);
 
     // NB: Excel's range does not include page field area (if any).
@@ -723,6 +725,7 @@ void XclExpXmlPivotTables::SavePivotTableXml( XclExpXmlStream& rStrm, const ScDP
         {
             pPivotStrm->singleElement(XML_pivotField,
                 XML_showAll, ToPsz10(false),
+                XML_compact, ToPsz10(false),
                 FSEND);
             continue;
         }
@@ -733,6 +736,7 @@ void XclExpXmlPivotTables::SavePivotTableXml( XclExpXmlStream& rStrm, const ScDP
         {
             pPivotStrm->singleElement(XML_pivotField,
                 XML_showAll, ToPsz10(false),
+                XML_compact, ToPsz10(false),
                 FSEND);
             continue;
         }
@@ -742,6 +746,7 @@ void XclExpXmlPivotTables::SavePivotTableXml( XclExpXmlStream& rStrm, const ScDP
             pPivotStrm->singleElement(XML_pivotField,
                 XML_dataField, ToPsz10(true),
                 XML_showAll, ToPsz10(false),
+                XML_compact, ToPsz10(false),
                 FSEND);
 
             continue;
@@ -810,6 +815,7 @@ void XclExpXmlPivotTables::SavePivotTableXml( XclExpXmlStream& rStrm, const ScDP
         if (!bHasDefaultSubtotal)
             pAttList->add(XML_defaultSubtotal, ToPsz10(false));
 
+        pAttList->add( XML_compact, ToPsz10(false));
         sax_fastparser::XFastAttributeListRef xAttributeList(pAttList);
         pPivotStrm->startElement(XML_pivotField, xAttributeList);
 
commit 05c704d3bea7f9a7ec51ac28d4d55ba8068f2da5
Author: Michael Stahl <mstahl at redhat.com>
Date:   Fri Oct 6 21:39:24 2017 +0200

    sw: fix infinite grammar checking idle loop
    
    The grammar checker always wants to be started in DoIdleJobs(),
    even if all paragraphs are already marked as checked.
    
    This is because there is currently no call anywhere of
    SwRootFrame::SetNeedGrammarCheck(false) to reset the flag
    and prevent DoIdleJobs from trying to start the grammar checker.
    
    This call was already there before but was removed without
    any justification in commit 9160fe814a46e93da6907e169ce9d58e46fa37f2.
    
    This has become an infinite loop in several Junit tests with commit
    53da556c600fa82ba84bc7fdce6a594b43f2b097.
    
    Change-Id: Ibe7ad93442070aac0577725d044281912307d9e8

diff --git a/sw/source/core/doc/docnew.cxx b/sw/source/core/doc/docnew.cxx
index 9e2a82d3083c..d414b920aef0 100644
--- a/sw/source/core/doc/docnew.cxx
+++ b/sw/source/core/doc/docnew.cxx
@@ -172,7 +172,14 @@ bool SwDoc::StartGrammarChecking( bool bSkipStart )
             {
                 bStarted = true;
                 if ( !bSkipStart )
+                {
+                    for (auto pLayout : GetAllLayouts())
+                    {   // we're starting it now, don't start grammar checker
+                        // again until the user modifies the document
+                        pLayout->SetNeedGrammarCheck(false);
+                    }
                     xGCIterator->startProofreading( xDoc, xFPIP );
+                }
             }
         }
     }
commit 3ee1c87e6cf3fac38e1c7666c4c7ea357f26bec8
Author: Noel Grandin <noel.grandin at collabora.co.uk>
Date:   Fri Oct 6 15:57:25 2017 +0200

    use more rtl::Reference in SdrLightEmbeddedClient_Impl
    
    instead of manual ref counting
    
    Change-Id: Ia07d5411c45d24934a619016cd8dbfb1fac6cc4b
    Reviewed-on: https://gerrit.libreoffice.org/43204
    Tested-by: Jenkins <ci at libreoffice.org>
    Reviewed-by: Noel Grandin <noel.grandin at collabora.co.uk>

diff --git a/svx/source/svdraw/svdoole2.cxx b/svx/source/svdraw/svdoole2.cxx
index 02a41ca31e0a..d2b0470196b7 100644
--- a/svx/source/svdraw/svdoole2.cxx
+++ b/svx/source/svdraw/svdoole2.cxx
@@ -120,7 +120,6 @@ class SdrLightEmbeddedClient_Impl : public ::cppu::WeakImplHelper
 
 public:
     explicit SdrLightEmbeddedClient_Impl( SdrOle2Obj* pObj );
-    void Release();
 
     void SetSizeScale( const Fraction& aScaleWidth, const Fraction& aScaleHeight )
     {
@@ -185,16 +184,6 @@ void SAL_CALL SdrLightEmbeddedClient_Impl::changingState( const css::lang::Event
 {
 }
 
-void SdrLightEmbeddedClient_Impl::Release()
-{
-    {
-        SolarMutexGuard aGuard;
-        mpObj = nullptr;
-    }
-
-    release();
-}
-
 void SAL_CALL SdrLightEmbeddedClient_Impl::stateChanged( const css::lang::EventObject& /*aEvent*/, ::sal_Int32 nOldState, ::sal_Int32 nNewState )
 {
     SolarMutexGuard aGuard;
@@ -595,9 +584,9 @@ public:
     svt::EmbeddedObjectRef mxObjRef;
 
     std::unique_ptr<Graphic> mxGraphic;
-    OUString maProgName;
+    OUString        maProgName;
     OUString        aPersistName;       // name of object in persist
-    SdrLightEmbeddedClient_Impl* pLightClient; // must be registered as client only using AddOwnLightClient() call
+    rtl::Reference<SdrLightEmbeddedClient_Impl> mxLightClient; // must be registered as client only using AddOwnLightClient() call
 
     bool mbFrame:1; // Due to compatibility at SdrTextObj for now
     bool mbSuppressSetVisAreaSize:1; // #i118524#
@@ -612,7 +601,6 @@ public:
     rtl::Reference<SvxUnoShapeModifyListener> mxModifyListener;
 
     explicit SdrOle2ObjImpl( bool bFrame ) :
-        pLightClient (nullptr),
         mbFrame(bFrame),
         mbSuppressSetVisAreaSize(false),
         mbTypeAsked(false),
@@ -626,7 +614,6 @@ public:
 
     SdrOle2ObjImpl( bool bFrame, const svt::EmbeddedObjectRef& rObjRef ) :
         mxObjRef(rObjRef),
-        pLightClient (nullptr),
         mbFrame(bFrame),
         mbSuppressSetVisAreaSize(false),
         mbTypeAsked(false),
@@ -713,11 +700,7 @@ SdrOle2Obj::~SdrOle2Obj()
 
     DisconnectFileLink_Impl();
 
-    if ( mpImpl->pLightClient )
-    {
-        mpImpl->pLightClient->Release();
-        mpImpl->pLightClient = nullptr;
-    }
+    mpImpl->mxLightClient.clear();
 }
 
 void SdrOle2Obj::SetAspect( sal_Int64 nAspect )
@@ -962,14 +945,11 @@ void SdrOle2Obj::Connect_Impl()
 
             if ( mpImpl->mxObjRef.is() )
             {
-                if ( !mpImpl->pLightClient )
-                {
-                    mpImpl->pLightClient = new SdrLightEmbeddedClient_Impl( this );
-                    mpImpl->pLightClient->acquire();
-                }
+                if ( !mpImpl->mxLightClient.is() )
+                    mpImpl->mxLightClient = new SdrLightEmbeddedClient_Impl( this );
 
-                mpImpl->mxObjRef->addStateChangeListener( mpImpl->pLightClient );
-                mpImpl->mxObjRef->addEventListener( uno::Reference< document::XEventListener >( mpImpl->pLightClient ) );
+                mpImpl->mxObjRef->addStateChangeListener( mpImpl->mxLightClient.get() );
+                mpImpl->mxObjRef->addEventListener( uno::Reference< document::XEventListener >( mpImpl->mxLightClient.get() ) );
 
                 if ( mpImpl->mxObjRef->getCurrentState() != embed::EmbedStates::LOADED )
                     GetSdrGlobalData().GetOLEObjCache().InsertObj(this);
@@ -1119,10 +1099,10 @@ void SdrOle2Obj::Disconnect_Impl()
             }
         }
 
-        if ( mpImpl->mxObjRef.is() && mpImpl->pLightClient )
+        if ( mpImpl->mxObjRef.is() && mpImpl->mxLightClient.is() )
         {
-            mpImpl->mxObjRef->removeStateChangeListener ( mpImpl->pLightClient );
-            mpImpl->mxObjRef->removeEventListener( uno::Reference< document::XEventListener >( mpImpl->pLightClient ) );
+            mpImpl->mxObjRef->removeStateChangeListener ( mpImpl->mxLightClient.get() );
+            mpImpl->mxObjRef->removeEventListener( uno::Reference< document::XEventListener >( mpImpl->mxLightClient.get() ) );
             mpImpl->mxObjRef->setClientSite( nullptr );
 
             GetSdrGlobalData().GetOLEObjCache().RemoveObj(this);
@@ -1518,8 +1498,8 @@ void SdrOle2Obj::ImpSetVisAreaSize()
         // the client is required to get access to scaling
         SfxInPlaceClient* pClient = SfxInPlaceClient::GetClient( dynamic_cast<SfxObjectShell*>(pModel->GetPersist()), mpImpl->mxObjRef.GetObject() );
         bool bHasOwnClient =
-                        ( mpImpl->pLightClient
-                        && mpImpl->mxObjRef->getClientSite() == uno::Reference< embed::XEmbeddedClient >( mpImpl->pLightClient ) );
+                        ( mpImpl->mxLightClient.is()
+                        && mpImpl->mxObjRef->getClientSite() == uno::Reference< embed::XEmbeddedClient >( mpImpl->mxLightClient.get() ) );
 
         if ( pClient || bHasOwnClient )
         {
@@ -1538,8 +1518,8 @@ void SdrOle2Obj::ImpSetVisAreaSize()
                 }
                 else
                 {
-                    aScaleWidth = mpImpl->pLightClient->GetScaleWidth();
-                    aScaleHeight = mpImpl->pLightClient->GetScaleHeight();
+                    aScaleWidth = mpImpl->mxLightClient->GetScaleWidth();
+                    aScaleHeight = mpImpl->mxLightClient->GetScaleHeight();
                 }
 
                 // The object wants to resize itself (f.e. Chart wants to recalculate the layout)
@@ -1605,7 +1585,7 @@ void SdrOle2Obj::ImpSetVisAreaSize()
                     }
                     else
                     {
-                        mpImpl->pLightClient->SetSizeScale( aScaleWidth, aScaleHeight );
+                        mpImpl->mxLightClient->SetSizeScale( aScaleWidth, aScaleHeight );
                     }
                 }
             }
@@ -1942,20 +1922,20 @@ bool SdrOle2Obj::AddOwnLightClient()
 {
     // The Own Light Client must be registered in object only using this method!
     if ( !SfxInPlaceClient::GetClient( dynamic_cast<SfxObjectShell*>(pModel->GetPersist()), mpImpl->mxObjRef.GetObject() )
-      && !( mpImpl->pLightClient && mpImpl->mxObjRef->getClientSite() == uno::Reference< embed::XEmbeddedClient >( mpImpl->pLightClient ) ) )
+      && !( mpImpl->mxLightClient.is() && mpImpl->mxObjRef->getClientSite() == uno::Reference< embed::XEmbeddedClient >( mpImpl->mxLightClient.get() ) ) )
     {
         Connect();
 
-        if ( mpImpl->mxObjRef.is() && mpImpl->pLightClient )
+        if ( mpImpl->mxObjRef.is() && mpImpl->mxLightClient.is() )
         {
             Fraction aScaleWidth;
             Fraction aScaleHeight;
             Size aObjAreaSize;
             if ( CalculateNewScaling( aScaleWidth, aScaleHeight, aObjAreaSize ) )
             {
-                mpImpl->pLightClient->SetSizeScale( aScaleWidth, aScaleHeight );
+                mpImpl->mxLightClient->SetSizeScale( aScaleWidth, aScaleHeight );
                 try {
-                    mpImpl->mxObjRef->setClientSite( mpImpl->pLightClient );
+                    mpImpl->mxObjRef->setClientSite( mpImpl->mxLightClient.get() );
                     return true;
                 } catch( uno::Exception& )
                 {}
@@ -1976,9 +1956,9 @@ Graphic SdrOle2Obj::GetEmptyOLEReplacementGraphic()
 
 void SdrOle2Obj::SetWindow(const css::uno::Reference < css::awt::XWindow >& _xWindow)
 {
-    if ( mpImpl->mxObjRef.is() && mpImpl->pLightClient )
+    if ( mpImpl->mxObjRef.is() && mpImpl->mxLightClient.is() )
     {
-        mpImpl->pLightClient->setWindow(_xWindow);
+        mpImpl->mxLightClient->setWindow(_xWindow);
     }
 }
 
commit c8cbcd77484d8172d76d0758f16f9b340277fa52
Author: Noel Grandin <noel.grandin at collabora.co.uk>
Date:   Fri Oct 6 15:57:05 2017 +0200

    use more rtl::Reference in connectivity
    
    instead of manual ref counting
    
    Change-Id: I210d4a2cd6487bd2d7d81a53106b484fe411ca9b
    Reviewed-on: https://gerrit.libreoffice.org/43203
    Tested-by: Jenkins <ci at libreoffice.org>
    Reviewed-by: Noel Grandin <noel.grandin at collabora.co.uk>

diff --git a/connectivity/source/drivers/evoab2/NStatement.cxx b/connectivity/source/drivers/evoab2/NStatement.cxx
index 58225437ace1..095d2abf7038 100644
--- a/connectivity/source/drivers/evoab2/NStatement.cxx
+++ b/connectivity/source/drivers/evoab2/NStatement.cxx
@@ -72,7 +72,7 @@ OCommonStatement::OCommonStatement(OEvoabConnection* _pConnection)
     , ::comphelper::OPropertyContainer(OCommonStatement_IBase::rBHelper)
     , OStatement_CBase( static_cast<cppu::OWeakObject*>(_pConnection), this )
     , m_xResultSet(nullptr)
-    , m_pConnection(_pConnection)
+    , m_xConnection(_pConnection)
     , m_aParser(_pConnection->getDriver().getComponentContext())
     , m_aSQLIterator( _pConnection, _pConnection->createCatalog()->getTables(), m_aParser )
     , m_pParseTree(nullptr)
@@ -85,8 +85,6 @@ OCommonStatement::OCommonStatement(OEvoabConnection* _pConnection)
     , m_nResultSetConcurrency(ResultSetConcurrency::UPDATABLE)
     , m_bEscapeProcessing(true)
 {
-    m_pConnection->acquire();
-
 #define REGISTER_PROP( id, member ) \
     registerProperty( \
         OMetaConnection::getPropMap().getNameByIndex( id ), \
@@ -126,9 +124,7 @@ void OCommonStatement::disposing()
 
     disposeResultSet();
 
-    if (m_pConnection)
-        m_pConnection->release();
-    m_pConnection = nullptr;
+    m_xConnection.clear();
 
     dispose_ChildImpl();
     OCommonStatement_IBase::disposing();
@@ -198,7 +194,7 @@ OUString OCommonStatement::impl_getColumnRefColumnName_throw( const OSQLParseNod
     }
 
     if ( !sColumnName.getLength() )
-        m_pConnection->throwGenericSQLException( STR_QUERY_TOO_COMPLEX, *this );
+        m_xConnection->throwGenericSQLException( STR_QUERY_TOO_COMPLEX, *this );
 
     return sColumnName;
 }
@@ -230,7 +226,7 @@ void OCommonStatement::orderByAnalysis( const OSQLParseNode* _pOrderByClause, So
 
         // column name -> column field
         if ( !SQL_ISRULE( pColumnRef, column_ref ) )
-            m_pConnection->throwGenericSQLException( STR_SORT_BY_COL_ONLY, *this );
+            m_xConnection->throwGenericSQLException( STR_SORT_BY_COL_ONLY, *this );
         const OUString sColumnName( impl_getColumnRefColumnName_throw( *pColumnRef ) );
         guint nField = evoab::findEvoabField( sColumnName );
         // ascending/descending?
@@ -301,14 +297,14 @@ EBookQuery *OCommonStatement::whereAnalysis( const OSQLParseNode* parseTree )
                 )
             )
         {
-            m_pConnection->throwGenericSQLException( STR_QUERY_TOO_COMPLEX, *this );
+            m_xConnection->throwGenericSQLException( STR_QUERY_TOO_COMPLEX, *this );
         }
 
         if  (   ( pPrec->getNodeType() != SQLNodeType::Equal )
             &&  ( pPrec->getNodeType() != SQLNodeType::NotEqual )
             )
         {
-            m_pConnection->throwGenericSQLException( STR_OPERATOR_TOO_COMPLEX, *this );
+            m_xConnection->throwGenericSQLException( STR_OPERATOR_TOO_COMPLEX, *this );
         }
 
         // recognize the special "0 = 1" condition
@@ -342,7 +338,7 @@ EBookQuery *OCommonStatement::whereAnalysis( const OSQLParseNode* parseTree )
         const OSQLParseNode* pPart2 = parseTree->getChild(1);
 
         if( ! SQL_ISRULE( parseTree->getChild( 0 ), column_ref) )
-            m_pConnection->throwGenericSQLException(STR_QUERY_INVALID_LIKE_COLUMN,*this);
+            m_xConnection->throwGenericSQLException(STR_QUERY_INVALID_LIKE_COLUMN,*this);
 
         OUString aColumnName( impl_getColumnRefColumnName_throw( *parseTree->getChild( 0 ) ) );
 
@@ -358,7 +354,7 @@ EBookQuery *OCommonStatement::whereAnalysis( const OSQLParseNode* parseTree )
             SAL_INFO(
                 "connectivity.evoab2",
                 "analyseSQL : pAtom->count() = " << pAtom->count());
-            m_pConnection->throwGenericSQLException(STR_QUERY_INVALID_LIKE_STRING,*this);
+            m_xConnection->throwGenericSQLException(STR_QUERY_INVALID_LIKE_STRING,*this);
         }
 
         const sal_Unicode WILDCARD = '%';
@@ -383,7 +379,7 @@ EBookQuery *OCommonStatement::whereAnalysis( const OSQLParseNode* parseTree )
         else if( bNotLike )
         {
             // We currently can't handle a 'NOT LIKE' when there are '%'
-            m_pConnection->throwGenericSQLException(STR_QUERY_NOT_LIKE_TOO_COMPLEX,*this);
+            m_xConnection->throwGenericSQLException(STR_QUERY_NOT_LIKE_TOO_COMPLEX,*this);
         }
         else if( aMatchString.indexOf ( WILDCARD ) == aMatchString.lastIndexOf ( WILDCARD ) )
         {   // One occurrence of '%'  matches...
@@ -392,7 +388,7 @@ EBookQuery *OCommonStatement::whereAnalysis( const OSQLParseNode* parseTree )
             else if ( aMatchString.indexOf ( WILDCARD ) == aMatchString.getLength() - 1 )
                 pResult = createTest( aColumnName, E_BOOK_QUERY_BEGINS_WITH, aMatchString.copy( 0, aMatchString.getLength() - 1 ) );
             else
-                m_pConnection->throwGenericSQLException(STR_QUERY_LIKE_WILDCARD,*this);
+                m_xConnection->throwGenericSQLException(STR_QUERY_LIKE_WILDCARD,*this);
         }
         else if( aMatchString.getLength() >= 3 &&
                  aMatchString.startsWith(OUStringLiteral1(WILDCARD)) &&
@@ -401,7 +397,7 @@ EBookQuery *OCommonStatement::whereAnalysis( const OSQLParseNode* parseTree )
             pResult = createTest( aColumnName, E_BOOK_QUERY_CONTAINS, aMatchString.copy (1, aMatchString.getLength() - 2) );
         }
         else
-            m_pConnection->throwGenericSQLException(STR_QUERY_LIKE_WILDCARD_MANY,*this);
+            m_xConnection->throwGenericSQLException(STR_QUERY_LIKE_WILDCARD_MANY,*this);
     }
 
     return pResult;
@@ -552,12 +548,12 @@ QueryData OCommonStatement::impl_getEBookQuery_throw( const OUString& _rSql )
 #endif
 
     if ( !aData.getQuery() )
-        m_pConnection->throwGenericSQLException( STR_QUERY_TOO_COMPLEX, *this );
+        m_xConnection->throwGenericSQLException( STR_QUERY_TOO_COMPLEX, *this );
 
     // a postcondition of this method is that we properly determined the SELECT columns
     aData.xSelectColumns = m_aSQLIterator.getSelectColumns();
     if ( !aData.xSelectColumns.is() )
-        m_pConnection->throwGenericSQLException( STR_QUERY_TOO_COMPLEX, *this );
+        m_xConnection->throwGenericSQLException( STR_QUERY_TOO_COMPLEX, *this );
 
     return aData;
 }
@@ -566,7 +562,7 @@ QueryData OCommonStatement::impl_getEBookQuery_throw( const OUString& _rSql )
 Reference< XResultSet > OCommonStatement::impl_executeQuery_throw( const QueryData& _rQueryData )
 {
     // create result set
-    OEvoabResultSet* pResult = new OEvoabResultSet( this, m_pConnection );
+    OEvoabResultSet* pResult = new OEvoabResultSet( this, m_xConnection.get() );
     Reference< XResultSet > xRS = pResult;
     pResult->construct( _rQueryData );
 
diff --git a/connectivity/source/drivers/evoab2/NStatement.hxx b/connectivity/source/drivers/evoab2/NStatement.hxx
index 87ede6f43ed9..7779673b255f 100644
--- a/connectivity/source/drivers/evoab2/NStatement.hxx
+++ b/connectivity/source/drivers/evoab2/NStatement.hxx
@@ -160,7 +160,7 @@ namespace connectivity
 
         private:
             css::uno::WeakReference< css::sdbc::XResultSet>    m_xResultSet;   // The last ResultSet created
-            OEvoabConnection                     *m_pConnection;
+            rtl::Reference<OEvoabConnection>      m_xConnection;
             connectivity::OSQLParser              m_aParser;
             connectivity::OSQLParseTreeIterator   m_aSQLIterator;
             connectivity::OSQLParseNode          *m_pParseTree;
@@ -197,7 +197,7 @@ namespace connectivity
         public:
 
             // other methods
-            OEvoabConnection* getOwnConnection() const { return m_pConnection;}
+            OEvoabConnection* getOwnConnection() const { return m_xConnection.get(); }
 
             using OCommonStatement_IBase::operator css::uno::Reference< css::uno::XInterface >;
 
@@ -239,7 +239,7 @@ namespace connectivity
                 impl_executeQuery_throw( const QueryData& _rData );
 
             css::uno::Reference< css::sdbc::XConnection >
-                impl_getConnection() { return css::uno::Reference< css::sdbc::XConnection >( m_pConnection ); }
+                impl_getConnection() { return css::uno::Reference< css::sdbc::XConnection >( m_xConnection.get() ); }
 
             OUString
                 impl_getColumnRefColumnName_throw( const ::connectivity::OSQLParseNode& _rColumnRef );
diff --git a/connectivity/source/drivers/odbc/OConnection.cxx b/connectivity/source/drivers/odbc/OConnection.cxx
index 711fc1b96a5b..ea2d0e07417b 100644
--- a/connectivity/source/drivers/odbc/OConnection.cxx
+++ b/connectivity/source/drivers/odbc/OConnection.cxx
@@ -46,7 +46,7 @@ using namespace com::sun::star::sdbc;
 
 OConnection::OConnection(const SQLHANDLE _pDriverHandle,ODBCDriver* _pDriver)
                          : OSubComponent<OConnection, OConnection_BASE>(static_cast<cppu::OWeakObject*>(_pDriver), this)
-                         ,m_pDriver(_pDriver)
+                         ,m_xDriver(_pDriver)
                          ,m_aConnectionHandle(nullptr)
                          ,m_pDriverHandleCopy(_pDriverHandle)
                          ,m_nStatementCount(0)
@@ -58,7 +58,6 @@ OConnection::OConnection(const SQLHANDLE _pDriverHandle,ODBCDriver* _pDriver)
                          ,m_bPreventGetVersionColumns(false)
                          ,m_bReadOnly(true)
 {
-    m_pDriver->acquire();
 }
 
 OConnection::~OConnection()
@@ -78,9 +77,6 @@ OConnection::~OConnection()
 
         m_aConnectionHandle = SQL_NULL_HANDLE;
     }
-
-    m_pDriver->release();
-    m_pDriver = nullptr;
 }
 
 void SAL_CALL OConnection::release() throw()
@@ -90,8 +86,8 @@ void SAL_CALL OConnection::release() throw()
 
 oslGenericFunction OConnection::getOdbcFunction(ODBC3SQLFunctionId _nIndex)  const
 {
-    OSL_ENSURE(m_pDriver,"OConnection::getOdbcFunction: m_pDriver is null!");
-    return m_pDriver->getOdbcFunction(_nIndex);
+    OSL_ENSURE(m_xDriver.get(),"OConnection::getOdbcFunction: m_xDriver is null!");
+    return m_xDriver->getOdbcFunction(_nIndex);
 }
 
 SQLRETURN OConnection::OpenConnection(const OUString& aConnectStr, sal_Int32 nTimeOut, bool bSilent)
@@ -479,10 +475,10 @@ void OConnection::disposing()
 
     OConnection_BASE::disposing();
 
-    for (std::map< SQLHANDLE,OConnection*>::iterator aConIter = m_aConnections.begin();aConIter != m_aConnections.end();++aConIter )
+    for (auto aConIter = m_aConnections.begin(); aConIter != m_aConnections.end(); ++aConIter )
         aConIter->second->dispose();
 
-    std::map< SQLHANDLE,OConnection*>().swap(m_aConnections);
+    m_aConnections.clear();
 
     if(!m_bClosed)
         N3SQLDisconnect(m_aConnectionHandle);
@@ -493,17 +489,16 @@ void OConnection::disposing()
 
 SQLHANDLE OConnection::createStatementHandle()
 {
-    OConnection* pConnectionTemp = this;
+    rtl::Reference<OConnection> xConnectionTemp = this;
     bool bNew = false;
     try
     {
         sal_Int32 nMaxStatements = getMetaData()->getMaxStatements();
         if(nMaxStatements && nMaxStatements <= m_nStatementCount)
         {
-            OConnection* pConnection = new OConnection(m_pDriverHandleCopy,m_pDriver);
-            pConnection->acquire();
-            pConnection->Construct(m_sURL,getConnectionInfo());
-            pConnectionTemp = pConnection;
+            rtl::Reference<OConnection> xConnection(new OConnection(m_pDriverHandleCopy,m_xDriver.get()));
+            xConnection->Construct(m_sURL,getConnectionInfo());
+            xConnectionTemp = xConnection;
             bNew = true;
         }
     }
@@ -512,10 +507,10 @@ SQLHANDLE OConnection::createStatementHandle()
     }
 
     SQLHANDLE aStatementHandle = SQL_NULL_HANDLE;
-    N3SQLAllocHandle(SQL_HANDLE_STMT,pConnectionTemp->getConnection(),&aStatementHandle);
+    N3SQLAllocHandle(SQL_HANDLE_STMT,xConnectionTemp->getConnection(),&aStatementHandle);
     ++m_nStatementCount;
     if(bNew)
-        m_aConnections.emplace(aStatementHandle,pConnectionTemp);
+        m_aConnections.emplace(aStatementHandle,xConnectionTemp);
 
     return aStatementHandle;
 
@@ -526,7 +521,7 @@ void OConnection::freeStatementHandle(SQLHANDLE& _pHandle)
     if( SQL_NULL_HANDLE == _pHandle )
         return;
 
-    std::map< SQLHANDLE,OConnection*>::iterator aFind = m_aConnections.find(_pHandle);
+    auto aFind = m_aConnections.find(_pHandle);
 
     N3SQLFreeStmt(_pHandle,SQL_RESET_PARAMS);
     N3SQLFreeStmt(_pHandle,SQL_UNBIND);
diff --git a/connectivity/source/inc/odbc/OConnection.hxx b/connectivity/source/inc/odbc/OConnection.hxx
index f93e1e42e691..ed82ea85cf59 100644
--- a/connectivity/source/inc/odbc/OConnection.hxx
+++ b/connectivity/source/inc/odbc/OConnection.hxx
@@ -55,11 +55,12 @@ namespace connectivity
 
             // Data attributes
 
-            std::map< SQLHANDLE,OConnection*> m_aConnections; // holds all connections which are need for several statements
+            std::map< SQLHANDLE, rtl::Reference<OConnection>> m_aConnections; // holds all connections which are need for several statements
 
 
             OUString        m_sUser;        //  the user name
-            ODBCDriver*     m_pDriver;      //  Pointer to the owning
+            rtl::Reference<ODBCDriver>
+                            m_xDriver;      //  Pointer to the owning
                                             //  driver object
 
             SQLHANDLE       m_aConnectionHandle;
@@ -125,7 +126,7 @@ namespace connectivity
             bool     isIgnoreDriverPrivilegesEnabled()   const { return m_bIgnoreDriverPrivileges; }
             bool     preventGetVersionColumns()          const { return m_bPreventGetVersionColumns; }
             bool     useOldDateFormat()                  const { return m_bUseOldDateFormat; }
-            ODBCDriver*      getDriver()                     const { return m_pDriver;}
+            ODBCDriver*      getDriver()                 const { return m_xDriver.get();}
 
             SQLHANDLE       createStatementHandle();
             // close and free the handle and set it to SQL_NULLHANDLE
commit bab595df78bd05a45f92aa15dca058f27b86d5be
Author: Tamás Zolnai <tamas.zolnai at collabora.com>
Date:   Fri Oct 6 18:55:27 2017 +0200

    tdf#112936: Pivot table: LO created XLSX file makes Excel to crash
    
    It's not actually clear, why Excel crashes, but setting the version
    makes it working. I expect that this version number (which specifies MSO
    Excel versions) makes MSO to handle the pivot table differently. As the
    internal implementation of the pivot table was changed in different
    versions. The name "DATA" might had a special meaning in the earlier
    versions (e.g. XP, MSO 2000) which leads this crash.
    So setting the version to MSO 2007 seems a good solution for this.
    Older versions not seems a target of LO exported XLSX files in these days.
    Also smaller values leads to the crash described in the bug report.
    
    Change-Id: I6e9edc949d1670d657effff9277cfd86ff163458
    Reviewed-on: https://gerrit.libreoffice.org/43208
    Reviewed-by: Tamás Zolnai <tamas.zolnai at collabora.com>
    Tested-by: Tamás Zolnai <tamas.zolnai at collabora.com>

diff --git a/sc/source/filter/excel/xepivotxml.cxx b/sc/source/filter/excel/xepivotxml.cxx
index 270066f76126..9bc8836a57f4 100644
--- a/sc/source/filter/excel/xepivotxml.cxx
+++ b/sc/source/filter/excel/xepivotxml.cxx
@@ -221,6 +221,7 @@ void XclExpXmlPivotCaches::SavePivotCacheXml( XclExpXmlStream& rStrm, const Entr
         FSNS(XML_xmlns, XML_r), XclXmlUtils::ToOString(rStrm.getNamespaceURL(OOX_NS(officeRel))).getStr(),
         FSNS(XML_r, XML_id), XclXmlUtils::ToOString(aRelId).getStr(),
         XML_recordCount, OString::number(rEntry.mpCache->GetDataSize()).getStr(),
+        XML_createdVersion, "3", // MS Excel 2007, tdf#112936: setting version number makes MSO to handle the pivot table differently
         FSEND);
 
     if (rEntry.meType == Worksheet)


More information about the Libreoffice-commits mailing list