xref: /core/sc/source/ui/dbgui/tpsort.cxx (revision 57c7269f)
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3  * This file is part of the LibreOffice project.
4  *
5  * This Source Code Form is subject to the terms of the Mozilla Public
6  * License, v. 2.0. If a copy of the MPL was not distributed with this
7  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8  *
9  * This file incorporates work covered by the following license notice:
10  *
11  *   Licensed to the Apache Software Foundation (ASF) under one or more
12  *   contributor license agreements. See the NOTICE file distributed
13  *   with this work for additional information regarding copyright
14  *   ownership. The ASF licenses this file to you under the Apache
15  *   License, Version 2.0 (the "License"); you may not use this file
16  *   except in compliance with the License. You may obtain a copy of
17  *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
18  */
19 
20 #undef SC_DLLIMPLEMENTATION
21 
22 #include <vcl/svapp.hxx>
23 #include <vcl/weld.hxx>
24 #include <i18nlangtag/languagetag.hxx>
25 #include <svtools/collatorres.hxx>
26 #include <unotools/collatorwrapper.hxx>
27 #include <comphelper/processfactory.hxx>
28 #include <osl/diagnose.h>
29 
30 #include <scitems.hxx>
31 #include <uiitems.hxx>
32 #include <viewdata.hxx>
33 #include <document.hxx>
34 #include <global.hxx>
35 #include <dbdata.hxx>
36 #include <userlist.hxx>
37 #include <rangeutl.hxx>
38 #include <scresid.hxx>
39 #include <sc.hrc>
40 #include <strings.hrc>
41 #include <globstr.hrc>
42 
43 #include <sortkeydlg.hxx>
44 
45 #include <sortdlg.hxx>
46 
47 #include <tpsort.hxx>
48 
49 using namespace com::sun::star;
50 
51 /*
52  * Since the settings on the second Tab Page (Options) effects
53  * the first Tab Page, there must be a way for it to communicate with the
54  * other Page.
55  *
56  * At the moment this problem is solved through using two data members of the
57  * Tab Pages. If a page is enabled / disabled, it compares this data member
58  * with its own state (-> Activate() / Deactivate()).
59  *
60  * In the meantime the class SfxTabPage offers the following method:
61  *
62  * virtual sal_Bool HasExchangeSupport() const; -> return sal_True;
63  * virtual void ActivatePage(const SfxItemSet &);
64  * virtual int  DeactivatePage(SfxItemSet * = 0);
65  *
66  * This still needs to be changed!
67  */
68 
69 // Sort Criteria Tab page
70 
ScTabPageSortFields(weld::Container * pPage,weld::DialogController * pController,const SfxItemSet & rArgSet)71 ScTabPageSortFields::ScTabPageSortFields(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& rArgSet)
72     : SfxTabPage(pPage, pController, u"modules/scalc/ui/sortcriteriapage.ui"_ustr, u"SortCriteriaPage"_ustr, &rArgSet)
73     ,
74 
75         m_aIdle("ScTabPageSortFields Scroll To End Idle"),
76         aStrUndefined   ( ScResId( SCSTR_UNDEFINED ) ),
77         aStrColumn      ( ScResId( SCSTR_COLUMN ) ),
78         aStrRow         ( ScResId( SCSTR_ROW ) ),
79         aStrRowLabel    ( ScResId( SCSTR_ROW_LABEL ) ),
80         aStrColLabel    ( ScResId( SCSTR_COL_LABEL ) ),
81 
82         nWhichSort      ( rArgSet.GetPool()->GetWhichIDFromSlotID( SID_SORT ) ),
83         pViewData       ( nullptr ),
84         aSortData       ( rArgSet.Get( nWhichSort ).GetSortData() ),
85         nFieldCount     ( 0 ),
86         // show actual size of the sorting keys without limiting them to the default size
87         nSortKeyCount(std::max(aSortData.GetSortKeyCount(), static_cast<sal_uInt16>(DEFSORT)))
88 
89     , m_xTop(m_xBuilder->weld_container(u"TopWindow"_ustr))
90     , m_xBtnHeader(m_xBuilder->weld_check_button(u"cbHeader"_ustr))
91     , m_xBtnTopDown(m_xBuilder->weld_radio_button(u"rbTopDown"_ustr))
92     , m_xBtnLeftRight(m_xBuilder->weld_radio_button(u"rbLeftRight"_ustr))
93     , m_xScrolledWindow(m_xBuilder->weld_scrolled_window(u"SortCriteriaPage"_ustr))
94     , m_xBox(m_xBuilder->weld_container(u"SortKeyWindow"_ustr))
95     , m_aSortWin(m_xBox.get())
96 {
97     // tdf#147722 set some nominal small default height so the height adapts
98     // to all the other contents and the natural height of this widget isn't
99     // an input into the overall size
100     m_xScrolledWindow->set_size_request(-1, 42);
101 
102     Init();
103 
104     m_aIdle.SetInvokeHandler(LINK(this, ScTabPageSortFields, ScrollToEndHdl));
105 
106     SetExchangeSupport();
107 }
108 
~ScTabPageSortFields()109 ScTabPageSortFields::~ScTabPageSortFields()
110 {
111     m_aSortWin.m_aSortKeyItems.clear();
112     m_xBox.reset();
113     m_xScrolledWindow.reset();
114 }
115 
Init()116 void ScTabPageSortFields::Init()
117 {
118     // Check whether the field that is passed on is a database field:
119     ScDocument* pDoc = pViewData ? &pViewData->GetDocument() : nullptr;
120     if ( pDoc )
121     {
122         ScDBCollection* pDBColl = pDoc->GetDBCollection();
123         const SCTAB     nCurTab = pViewData->GetTabNo();
124         if ( pDBColl )
125         {
126             ScDBData* pDBData
127                     = pDBColl->GetDBAtArea( nCurTab,
128                                             aSortData.nCol1, aSortData.nRow1,
129                                             aSortData.nCol2, aSortData.nRow2 );
130             if ( pDBData )
131             {
132                 m_xBtnHeader->set_active(pDBData->HasHeader());
133             }
134         }
135     }
136     m_xBtnHeader->set_label(aStrColLabel);
137 
138     Link<weld::Toggleable&,void> aLink = LINK(this, ScTabPageSortFields, SortDirHdl );
139     m_xBtnTopDown->connect_toggled( aLink );
140     m_xBtnLeftRight->connect_toggled( aLink );
141     m_xBtnHeader->connect_toggled( aLink );
142 
143     const ScSortItem& rSortItem = GetItemSet().Get( nWhichSort );
144 
145     pViewData = rSortItem.GetViewData();
146     OSL_ENSURE( pViewData, "ViewData not found!" );
147 
148     nFieldArr.push_back( 0 );
149 
150     // Create three sort key dialogs by default
151     for ( sal_uInt16 i=0; i<nSortKeyCount; i++ )
152     {
153         AddSortKey(i+1);
154         m_aSortWin.m_aSortKeyItems[i]->m_xLbSort->connect_changed(LINK(this, ScTabPageSortFields, SelectHdl));
155     }
156 }
157 
Create(weld::Container * pPage,weld::DialogController * pController,const SfxItemSet * pArgSet)158 std::unique_ptr<SfxTabPage> ScTabPageSortFields::Create(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet* pArgSet)
159 {
160     return std::make_unique<ScTabPageSortFields>(pPage, pController, *pArgSet);
161 }
162 
Reset(const SfxItemSet *)163 void ScTabPageSortFields::Reset( const SfxItemSet* /* rArgSet */ )
164 {
165     m_xBtnHeader->set_active( aSortData.bHasHeader );
166     m_xBtnTopDown->set_active( aSortData.bByRow );
167     m_xBtnLeftRight->set_active( !aSortData.bByRow );
168 
169     if (m_aSortWin.m_aSortKeyItems[0]->m_xLbSort->get_count() == 0)
170         FillFieldLists(0);
171 
172     // ListBox selection:
173     if (!aSortData.maKeyState.empty() && aSortData.maKeyState[0].bDoSort)
174     {
175         // Make sure that the all sort keys are reset
176         for ( sal_uInt16 i=nSortKeyCount; i<aSortData.GetSortKeyCount(); i++ )
177         {
178             AddSortKey(i+1);
179             m_aSortWin.m_aSortKeyItems[i]->m_xLbSort->connect_changed( LINK( this,
180                                  ScTabPageSortFields, SelectHdl ) );
181         }
182         nSortKeyCount = aSortData.GetSortKeyCount();
183         FillFieldLists(0);
184 
185         for ( sal_uInt16 i=0; i<nSortKeyCount; i++ )
186         {
187             if (aSortData.maKeyState[i].bDoSort )
188             {
189                 m_aSortWin.m_aSortKeyItems[i]->m_xLbSort->set_active( GetFieldSelPos(
190                                     aSortData.maKeyState[i].nField ) );
191                 (aSortData.maKeyState[i].bAscending)
192                     ? m_aSortWin.m_aSortKeyItems[i]->m_xBtnUp->set_active(true)
193                     : m_aSortWin.m_aSortKeyItems[i]->m_xBtnDown->set_active(true);
194             }
195             else
196             {
197                 m_aSortWin.m_aSortKeyItems[i]->m_xLbSort->set_active(0); // Select none
198                 m_aSortWin.m_aSortKeyItems[i]->m_xBtnUp->set_active(true);
199             }
200         }
201 
202         // Enable or disable field depending on preceding Listbox selection
203         m_aSortWin.m_aSortKeyItems[0]->EnableField();
204         for ( sal_uInt16 i=1; i<nSortKeyCount; i++ )
205             if ( m_aSortWin.m_aSortKeyItems[i - 1]->m_xLbSort->get_active() == 0 )
206                 m_aSortWin.m_aSortKeyItems[i]->DisableField();
207             else
208                 m_aSortWin.m_aSortKeyItems[i]->EnableField();
209     }
210     else
211     {
212         SCCOL  nCol = pViewData->GetCurX();
213 
214         if( nCol < aSortData.nCol1 )
215             nCol = aSortData.nCol1;
216         else if( nCol > aSortData.nCol2 )
217             nCol = aSortData.nCol2;
218 
219         sal_uInt16  nSort1Pos = nCol - aSortData.nCol1+1;
220 
221         m_aSortWin.m_aSortKeyItems[0]->m_xLbSort->set_active(nSort1Pos);
222         for ( sal_uInt16 i=1; i<nSortKeyCount; i++ )
223             m_aSortWin.m_aSortKeyItems[i]->m_xLbSort->set_active(0);
224 
225         for ( sal_uInt16 i=0; i<nSortKeyCount; i++ )
226             m_aSortWin.m_aSortKeyItems[i]->m_xBtnUp->set_active(true);
227 
228         m_aSortWin.m_aSortKeyItems[0]->EnableField();
229         m_aSortWin.m_aSortKeyItems[1]->EnableField();
230         for ( sal_uInt16 i=2; i<nSortKeyCount; i++ )
231             m_aSortWin.m_aSortKeyItems[i]->DisableField();
232     }
233 
234     // Make sure that there is always a last undefined sort key
235     if (m_aSortWin.m_aSortKeyItems[nSortKeyCount - 1]->m_xLbSort->get_active() > 0)
236         SetLastSortKey( nSortKeyCount );
237 }
238 
FillItemSet(SfxItemSet * rArgSet)239 bool ScTabPageSortFields::FillItemSet( SfxItemSet* rArgSet )
240 {
241     ScSortParam aNewSortData = aSortData;
242 
243     const SfxItemSet* pExample = GetDialogExampleSet();
244     if (pExample)
245     {
246         if (const ScSortItem* pItem = pExample->GetItemIfSet(nWhichSort))
247         {
248             ScSortParam aTempData = pItem->GetSortData();
249             aTempData.maKeyState = aNewSortData.maKeyState;
250             aNewSortData = aTempData;
251         }
252     }
253     aNewSortData.bByRow        = m_xBtnTopDown->get_active();
254     aNewSortData.bHasHeader    = m_xBtnHeader->get_active();
255 
256     std::vector<sal_Int32>  nSortPos;
257 
258     for ( sal_uInt16 i=0; i<nSortKeyCount; i++ )
259     {
260         nSortPos.push_back(m_aSortWin.m_aSortKeyItems[i]->m_xLbSort->get_active());
261         if (nSortPos[i] == -1) nSortPos[i] = 0;
262     }
263 
264     if( nSortKeyCount >= aNewSortData.GetSortKeyCount() )
265         aNewSortData.maKeyState.resize(nSortKeyCount);
266 
267     if ( nSortPos[0] > 0 )
268     {
269         for ( sal_uInt16 i=0; i<nSortKeyCount; i++ )
270         {
271             aNewSortData.maKeyState[i].bDoSort = (nSortPos[i] > 0);
272             aNewSortData.maKeyState[i].nField = nFieldArr[nSortPos[i]];
273             aNewSortData.maKeyState[i].bAscending = m_aSortWin.m_aSortKeyItems[i]->m_xBtnUp->get_active();
274         }
275     }
276     else
277     {
278         for ( sal_uInt16 i=0; i<nSortKeyCount; i++ )
279             aNewSortData.maKeyState[i].bDoSort = false;
280     }
281 
282     rArgSet->Put( ScSortItem( SCITEM_SORTDATA, nullptr, &aNewSortData ) );
283 
284     return true;
285 }
286 
287 // for data exchange without dialogue detour:
ActivatePage(const SfxItemSet & rSet)288 void ScTabPageSortFields::ActivatePage( const SfxItemSet& rSet )
289 {
290     // Refresh local copy with shared data
291     aSortData = rSet.Get( SCITEM_SORTDATA ).GetSortData();
292 
293     m_xBtnHeader->set_active( aSortData.bHasHeader );
294     m_xBtnTopDown->set_active( aSortData.bByRow );
295     m_xBtnLeftRight->set_active( !aSortData.bByRow );
296 }
297 
DeactivatePage(SfxItemSet * pSetP)298 DeactivateRC ScTabPageSortFields::DeactivatePage( SfxItemSet* pSetP )
299 {
300     if ( pSetP )
301         FillItemSet( pSetP );
302 
303     return DeactivateRC::LeavePage;
304 }
305 
FillFieldLists(sal_uInt16 nStartField)306 void ScTabPageSortFields::FillFieldLists( sal_uInt16 nStartField )
307 {
308     if ( !pViewData )
309         return;
310 
311     ScDocument& rDoc = pViewData->GetDocument();
312 
313     for (sal_uInt16 j = nStartField; j < nSortKeyCount; ++j)
314     {
315         m_aSortWin.m_aSortKeyItems[j]->m_xLabel->set_label(aSortData.bByRow ? aStrColumn : aStrRow);
316         m_aSortWin.m_aSortKeyItems[j]->m_xLbSort->clear();
317         m_aSortWin.m_aSortKeyItems[j]->m_xLbSort->freeze();
318         m_aSortWin.m_aSortKeyItems[j]->m_xLbSort->append_text(aStrUndefined);
319     }
320 
321     SCCOL   nFirstSortCol   = aSortData.nCol1;
322     SCROW   nFirstSortRow   = aSortData.nRow1;
323     SCTAB   nTab        = pViewData->GetTabNo();
324     sal_uInt16  i           = 1;
325     nFieldArr.clear();
326     nFieldArr.push_back(0);
327 
328     if ( aSortData.bByRow )
329     {
330         OUString  aFieldName;
331         SCCOL   nMaxCol = rDoc.ClampToAllocatedColumns(nTab, aSortData.nCol2);
332         SCCOL   col;
333 
334         for ( col=nFirstSortCol; col<=nMaxCol && i<SC_MAXFIELDS(rDoc.GetSheetLimits()); col++ )
335         {
336             aFieldName = rDoc.GetString(col, nFirstSortRow, nTab);
337             if ( !aSortData.bHasHeader || aFieldName.isEmpty() )
338                 aFieldName = ScColToAlpha( col );
339             nFieldArr.push_back( col );
340 
341             for ( sal_uInt16 j=nStartField; j<nSortKeyCount; j++ )
342                 m_aSortWin.m_aSortKeyItems[j]->m_xLbSort->insert_text(i, aFieldName);
343 
344             i++;
345         }
346     }
347     else
348     {
349         OUString  aFieldName;
350         SCROW   nMaxRow = aSortData.nRow2;
351         SCROW   row;
352 
353         for ( row=nFirstSortRow; row<=nMaxRow && i<SC_MAXFIELDS(rDoc.GetSheetLimits()); row++ )
354         {
355             aFieldName = rDoc.GetString(nFirstSortCol, row, nTab);
356             if ( !aSortData.bHasHeader || aFieldName.isEmpty() )
357                 aFieldName = OUString::number( row+1);
358             nFieldArr.push_back( row );
359 
360             for ( sal_uInt16 j=nStartField; j<nSortKeyCount; j++ )
361                 m_aSortWin.m_aSortKeyItems[j]->m_xLbSort->insert_text(i, aFieldName);
362 
363             i++;
364         }
365     }
366 
367     for (sal_uInt16 j=nStartField; j < nSortKeyCount; ++j)
368     {
369         m_aSortWin.m_aSortKeyItems[j]->m_xLbSort->thaw();
370     }
371 
372     nFieldCount = i;
373 }
374 
GetFieldSelPos(SCCOLROW nField)375 sal_uInt16 ScTabPageSortFields::GetFieldSelPos( SCCOLROW nField )
376 {
377     sal_uInt16  nFieldPos   = 0;
378     bool    bFound      = false;
379 
380     for ( sal_uInt16 n=1; n<nFieldCount && !bFound; n++ )
381     {
382         if ( nFieldArr[n] == nField )
383         {
384             nFieldPos = n;
385             bFound = true;
386         }
387     }
388 
389     return nFieldPos;
390 }
391 
SetLastSortKey(sal_uInt16 nItem)392 void ScTabPageSortFields::SetLastSortKey( sal_uInt16 nItem )
393 {
394     // Extend local SortParam copy
395     const ScSortKeyState atempKeyState = { 0, false, true, ScColorSortMode::None, Color() };
396     aSortData.maKeyState.push_back( atempKeyState );
397 
398     // Add Sort Key Item
399     ++nSortKeyCount;
400     AddSortKey( nSortKeyCount );
401     m_aSortWin.m_aSortKeyItems[nItem]->m_xLbSort->connect_changed(
402                      LINK( this, ScTabPageSortFields, SelectHdl ) );
403 
404     FillFieldLists( nItem );
405 
406     // Set Status
407     m_aSortWin.m_aSortKeyItems[nItem]->m_xBtnUp->set_active(true);
408     m_aSortWin.m_aSortKeyItems[nItem]->m_xLbSort->set_active(0);
409 }
410 
411 // Handler:
412 
IMPL_LINK_NOARG(ScTabPageSortFields,SortDirHdl,weld::Toggleable &,void)413 IMPL_LINK_NOARG(ScTabPageSortFields, SortDirHdl, weld::Toggleable&, void)
414 {
415     if ( (m_xBtnTopDown->get_active() != aSortData.bByRow) || (m_xBtnHeader->get_active() != aSortData.bHasHeader))
416     {
417         if (m_xBtnTopDown->get_active())
418             m_xBtnHeader->set_label(aStrColLabel);
419         else
420             m_xBtnHeader->set_label(aStrRowLabel);
421 
422         aSortData.bByRow     = m_xBtnTopDown->get_active();
423         aSortData.bHasHeader = m_xBtnHeader->get_active();
424 
425         // remember selection
426         std::vector<sal_uInt16> nCurSel;
427         for ( sal_uInt16 i=0; i<nSortKeyCount; i++ )
428             nCurSel.push_back( m_aSortWin.m_aSortKeyItems[i]->m_xLbSort->get_active() );
429 
430         FillFieldLists(0);
431 
432         for ( sal_uInt16 i=0; i<nSortKeyCount; i++ )
433             m_aSortWin.m_aSortKeyItems[i]->m_xLbSort->set_active(nCurSel[i]);
434     }
435 }
436 
IMPL_LINK(ScTabPageSortFields,SelectHdl,weld::ComboBox &,rLb,void)437 IMPL_LINK( ScTabPageSortFields, SelectHdl, weld::ComboBox&, rLb, void )
438 {
439     OUString aSelEntry = rLb.get_active_text();
440     ScSortKeyItems::iterator pIter;
441 
442     // If last listbox is enabled add one item
443     if (m_aSortWin.m_aSortKeyItems.back()->m_xLbSort.get() == &rLb)
444     {
445         if ( aSelEntry != aStrUndefined )
446         {
447             SetLastSortKey( nSortKeyCount );
448             return;
449         }
450     }
451 
452     // Find selected listbox
453     pIter = std::find_if(m_aSortWin.m_aSortKeyItems.begin(), m_aSortWin.m_aSortKeyItems.end(),
454         [&rLb](const ScSortKeyItems::value_type& rItem) { return rItem->m_xLbSort.get() == &rLb; });
455 
456     if (pIter == m_aSortWin.m_aSortKeyItems.end())
457         return;
458 
459     // If not selecting the last Listbox, modify the succeeding ones
460     ++pIter;
461     if ( std::distance(m_aSortWin.m_aSortKeyItems.begin(), pIter) >= nSortKeyCount )
462         return;
463 
464     if ( aSelEntry == aStrUndefined )
465     {
466         for ( ; pIter != m_aSortWin.m_aSortKeyItems.end(); ++pIter )
467         {
468             (*pIter)->m_xLbSort->set_active(0);
469 
470             (*pIter)->DisableField();
471         }
472     }
473     else
474     {
475         (*pIter)->EnableField();
476     }
477 }
478 
IMPL_LINK_NOARG(ScTabPageSortFields,ScrollToEndHdl,Timer *,void)479 IMPL_LINK_NOARG(ScTabPageSortFields, ScrollToEndHdl, Timer*, void)
480 {
481     m_xScrolledWindow->vadjustment_set_value(m_xScrolledWindow->vadjustment_get_upper());
482 }
483 
AddSortKey(sal_uInt16 nItem)484 void ScTabPageSortFields::AddSortKey( sal_uInt16 nItem )
485 {
486     m_aSortWin.AddSortKey(nItem);
487     m_aIdle.Start();
488 }
489 
490 // Sort option Tab Page:
491 
ScTabPageSortOptions(weld::Container * pPage,weld::DialogController * pController,const SfxItemSet & rArgSet)492 ScTabPageSortOptions::ScTabPageSortOptions(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& rArgSet)
493     : SfxTabPage(pPage, pController, u"modules/scalc/ui/sortoptionspage.ui"_ustr, u"SortOptionsPage"_ustr, &rArgSet)
494     , aStrUndefined(ScResId(SCSTR_UNDEFINED))
495     , aStrCommentsRowLabel(ScResId(SCSTR_NOTES_ROW_LABEL))
496     , aStrCommentsColLabel(ScResId(SCSTR_NOTES_COL_LABEL))
497     , aStrImgRowLabel(ScResId(SCSTR_IMAGES_ROW_LABEL))
498     , aStrImgColLabel(ScResId(SCSTR_IMAGES_COL_LABEL))
499     , nWhichSort(rArgSet.GetPool()->GetWhichIDFromSlotID(SID_SORT))
500     , aSortData(rArgSet.Get(nWhichSort).GetSortData())
501     , pViewData(nullptr)
502     , pDoc(nullptr)
503     , m_xBtnCase(m_xBuilder->weld_check_button(u"case"_ustr))
504     , m_xBtnFormats(m_xBuilder->weld_check_button(u"formats"_ustr))
505     , m_xBtnNaturalSort(m_xBuilder->weld_check_button(u"naturalsort"_ustr))
506     , m_xBtnCopyResult(m_xBuilder->weld_check_button(u"copyresult"_ustr))
507     , m_xLbOutPos(m_xBuilder->weld_combo_box(u"outarealb"_ustr))
508     , m_xEdOutPos(m_xBuilder->weld_entry(u"outareaed"_ustr))
509     , m_xBtnSortUser(m_xBuilder->weld_check_button(u"sortuser"_ustr))
510     , m_xLbSortUser(m_xBuilder->weld_combo_box(u"sortuserlb"_ustr))
511     , m_xLbLanguage(new SvxLanguageBox(m_xBuilder->weld_combo_box(u"language"_ustr)))
512     , m_xFtAlgorithm(m_xBuilder->weld_label(u"algorithmft"_ustr))
513     , m_xLbAlgorithm(m_xBuilder->weld_combo_box(u"algorithmlb"_ustr))
514     , m_xBtnIncComments(m_xBuilder->weld_check_button(u"includenotes"_ustr))
515     , m_xBtnIncImages(m_xBuilder->weld_check_button(u"includeimages"_ustr))
516 {
517     m_xLbSortUser->set_size_request(m_xLbSortUser->get_approximate_digit_width() * 50, -1);
518     m_xLbSortUser->set_accessible_description(ScResId(STR_A11Y_DESC_SORTUSER));
519     Init();
520     SetExchangeSupport();
521 }
522 
Init()523 void ScTabPageSortOptions::Init()
524 {
525     //  CollatorResource has user-visible names for sort algorithms
526     m_xColRes.reset(new CollatorResource);
527 
528     //! use CollatorWrapper from document?
529     m_oColWrap.emplace(comphelper::getProcessComponentContext());
530 
531     const ScSortItem& rSortItem = GetItemSet().Get( nWhichSort );
532 
533     m_xLbOutPos->connect_changed( LINK( this, ScTabPageSortOptions, SelOutPosHdl ) );
534     m_xBtnCopyResult->connect_toggled( LINK( this, ScTabPageSortOptions, EnableHdl ) );
535     m_xBtnSortUser->connect_toggled( LINK( this, ScTabPageSortOptions, EnableHdl ) );
536     m_xLbLanguage->connect_changed( LINK( this, ScTabPageSortOptions, FillAlgorHdl ) );
537 
538     pViewData = rSortItem.GetViewData();
539     pDoc      = pViewData ? &pViewData->GetDocument() : nullptr;
540 
541     OSL_ENSURE( pViewData, "ViewData not found! :-/" );
542 
543     if ( pViewData && pDoc )
544     {
545         const formula::FormulaGrammar::AddressConvention eConv = pDoc->GetAddressConvention();
546 
547         m_xLbOutPos->clear();
548         m_xLbOutPos->append_text(aStrUndefined);
549         m_xLbOutPos->set_sensitive(false);
550 
551         ScAreaNameIterator aIter( *pDoc );
552         OUString aName;
553         ScRange aRange;
554         while ( aIter.Next( aName, aRange ) )
555         {
556             OUString aRefStr(aRange.aStart.Format(ScRefFlags::ADDR_ABS_3D, pDoc, eConv));
557             m_xLbOutPos->append(aRefStr, aName);
558         }
559 
560         m_xLbOutPos->set_active(0);
561         m_xEdOutPos->set_text(OUString());
562     }
563 
564     m_xBtnIncComments->set_label(aStrCommentsColLabel);
565     m_xBtnIncImages->set_label(aStrImgColLabel);
566 
567     FillUserSortListBox();
568 
569     //  get available languages
570 
571     m_xLbLanguage->SetLanguageList( SvxLanguageListFlags::ALL | SvxLanguageListFlags::ONLY_KNOWN, false );
572     m_xLbLanguage->InsertLanguage( LANGUAGE_SYSTEM );
573 }
574 
Create(weld::Container * pPage,weld::DialogController * pController,const SfxItemSet * rArgSet)575 std::unique_ptr<SfxTabPage> ScTabPageSortOptions::Create(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet* rArgSet)
576 {
577     return std::make_unique<ScTabPageSortOptions>(pPage, pController, *rArgSet);
578 }
579 
Reset(const SfxItemSet *)580 void ScTabPageSortOptions::Reset( const SfxItemSet* /* rArgSet */ )
581 {
582     if ( aSortData.bUserDef )
583     {
584         m_xBtnSortUser->set_active(true);
585         m_xLbSortUser->set_sensitive(true);
586         m_xLbSortUser->set_active(aSortData.nUserIndex);
587     }
588     else
589     {
590         m_xBtnSortUser->set_active(false);
591         m_xLbSortUser->set_sensitive(false);
592         m_xLbSortUser->set_active(0);
593     }
594 
595     m_xBtnCase->set_active( aSortData.bCaseSens );
596     m_xBtnFormats->set_active( aSortData.aDataAreaExtras.mbCellFormats );
597     m_xBtnNaturalSort->set_active( aSortData.bNaturalSort );
598     m_xBtnIncComments->set_active( aSortData.aDataAreaExtras.mbCellNotes );
599     m_xBtnIncImages->set_active( aSortData.aDataAreaExtras.mbCellDrawObjects );
600 
601     LanguageType eLang = LanguageTag::convertToLanguageType( aSortData.aCollatorLocale, false);
602     if ( eLang == LANGUAGE_DONTKNOW )
603         eLang = LANGUAGE_SYSTEM;
604     m_xLbLanguage->set_active_id(eLang);
605     FillAlgor();               // get algorithms, select default
606     if ( !aSortData.aCollatorAlgorithm.isEmpty() )
607         m_xLbAlgorithm->set_active_text(m_xColRes->GetTranslation(aSortData.aCollatorAlgorithm));
608 
609     if ( pDoc && !aSortData.bInplace )
610     {
611         ScRefFlags nFormat = (aSortData.nDestTab != pViewData->GetTabNo())
612                             ? ScRefFlags::RANGE_ABS_3D
613                             : ScRefFlags::RANGE_ABS;
614 
615         theOutPos.Set( aSortData.nDestCol,
616                        aSortData.nDestRow,
617                        aSortData.nDestTab );
618 
619         OUString aStr(theOutPos.Format(nFormat, pDoc, pDoc->GetAddressConvention()));
620         m_xBtnCopyResult->set_active(true);
621         m_xLbOutPos->set_sensitive(true);
622         m_xEdOutPos->set_sensitive(true);
623         m_xEdOutPos->set_text( aStr );
624         EdOutPosModHdl();
625         m_xEdOutPos->grab_focus();
626         m_xEdOutPos->select_region(0, -1);
627     }
628     else
629     {
630         m_xBtnCopyResult->set_active( false );
631         m_xLbOutPos->set_sensitive(false);
632         m_xEdOutPos->set_sensitive(false);
633         m_xEdOutPos->set_text( OUString() );
634     }
635 }
636 
FillItemSet(SfxItemSet * rArgSet)637 bool ScTabPageSortOptions::FillItemSet( SfxItemSet* rArgSet )
638 {
639     // Create local copy of ScParam
640     ScSortParam aNewSortData = aSortData;
641 
642     const SfxItemSet* pExample = GetDialogExampleSet();
643     if (pExample)
644     {
645         if (const ScSortItem* pSortItem = pExample->GetItemIfSet(nWhichSort))
646             aNewSortData = pSortItem->GetSortData();
647     }
648     aNewSortData.bCaseSens       = m_xBtnCase->get_active();
649     aNewSortData.bNaturalSort    = m_xBtnNaturalSort->get_active();
650     aNewSortData.aDataAreaExtras.mbCellNotes = m_xBtnIncComments->get_active();
651     aNewSortData.aDataAreaExtras.mbCellDrawObjects = m_xBtnIncImages->get_active();
652     aNewSortData.aDataAreaExtras.mbCellFormats = m_xBtnFormats->get_active();
653     aNewSortData.bInplace        = !m_xBtnCopyResult->get_active();
654     aNewSortData.nDestCol        = theOutPos.Col();
655     aNewSortData.nDestRow        = theOutPos.Row();
656     aNewSortData.nDestTab        = theOutPos.Tab();
657     aNewSortData.bUserDef        = m_xBtnSortUser->get_active();
658     aNewSortData.nUserIndex      = (m_xBtnSortUser->get_active())
659                                    ? m_xLbSortUser->get_active()
660                                    : 0;
661 
662     // get locale
663     LanguageType eLang = m_xLbLanguage->get_active_id();
664     aNewSortData.aCollatorLocale = LanguageTag::convertToLocale( eLang, false);
665 
666     // get algorithm
667     OUString sAlg;
668     if ( eLang != LANGUAGE_SYSTEM )
669     {
670         uno::Sequence<OUString> aAlgos = m_oColWrap->listCollatorAlgorithms(
671                 aNewSortData.aCollatorLocale );
672         const int nSel = m_xLbAlgorithm->get_active();
673         if ( nSel < aAlgos.getLength() )
674             sAlg = aAlgos[nSel];
675     }
676     aNewSortData.aCollatorAlgorithm = sAlg;
677 
678     rArgSet->Put( ScSortItem( SCITEM_SORTDATA, &aNewSortData ) );
679 
680     return true;
681 }
682 
683 // for data exchange without dialogue detour:
ActivatePage(const SfxItemSet & rSet)684 void ScTabPageSortOptions::ActivatePage( const SfxItemSet& rSet )
685 {
686     // Refresh local copy with shared data
687     aSortData = rSet.Get( SCITEM_SORTDATA ).GetSortData();
688     ScSortDlg* pDlg = static_cast<ScSortDlg*>(GetDialogController());
689     if (!pDlg)
690         return;
691 
692     if (aSortData.bByRow)
693     {
694         m_xBtnIncComments->set_label(aStrCommentsRowLabel);
695         m_xBtnIncImages->set_label(aStrImgRowLabel);
696     }
697     else
698     {
699         m_xBtnIncComments->set_label(aStrCommentsColLabel);
700         m_xBtnIncImages->set_label(aStrImgColLabel);
701     }
702 }
703 
DeactivatePage(SfxItemSet * pSetP)704 DeactivateRC ScTabPageSortOptions::DeactivatePage( SfxItemSet* pSetP )
705 {
706     bool bPosInputOk = true;
707 
708     if ( m_xBtnCopyResult->get_active() )
709     {
710         OUString    thePosStr = m_xEdOutPos->get_text();
711         ScAddress   thePos;
712         sal_Int32   nColonPos = thePosStr.indexOf( ':' );
713 
714         if ( -1 != nColonPos )
715             thePosStr = thePosStr.copy( 0, nColonPos );
716 
717         if ( pViewData )
718         {
719             //  visible table is default for input without table
720             //  must be changed to GetRefTabNo when sorting has RefInput!
721             thePos.SetTab( pViewData->GetTabNo() );
722         }
723 
724         ScRefFlags nResult = thePos.Parse( thePosStr, *pDoc, pDoc->GetAddressConvention() );
725 
726         bPosInputOk = (nResult & ScRefFlags::VALID) == ScRefFlags::VALID;
727 
728         if ( !bPosInputOk )
729         {
730             std::unique_ptr<weld::MessageDialog> xBox(Application::CreateMessageDialog(GetFrameWeld(),
731                                                       VclMessageType::Warning, VclButtonsType::Ok,
732                                                       ScResId(STR_INVALID_TABREF)));
733             xBox->run();
734             m_xEdOutPos->grab_focus();
735             m_xEdOutPos->select_region(0, -1);
736             theOutPos.Set(0,0,0);
737         }
738         else
739         {
740             m_xEdOutPos->set_text(thePosStr);
741             theOutPos = thePos;
742         }
743     }
744 
745     if ( pSetP && bPosInputOk )
746         FillItemSet( pSetP );
747 
748     return bPosInputOk ? DeactivateRC::LeavePage : DeactivateRC::KeepPage;
749 }
750 
FillUserSortListBox()751 void ScTabPageSortOptions::FillUserSortListBox()
752 {
753     ScUserList& rUserLists = ScGlobal::GetUserList();
754 
755     m_xLbSortUser->clear();
756     size_t nCount = rUserLists.size();
757     for (size_t i=0; i<nCount; ++i)
758         m_xLbSortUser->append_text(rUserLists[i].GetString());
759 }
760 
761 // Handler:
762 
IMPL_LINK(ScTabPageSortOptions,EnableHdl,weld::Toggleable &,rButton,void)763 IMPL_LINK( ScTabPageSortOptions, EnableHdl, weld::Toggleable&, rButton, void )
764 {
765     if (&rButton == m_xBtnCopyResult.get())
766     {
767         if (rButton.get_active())
768         {
769             m_xLbOutPos->set_sensitive(true);
770             m_xEdOutPos->set_sensitive(true);
771             m_xEdOutPos->grab_focus();
772         }
773         else
774         {
775             m_xLbOutPos->set_sensitive(false);
776             m_xEdOutPos->set_sensitive(false);
777         }
778     }
779     else if (&rButton == m_xBtnSortUser.get())
780     {
781         if (rButton.get_active())
782         {
783             m_xLbSortUser->set_sensitive(true);
784             m_xLbSortUser->grab_focus();
785         }
786         else
787             m_xLbSortUser->set_sensitive(false);
788     }
789 }
790 
IMPL_LINK(ScTabPageSortOptions,SelOutPosHdl,weld::ComboBox &,rLb,void)791 IMPL_LINK(ScTabPageSortOptions, SelOutPosHdl, weld::ComboBox&, rLb, void)
792 {
793     if (&rLb == m_xLbOutPos.get())
794     {
795         OUString  aString;
796         const int nSelPos = m_xLbOutPos->get_active();
797 
798         if (nSelPos > 0)
799             aString = m_xLbOutPos->get_id(nSelPos);
800 
801         m_xEdOutPos->set_text(aString);
802     }
803 }
804 
EdOutPosModHdl()805 void ScTabPageSortOptions::EdOutPosModHdl()
806 {
807     OUString  theCurPosStr = m_xEdOutPos->get_text();
808     ScRefFlags  nResult = ScAddress().Parse( theCurPosStr, *pDoc, pDoc->GetAddressConvention() );
809 
810     if ( (nResult & ScRefFlags::VALID) != ScRefFlags::VALID )
811         return;
812 
813     bool    bFound  = false;
814     sal_Int32 i = 0;
815     const int nCount = m_xLbOutPos->get_count();
816 
817     for ( i=2; i<nCount && !bFound; i++ )
818     {
819         OUString aStr = m_xLbOutPos->get_id(i);
820         bFound = (theCurPosStr == aStr);
821     }
822 
823     if ( bFound )
824         m_xLbOutPos->set_active(--i);
825     else
826         m_xLbOutPos->set_active(0);
827 }
828 
FillAlgor()829 void ScTabPageSortOptions::FillAlgor()
830 {
831     tools::Long nCount = 0;
832 
833     m_xLbAlgorithm->freeze();
834     m_xLbAlgorithm->clear();
835 
836     LanguageType eLang = m_xLbLanguage->get_active_id();
837     if ( eLang == LANGUAGE_SYSTEM )
838     {
839         //  for LANGUAGE_SYSTEM no algorithm can be selected because
840         //  it wouldn't necessarily exist for other languages
841         //  -> leave list box empty if LANGUAGE_SYSTEM is selected
842         m_xFtAlgorithm->set_sensitive( false );           // nothing to select
843         m_xLbAlgorithm->set_sensitive( false );           // nothing to select
844     }
845     else
846     {
847         lang::Locale aLocale( LanguageTag::convertToLocale( eLang ));
848         const uno::Sequence<OUString> aAlgos = m_oColWrap->listCollatorAlgorithms( aLocale );
849 
850         nCount = aAlgos.getLength();
851         for (const OUString& sAlg : aAlgos)
852         {
853             OUString sUser = m_xColRes->GetTranslation( sAlg );
854             m_xLbAlgorithm->append_text(sUser);
855         }
856     }
857 
858     m_xLbAlgorithm->thaw();
859 
860     m_xLbAlgorithm->set_active(nCount ? 0 : -1);    // first entry is default
861     m_xFtAlgorithm->set_sensitive(nCount > 1);      // enable only if there is a choice
862     m_xLbAlgorithm->set_sensitive(nCount > 1);      // enable only if there is a choice
863 }
864 
IMPL_LINK_NOARG(ScTabPageSortOptions,FillAlgorHdl,weld::ComboBox &,void)865 IMPL_LINK_NOARG(ScTabPageSortOptions, FillAlgorHdl, weld::ComboBox&, void)
866 {
867     FillAlgor();
868 }
869 
870 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
871