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 #ifdef SC_DLLIMPLEMENTATION
21 #undef SC_DLLIMPLEMENTATION
22 #endif
23 
24 #include <com/sun/star/sheet/TableValidationVisibility.hpp>
25 #include <comphelper/string.hxx>
26 #include <vcl/svapp.hxx>
27 #include <svl/aeitem.hxx>
28 #include <svl/stritem.hxx>
29 #include <svl/eitem.hxx>
30 #include <svl/intitem.hxx>
31 #include <sfx2/app.hxx>
32 
33 #include <scresid.hxx>
34 #include <strings.hrc>
35 
36 #include <stringutil.hxx>
37 #include <validat.hxx>
38 #include <validate.hxx>
39 #include <compiler.hxx>
40 #include <formula/opcode.hxx>
41 
42 // cell range picker
43 #include <tabvwsh.hxx>
44 #include <sfx2/viewfrm.hxx>
45 #include <sfx2/childwin.hxx>
46 #include <reffact.hxx>
47 
48 /*  Position indexes for "Allow" list box.
49     They do not map directly to ScValidationMode and can safely be modified to
50     change the order of the list box entries. */
51 #define SC_VALIDDLG_ALLOW_ANY       0
52 #define SC_VALIDDLG_ALLOW_WHOLE     1
53 #define SC_VALIDDLG_ALLOW_DECIMAL   2
54 #define SC_VALIDDLG_ALLOW_DATE      3
55 #define SC_VALIDDLG_ALLOW_TIME      4
56 #define SC_VALIDDLG_ALLOW_RANGE     5
57 #define SC_VALIDDLG_ALLOW_LIST      6
58 #define SC_VALIDDLG_ALLOW_TEXTLEN   7
59 #define SC_VALIDDLG_ALLOW_CUSTOM    8
60 
61 /*  Position indexes for "Data" list box.
62     They do not map directly to ScConditionMode and can safely be modified to
63     change the order of the list box entries. */
64 #define SC_VALIDDLG_DATA_EQUAL        0
65 #define SC_VALIDDLG_DATA_LESS         1
66 #define SC_VALIDDLG_DATA_GREATER      2
67 #define SC_VALIDDLG_DATA_EQLESS       3
68 #define SC_VALIDDLG_DATA_EQGREATER    4
69 #define SC_VALIDDLG_DATA_NOTEQUAL     5
70 #define SC_VALIDDLG_DATA_VALIDRANGE   6
71 #define SC_VALIDDLG_DATA_INVALIDRANGE 7
72 #define SC_VALIDDLG_DATA_DIRECT       8
73 
74 namespace ValidListType = css::sheet::TableValidationVisibility;
75 
76 const sal_uInt16 ScTPValidationValue::pValueRanges[] =
77 {
78     FID_VALID_MODE, FID_VALID_ERRTEXT,
79     FID_VALID_LISTTYPE, FID_VALID_LISTTYPE,
80     0
81 };
82 
ScValidationDlg(weld::Window * pParent,const SfxItemSet * pArgSet,ScTabViewShell * pTabViewSh)83 ScValidationDlg::ScValidationDlg(weld::Window* pParent, const SfxItemSet* pArgSet,
84     ScTabViewShell *pTabViewSh)
85     : ScValidationDlgBase(pParent,
86         "modules/scalc/ui/validationdialog.ui", "ValidationDialog", pArgSet, nullptr)
87     , m_pTabVwSh(pTabViewSh)
88     , m_sValuePageId("criteria")
89     , m_bOwnRefHdlr(false)
90     , m_bRefInputting(false)
91     , m_xHBox(m_xBuilder->weld_container("refinputbox"))
92 {
93     AddTabPage(m_sValuePageId, ScTPValidationValue::Create, nullptr);
94     AddTabPage("inputhelp", ScTPValidationHelp::Create, nullptr);
95     AddTabPage("erroralert", ScTPValidationError::Create, nullptr);
96 }
97 
~ScValidationDlg()98 ScValidationDlg::~ScValidationDlg()
99 {
100     if (m_bOwnRefHdlr)
101         RemoveRefDlg(false);
102 }
103 
SetReferenceHdl(const ScRange & rRange,const ScDocument * pDoc)104 void ScTPValidationValue::SetReferenceHdl( const ScRange&rRange , const ScDocument* pDoc )
105 {
106     if ( rRange.aStart != rRange.aEnd )
107         if ( ScValidationDlg *pValidationDlg = GetValidationDlg() )
108             if( m_pRefEdit )
109                 pValidationDlg->RefInputStart( m_pRefEdit );
110 
111     if ( m_pRefEdit )
112     {
113         OUString aStr(rRange.Format(ScRefFlags::RANGE_ABS_3D, pDoc, pDoc->GetAddressConvention()));
114         m_pRefEdit->SetRefString( aStr );
115     }
116 }
117 
SetActiveHdl()118 void ScTPValidationValue:: SetActiveHdl()
119 {
120     if ( m_pRefEdit ) m_pRefEdit->GrabFocus();
121 
122     if ( ScValidationDlg *pValidationDlg = GetValidationDlg() )
123         if( m_pRefEdit )
124         {
125             pValidationDlg->RefInputDone();
126         }
127 }
128 
RefInputStartPreHdl(formula::RefEdit * pEdit,const formula::RefButton * pButton)129 void ScTPValidationValue::RefInputStartPreHdl( formula::RefEdit* pEdit, const formula::RefButton* pButton )
130 {
131     if (ScValidationDlg *pValidationDlg = GetValidationDlg())
132     {
133         weld::Container* pNewParent = pValidationDlg->get_refinput_shrink_parent();
134         if (pEdit == m_pRefEdit && pNewParent != m_pRefEditParent)
135         {
136             m_xRefGrid->move(m_pRefEdit->GetWidget(), pNewParent);
137             m_pRefEditParent = pNewParent;
138         }
139 
140         if (pNewParent != m_pBtnRefParent)
141         {
142             // if Edit SetParent but button not, the tab order will be
143             // incorrect, so move button anyway, and restore
144             // parent later in order to restore the tab order. But
145             // hide it if it's moved but unwanted.
146             m_xRefGrid->move(m_xBtnRef->GetWidget(), pNewParent);
147             m_xBtnRef->GetWidget()->set_visible(pButton == m_xBtnRef.get());
148             m_pBtnRefParent = pNewParent;
149         }
150 
151         pNewParent->show();
152     }
153 }
154 
RefInputDonePostHdl()155 void ScTPValidationValue::RefInputDonePostHdl()
156 {
157     if (ScValidationDlg *pValidationDlg = GetValidationDlg())
158     {
159         weld::Container* pOldParent = pValidationDlg->get_refinput_shrink_parent();
160 
161         if (m_pRefEdit && m_pRefEditParent != m_xRefGrid.get())
162         {
163             pOldParent->move(m_pRefEdit->GetWidget(), m_xRefGrid.get());
164             m_pRefEditParent = m_xRefGrid.get();
165         }
166 
167         if (m_pBtnRefParent != m_xRefGrid.get())
168         {
169             pOldParent->move(m_xBtnRef->GetWidget(), m_xRefGrid.get());
170             m_xBtnRef->GetWidget()->show();
171             m_pBtnRefParent = m_xRefGrid.get();
172         }
173 
174         pOldParent->hide();
175         ScViewData& rViewData = pValidationDlg->GetTabViewShell()->GetViewData();
176         SCTAB nCurTab = rViewData.GetTabNo();
177         SCTAB nRefTab = rViewData.GetRefTabNo();
178         // If RefInput switched to a different sheet from the data sheet,
179         // switch back: fdo#53920
180         if ( nCurTab != nRefTab )
181         {
182              rViewData.GetViewShell()->SetTabNo( nRefTab );
183         }
184     }
185 
186     if (m_pRefEdit && !m_pRefEdit->GetWidget()->has_focus())
187         m_pRefEdit->GrabFocus();
188 }
189 
190 namespace {
191 
192 /** Converts the passed ScValidationMode to the position in the list box. */
lclGetPosFromValMode(ScValidationMode eValMode)193 sal_uInt16 lclGetPosFromValMode( ScValidationMode eValMode )
194 {
195     sal_uInt16 nLbPos = SC_VALIDDLG_ALLOW_ANY;
196     switch( eValMode )
197     {
198         case SC_VALID_ANY:      nLbPos = SC_VALIDDLG_ALLOW_ANY;     break;
199         case SC_VALID_WHOLE:    nLbPos = SC_VALIDDLG_ALLOW_WHOLE;   break;
200         case SC_VALID_DECIMAL:  nLbPos = SC_VALIDDLG_ALLOW_DECIMAL; break;
201         case SC_VALID_DATE:     nLbPos = SC_VALIDDLG_ALLOW_DATE;    break;
202         case SC_VALID_TIME:     nLbPos = SC_VALIDDLG_ALLOW_TIME;    break;
203         case SC_VALID_TEXTLEN:  nLbPos = SC_VALIDDLG_ALLOW_TEXTLEN; break;
204         case SC_VALID_LIST:     nLbPos = SC_VALIDDLG_ALLOW_RANGE;   break;
205         case SC_VALID_CUSTOM:   nLbPos = SC_VALIDDLG_ALLOW_CUSTOM;  break;
206         default:    OSL_FAIL( "lclGetPosFromValMode - unknown validity mode" );
207     }
208     return nLbPos;
209 }
210 
211 /** Converts the passed list box position to an ScValidationMode. */
lclGetValModeFromPos(sal_uInt16 nLbPos)212 ScValidationMode lclGetValModeFromPos( sal_uInt16 nLbPos )
213 {
214     ScValidationMode eValMode = SC_VALID_ANY;
215     switch( nLbPos )
216     {
217         case SC_VALIDDLG_ALLOW_ANY:     eValMode = SC_VALID_ANY;        break;
218         case SC_VALIDDLG_ALLOW_WHOLE:   eValMode = SC_VALID_WHOLE;      break;
219         case SC_VALIDDLG_ALLOW_DECIMAL: eValMode = SC_VALID_DECIMAL;    break;
220         case SC_VALIDDLG_ALLOW_DATE:    eValMode = SC_VALID_DATE;       break;
221         case SC_VALIDDLG_ALLOW_TIME:    eValMode = SC_VALID_TIME;       break;
222         case SC_VALIDDLG_ALLOW_RANGE:   eValMode = SC_VALID_LIST;       break;
223         case SC_VALIDDLG_ALLOW_LIST:    eValMode = SC_VALID_LIST;       break;
224         case SC_VALIDDLG_ALLOW_TEXTLEN: eValMode = SC_VALID_TEXTLEN;    break;
225         case SC_VALIDDLG_ALLOW_CUSTOM:  eValMode = SC_VALID_CUSTOM;     break;
226         default:    OSL_FAIL( "lclGetValModeFromPos - invalid list box position" );
227     }
228     return eValMode;
229 }
230 
231 /** Converts the passed ScConditionMode to the position in the list box. */
lclGetPosFromCondMode(ScConditionMode eCondMode)232 sal_uInt16 lclGetPosFromCondMode( ScConditionMode eCondMode )
233 {
234     sal_uInt16 nLbPos = SC_VALIDDLG_DATA_EQUAL;
235     switch( eCondMode )
236     {
237         case ScConditionMode::NONE:          // may occur in old XML files after Excel import
238         case ScConditionMode::Equal:         nLbPos = SC_VALIDDLG_DATA_EQUAL;        break;
239         case ScConditionMode::Less:          nLbPos = SC_VALIDDLG_DATA_LESS;         break;
240         case ScConditionMode::Greater:       nLbPos = SC_VALIDDLG_DATA_GREATER;      break;
241         case ScConditionMode::EqLess:        nLbPos = SC_VALIDDLG_DATA_EQLESS;       break;
242         case ScConditionMode::EqGreater:     nLbPos = SC_VALIDDLG_DATA_EQGREATER;    break;
243         case ScConditionMode::NotEqual:      nLbPos = SC_VALIDDLG_DATA_NOTEQUAL;     break;
244         case ScConditionMode::Between:       nLbPos = SC_VALIDDLG_DATA_VALIDRANGE;      break;
245         case ScConditionMode::NotBetween:    nLbPos = SC_VALIDDLG_DATA_INVALIDRANGE;   break;
246         case ScConditionMode::Direct:        nLbPos = SC_VALIDDLG_DATA_DIRECT;         break;
247         default:    OSL_FAIL( "lclGetPosFromCondMode - unknown condition mode" );
248     }
249     return nLbPos;
250 }
251 
252 /** Converts the passed list box position to an ScConditionMode. */
lclGetCondModeFromPos(sal_uInt16 nLbPos)253 ScConditionMode lclGetCondModeFromPos( sal_uInt16 nLbPos )
254 {
255     ScConditionMode eCondMode = ScConditionMode::Equal;
256     switch( nLbPos )
257     {
258         case SC_VALIDDLG_DATA_EQUAL:        eCondMode = ScConditionMode::Equal;      break;
259         case SC_VALIDDLG_DATA_LESS:         eCondMode = ScConditionMode::Less;       break;
260         case SC_VALIDDLG_DATA_GREATER:      eCondMode = ScConditionMode::Greater;    break;
261         case SC_VALIDDLG_DATA_EQLESS:       eCondMode = ScConditionMode::EqLess;     break;
262         case SC_VALIDDLG_DATA_EQGREATER:    eCondMode = ScConditionMode::EqGreater;  break;
263         case SC_VALIDDLG_DATA_NOTEQUAL:     eCondMode = ScConditionMode::NotEqual;   break;
264         case SC_VALIDDLG_DATA_VALIDRANGE:      eCondMode = ScConditionMode::Between;    break;
265         case SC_VALIDDLG_DATA_INVALIDRANGE:   eCondMode = ScConditionMode::NotBetween; break;
266         case SC_VALIDDLG_DATA_DIRECT:         eCondMode = ScConditionMode::Direct;   break;
267         default:    OSL_FAIL( "lclGetCondModeFromPos - invalid list box position" );
268     }
269     return eCondMode;
270 }
271 
272 /** Converts line feed separated string to a formula with strings separated by semicolons.
273     @descr  Keeps all empty strings.
274     Example: abc\ndef\n\nghi -> "abc";"def";"";"ghi".
275     @param rFmlaStr  (out-param) The converted formula string. */
lclGetFormulaFromStringList(OUString & rFmlaStr,const OUString & rStringList,sal_Unicode cFmlaSep)276 void lclGetFormulaFromStringList( OUString& rFmlaStr, const OUString& rStringList, sal_Unicode cFmlaSep )
277 {
278     rFmlaStr.clear();
279     if (!rStringList.isEmpty())
280     {
281         sal_Int32 nIdx {0};
282         do
283         {
284             OUString aToken {rStringList.getToken( 0, '\n', nIdx )};
285             ScGlobal::AddQuotes( aToken, '"' );
286             rFmlaStr = ScGlobal::addToken(rFmlaStr, aToken, cFmlaSep);
287         }
288         while (nIdx>0);
289     }
290     if( rFmlaStr.isEmpty() )
291         rFmlaStr = "\"\"";
292 }
293 
294 /** Converts formula with strings separated by semicolons to line feed separated string.
295     @descr  Keeps all empty strings. Ignores all empty tokens (multiple semicolons).
296     Example: "abc";;;"def";"";"ghi" -> abc\ndef\n\nghi.
297     @param rStringList  (out-param) The converted line feed separated string list.
298     @return  true = Conversion successful. */
lclGetStringListFromFormula(OUString & rStringList,const OUString & rFmlaStr,sal_Unicode cFmlaSep)299 bool lclGetStringListFromFormula( OUString& rStringList, const OUString& rFmlaStr, sal_Unicode cFmlaSep )
300 {
301     const OUString aQuotes( "\"\"" );
302 
303     rStringList.clear();
304     bool bIsStringList = !rFmlaStr.isEmpty();
305     bool bTokenAdded = false;
306 
307     for ( sal_Int32 nStringIx = 0; bIsStringList && nStringIx>=0; )
308     {
309         OUString aToken( ScStringUtil::GetQuotedToken(rFmlaStr, 0, aQuotes, cFmlaSep, nStringIx ) );
310         aToken = comphelper::string::strip(aToken, ' ');
311         if( !aToken.isEmpty() )      // ignore empty tokens, i.e. "a";;"b"
312         {
313             bIsStringList = ScGlobal::IsQuoted( aToken, '"' );
314             if( bIsStringList )
315             {
316                 ScGlobal::EraseQuotes( aToken, '"' );
317                 rStringList = ScGlobal::addToken(rStringList, aToken, '\n', 1, bTokenAdded);
318                 bTokenAdded = true;
319             }
320         }
321     }
322 
323     return bIsStringList;
324 }
325 
326 } // namespace
327 
ScTPValidationValue(weld::Container * pPage,weld::DialogController * pController,const SfxItemSet & rArgSet)328 ScTPValidationValue::ScTPValidationValue(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& rArgSet)
329     : SfxTabPage(pPage, pController, "modules/scalc/ui/validationcriteriapage.ui",
330                  "ValidationCriteriaPage", &rArgSet)
331     , maStrMin(ScResId(SCSTR_VALID_MINIMUM))
332     , maStrMax(ScResId(SCSTR_VALID_MAXIMUM))
333     , maStrValue(ScResId(SCSTR_VALID_VALUE))
334     , maStrFormula(ScResId(SCSTR_VALID_FORMULA))
335     , maStrRange(ScResId(SCSTR_VALID_RANGE))
336     , maStrList(ScResId(SCSTR_VALID_LIST))
337     , m_pRefEdit(nullptr)
338     , m_xLbAllow(m_xBuilder->weld_combo_box("allow"))
339     , m_xCbAllow(m_xBuilder->weld_check_button("allowempty"))
340     , m_xCbShow(m_xBuilder->weld_check_button("showlist"))
341     , m_xCbSort(m_xBuilder->weld_check_button("sortascend"))
342     , m_xFtValue(m_xBuilder->weld_label("valueft"))
343     , m_xLbValue(m_xBuilder->weld_combo_box("data"))
344     , m_xFtMin(m_xBuilder->weld_label("minft"))
345     , m_xMinGrid(m_xBuilder->weld_widget("mingrid"))
346     , m_xEdMin(new formula::RefEdit(m_xBuilder->weld_entry("min")))
347     , m_xEdList(m_xBuilder->weld_text_view("minlist"))
348     , m_xFtMax(m_xBuilder->weld_label("maxft"))
349     , m_xEdMax(new formula::RefEdit(m_xBuilder->weld_entry("max")))
350     , m_xFtHint(m_xBuilder->weld_label("hintft"))
351     , m_xBtnRef(new formula::RefButton(m_xBuilder->weld_button("validref")))
352     , m_xRefGrid(m_xBuilder->weld_container("refgrid"))
353     , m_pRefEditParent(m_xRefGrid.get())
354     , m_pBtnRefParent(m_xRefGrid.get())
355 {
356     m_xEdMin->SetReferences(nullptr, m_xFtMin.get());
357 
358     Size aSize(m_xEdList->get_approximate_digit_width() * 40,
359                m_xEdList->get_height_rows(25));
360     m_xEdList->set_size_request(aSize.Width(), aSize.Height());
361     m_xEdMax->SetReferences(nullptr, m_xFtMax.get());
362 
363     m_xBtnRef->SetClickHdl(LINK(this, ScTPValidationValue, ClickHdl));
364 
365     //lock in the max size initial config
366     aSize = m_xContainer->get_preferred_size();
367     m_xContainer->set_size_request(aSize.Width(), aSize.Height());
368 
369     Init();
370 
371     // list separator in formulas
372     OUString aListSep = ::ScCompiler::GetNativeSymbol( ocSep );
373     OSL_ENSURE( aListSep.getLength() == 1, "ScTPValidationValue::ScTPValidationValue - list separator error" );
374     mcFmlaSep = aListSep.getLength() ? aListSep[0] : ';';
375     m_xBtnRef->GetWidget()->hide(); // cell range picker
376 }
377 
~ScTPValidationValue()378 ScTPValidationValue::~ScTPValidationValue()
379 {
380     m_xEdMin.reset();
381     m_xEdMin.reset();
382     m_xEdMax.reset();
383     m_xBtnRef.reset();
384     m_xEdMax.reset();
385 }
386 
Init()387 void ScTPValidationValue::Init()
388 {
389     m_xLbAllow->connect_changed( LINK( this, ScTPValidationValue, SelectHdl ) );
390     m_xLbValue->connect_changed( LINK( this, ScTPValidationValue, SelectHdl ) );
391     m_xCbShow->connect_clicked( LINK( this, ScTPValidationValue, CheckHdl ) );
392 
393     // cell range picker
394     m_xEdMin->SetGetFocusHdl( LINK( this, ScTPValidationValue, EditSetFocusHdl ) );
395     m_xEdMin->SetLoseFocusHdl( LINK( this, ScTPValidationValue, KillEditFocusHdl ) );
396     m_xEdMax->SetGetFocusHdl( LINK( this, ScTPValidationValue, EditSetFocusHdl ) );
397     m_xBtnRef->SetLoseFocusHdl( LINK( this, ScTPValidationValue, KillButtonFocusHdl ) );
398     m_xEdMax->SetLoseFocusHdl( LINK( this, ScTPValidationValue, KillEditFocusHdl ) );
399 
400     m_xLbAllow->set_active( SC_VALIDDLG_ALLOW_ANY );
401     m_xLbValue->set_active( SC_VALIDDLG_DATA_EQUAL );
402 
403     SelectHdl( *m_xLbAllow );
404     CheckHdl( *m_xCbShow );
405 }
406 
Create(weld::Container * pPage,weld::DialogController * pController,const SfxItemSet * rArgSet)407 std::unique_ptr<SfxTabPage> ScTPValidationValue::Create(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet* rArgSet)
408 {
409     return std::make_unique<ScTPValidationValue>(pPage, pController, *rArgSet);
410 }
411 
Reset(const SfxItemSet * rArgSet)412 void ScTPValidationValue::Reset( const SfxItemSet* rArgSet )
413 {
414     const SfxPoolItem* pItem;
415 
416     sal_uInt16 nLbPos = SC_VALIDDLG_ALLOW_ANY;
417     if( rArgSet->GetItemState( FID_VALID_MODE, true, &pItem ) == SfxItemState::SET )
418         nLbPos = lclGetPosFromValMode( static_cast< ScValidationMode >(
419             static_cast< const SfxUInt16Item* >( pItem )->GetValue() ) );
420     m_xLbAllow->set_active( nLbPos );
421 
422     nLbPos = SC_VALIDDLG_DATA_EQUAL;
423     if( rArgSet->GetItemState( FID_VALID_CONDMODE, true, &pItem ) == SfxItemState::SET )
424         nLbPos = lclGetPosFromCondMode( static_cast< ScConditionMode >(
425             static_cast< const SfxUInt16Item* >( pItem )->GetValue() ) );
426     m_xLbValue->set_active( nLbPos );
427 
428     // *** check boxes ***
429     bool bCheck = true;
430     if( rArgSet->GetItemState( FID_VALID_BLANK, true, &pItem ) == SfxItemState::SET )
431         bCheck = static_cast< const SfxBoolItem* >( pItem )->GetValue();
432     m_xCbAllow->set_active( bCheck );
433 
434     sal_Int32 nListType = ValidListType::UNSORTED;
435     if( rArgSet->GetItemState( FID_VALID_LISTTYPE, true, &pItem ) == SfxItemState::SET )
436         nListType = static_cast< const SfxInt16Item* >( pItem )->GetValue();
437     m_xCbShow->set_active( nListType != ValidListType::INVISIBLE );
438     m_xCbSort->set_active( nListType == ValidListType::SORTEDASCENDING );
439 
440     // *** formulas ***
441     OUString aFmlaStr;
442     if ( rArgSet->GetItemState( FID_VALID_VALUE1, true, &pItem ) == SfxItemState::SET )
443         aFmlaStr = static_cast< const SfxStringItem* >( pItem )->GetValue();
444     SetFirstFormula( aFmlaStr );
445 
446     aFmlaStr.clear();
447     if ( rArgSet->GetItemState( FID_VALID_VALUE2, true, &pItem ) == SfxItemState::SET )
448         aFmlaStr = static_cast< const SfxStringItem* >( pItem )->GetValue();
449     SetSecondFormula( aFmlaStr );
450 
451     SelectHdl( *m_xLbAllow );
452     CheckHdl( *m_xCbShow );
453 }
454 
FillItemSet(SfxItemSet * rArgSet)455 bool ScTPValidationValue::FillItemSet( SfxItemSet* rArgSet )
456 {
457     sal_Int16 nListType = m_xCbShow->get_active() ?
458         (m_xCbSort->get_active() ? ValidListType::SORTEDASCENDING : ValidListType::UNSORTED) :
459         ValidListType::INVISIBLE;
460 
461     const sal_Int32 nLbPos = m_xLbAllow->get_active();
462     bool bCustom = (nLbPos == SC_VALIDDLG_ALLOW_CUSTOM);
463     ScConditionMode eCondMode = bCustom ?
464             ScConditionMode::Direct : lclGetCondModeFromPos( m_xLbValue->get_active() );
465 
466     rArgSet->Put( SfxUInt16Item( FID_VALID_MODE, sal::static_int_cast<sal_uInt16>(
467                     lclGetValModeFromPos( nLbPos ) ) ) );
468     rArgSet->Put( SfxUInt16Item( FID_VALID_CONDMODE, sal::static_int_cast<sal_uInt16>( eCondMode ) ) );
469     rArgSet->Put( SfxStringItem( FID_VALID_VALUE1, GetFirstFormula() ) );
470     rArgSet->Put( SfxStringItem( FID_VALID_VALUE2, GetSecondFormula() ) );
471     rArgSet->Put( SfxBoolItem( FID_VALID_BLANK, m_xCbAllow->get_active() ) );
472     rArgSet->Put( SfxInt16Item( FID_VALID_LISTTYPE, nListType ) );
473     return true;
474 }
475 
GetFirstFormula() const476 OUString ScTPValidationValue::GetFirstFormula() const
477 {
478     OUString aFmlaStr;
479     if( m_xLbAllow->get_active() == SC_VALIDDLG_ALLOW_LIST )
480         lclGetFormulaFromStringList( aFmlaStr, m_xEdList->get_text(), mcFmlaSep );
481     else
482         aFmlaStr = m_xEdMin->GetText();
483     return aFmlaStr;
484 }
485 
GetSecondFormula() const486 OUString ScTPValidationValue::GetSecondFormula() const
487 {
488     return m_xEdMax->GetText();
489 }
490 
SetFirstFormula(const OUString & rFmlaStr)491 void ScTPValidationValue::SetFirstFormula( const OUString& rFmlaStr )
492 {
493     // try if formula is a string list, validation mode must already be set
494     OUString aStringList;
495     if( (m_xLbAllow->get_active() == SC_VALIDDLG_ALLOW_RANGE) &&
496         lclGetStringListFromFormula( aStringList, rFmlaStr, mcFmlaSep ) )
497     {
498         m_xEdList->set_text( aStringList );
499         m_xEdMin->SetText( EMPTY_OUSTRING );
500         // change validation mode to string list
501         m_xLbAllow->set_active( SC_VALIDDLG_ALLOW_LIST );
502     }
503     else
504     {
505         m_xEdMin->SetText( rFmlaStr );
506         m_xEdList->set_text( EMPTY_OUSTRING );
507     }
508 }
509 
SetSecondFormula(const OUString & rFmlaStr)510 void ScTPValidationValue::SetSecondFormula( const OUString& rFmlaStr )
511 {
512     m_xEdMax->SetText( rFmlaStr );
513 }
514 
GetValidationDlg()515 ScValidationDlg * ScTPValidationValue::GetValidationDlg()
516 {
517     return dynamic_cast<ScValidationDlg*>(GetDialogController());
518 }
519 
SetupRefDlg()520 void ScTPValidationValue::SetupRefDlg()
521 {
522     if( ScValidationDlg *pValidationDlg = GetValidationDlg() )
523     {
524         if( pValidationDlg->SetupRefDlg() )
525         {
526             pValidationDlg->SetHandler( this );
527             pValidationDlg->SetSetRefHdl( static_cast<ScRefHandlerHelper::PFUNCSETREFHDLTYPE>( &ScTPValidationValue::SetReferenceHdl ) );
528             pValidationDlg->SetSetActHdl( static_cast<ScRefHandlerHelper::PCOMMONHDLTYPE>( &ScTPValidationValue::SetActiveHdl ) );
529             pValidationDlg->SetRefInputStartPreHdl( static_cast<ScRefHandlerHelper::PINPUTSTARTDLTYPE>( &ScTPValidationValue::RefInputStartPreHdl ) );
530             pValidationDlg->SetRefInputDonePostHdl( static_cast<ScRefHandlerHelper::PCOMMONHDLTYPE>( &ScTPValidationValue::RefInputDonePostHdl ) );
531 
532             weld::Label* pLabel = nullptr;
533 
534             if (m_xEdMax->GetWidget()->get_visible())
535             {
536                 m_pRefEdit = m_xEdMax.get();
537                 pLabel = m_xFtMax.get();
538             }
539             else if (m_xEdMin->GetWidget()->get_visible())
540             {
541                 m_pRefEdit = m_xEdMin.get();
542                 pLabel = m_xFtMin.get();
543             }
544 
545             if (m_pRefEdit && !m_pRefEdit->GetWidget()->has_focus())
546                 m_pRefEdit->GrabFocus();
547 
548             if( m_pRefEdit )
549                 m_pRefEdit->SetReferences( pValidationDlg, pLabel );
550 
551             m_xBtnRef->SetReferences( pValidationDlg, m_pRefEdit );
552         }
553     }
554 }
555 
RemoveRefDlg(bool bRestoreModal)556 void ScTPValidationValue::RemoveRefDlg(bool bRestoreModal)
557 {
558     if( ScValidationDlg *pValidationDlg = GetValidationDlg() )
559     {
560         if( pValidationDlg->RemoveRefDlg(bRestoreModal) )
561         {
562             pValidationDlg->SetHandler( nullptr );
563             pValidationDlg->SetSetRefHdl( nullptr );
564             pValidationDlg->SetSetActHdl( nullptr );
565             pValidationDlg->SetRefInputStartPreHdl( nullptr );
566             pValidationDlg->SetRefInputDonePostHdl( nullptr );
567 
568             if( m_pRefEdit )
569                 m_pRefEdit->SetReferences( nullptr, nullptr );
570             m_pRefEdit = nullptr;
571 
572             m_xBtnRef->SetReferences( nullptr, nullptr );
573         }
574     }
575 }
576 
IMPL_LINK_NOARG(ScTPValidationValue,EditSetFocusHdl,formula::RefEdit &,void)577 IMPL_LINK_NOARG(ScTPValidationValue, EditSetFocusHdl, formula::RefEdit&, void)
578 {
579     const sal_Int32 nPos = m_xLbAllow->get_active();
580 
581     if ( nPos == SC_VALIDDLG_ALLOW_RANGE )
582     {
583         SetupRefDlg();
584     }
585 }
586 
IMPL_LINK(ScTPValidationValue,KillEditFocusHdl,formula::RefEdit &,rWnd,void)587 IMPL_LINK( ScTPValidationValue, KillEditFocusHdl, formula::RefEdit&, rWnd, void )
588 {
589     if (&rWnd != m_pRefEdit)
590         return;
591     if( ScValidationDlg *pValidationDlg = GetValidationDlg() )
592     {
593         if (pValidationDlg->IsChildFocus() && !pValidationDlg->IsRefInputting())
594         {
595             if( ( !m_pRefEdit || !m_pRefEdit->GetWidget()->has_focus()) && !m_xBtnRef->GetWidget()->has_focus() )
596             {
597                 RemoveRefDlg(true);
598             }
599         }
600     }
601 }
602 
IMPL_LINK(ScTPValidationValue,KillButtonFocusHdl,formula::RefButton &,rWnd,void)603 IMPL_LINK( ScTPValidationValue, KillButtonFocusHdl, formula::RefButton&, rWnd, void )
604 {
605     if( &rWnd != m_xBtnRef.get())
606         return;
607     if( ScValidationDlg *pValidationDlg = GetValidationDlg() )
608         if (pValidationDlg->IsChildFocus() && !pValidationDlg->IsRefInputting())
609             if( ( !m_pRefEdit || !m_pRefEdit->GetWidget()->has_focus()) && !m_xBtnRef->GetWidget()->has_focus() )
610             {
611                 RemoveRefDlg(true);
612             }
613 }
614 
IMPL_LINK_NOARG(ScTPValidationValue,SelectHdl,weld::ComboBox &,void)615 IMPL_LINK_NOARG(ScTPValidationValue, SelectHdl, weld::ComboBox&, void)
616 {
617     const sal_Int32 nLbPos = m_xLbAllow->get_active();
618     bool bEnable = (nLbPos != SC_VALIDDLG_ALLOW_ANY);
619     bool bRange = (nLbPos == SC_VALIDDLG_ALLOW_RANGE);
620     bool bList = (nLbPos == SC_VALIDDLG_ALLOW_LIST);
621     bool bCustom = (nLbPos == SC_VALIDDLG_ALLOW_CUSTOM);
622 
623     m_xCbAllow->set_sensitive( bEnable );   // Empty cell
624     m_xFtValue->set_sensitive( bEnable );
625     m_xLbValue->set_sensitive( bEnable );
626     m_xFtMin->set_sensitive( bEnable );
627     m_xEdMin->GetWidget()->set_sensitive( bEnable );
628     m_xEdList->set_sensitive( bEnable );
629     m_xFtMax->set_sensitive( bEnable );
630     m_xEdMax->GetWidget()->set_sensitive( bEnable );
631 
632     bool bShowMax = false;
633 
634     if( bRange )
635         m_xFtMin->set_label( maStrRange );
636     else if( bList )
637         m_xFtMin->set_label( maStrList );
638     else if( bCustom )
639         m_xFtMin->set_label( maStrFormula );
640     else
641     {
642         switch( m_xLbValue->get_active() )
643         {
644             case SC_VALIDDLG_DATA_EQUAL:
645             case SC_VALIDDLG_DATA_NOTEQUAL:     m_xFtMin->set_label( maStrValue );  break;
646 
647             case SC_VALIDDLG_DATA_LESS:
648             case SC_VALIDDLG_DATA_EQLESS:       m_xFtMin->set_label( maStrMax );    break;
649 
650             case SC_VALIDDLG_DATA_VALIDRANGE:
651             case SC_VALIDDLG_DATA_INVALIDRANGE:   bShowMax = true;
652                 [[fallthrough]];
653             case SC_VALIDDLG_DATA_GREATER:
654             case SC_VALIDDLG_DATA_EQGREATER:    m_xFtMin->set_label( maStrMin );    break;
655 
656             default:
657                 OSL_FAIL( "ScTPValidationValue::SelectHdl - unknown condition mode" );
658         }
659     }
660 
661     m_xCbShow->set_visible( bRange || bList );
662     m_xCbSort->set_visible( bRange || bList );
663     m_xFtValue->set_visible( !bRange && !bList && !bCustom);
664     m_xLbValue->set_visible( !bRange && !bList && !bCustom );
665     m_xEdMin->GetWidget()->set_visible( !bList );
666     m_xEdList->set_visible( bList );
667     m_xMinGrid->set_vexpand( bList );
668     m_xFtMax->set_visible( bShowMax );
669     m_xEdMax->GetWidget()->set_visible( bShowMax );
670     m_xFtHint->set_visible( bRange );
671     m_xBtnRef->GetWidget()->set_visible( bRange );  // cell range picker
672 }
673 
IMPL_LINK_NOARG(ScTPValidationValue,CheckHdl,weld::Button &,void)674 IMPL_LINK_NOARG(ScTPValidationValue, CheckHdl, weld::Button&, void)
675 {
676     m_xCbSort->set_sensitive( m_xCbShow->get_active() );
677 }
678 
679 // Input Help Page
680 
ScTPValidationHelp(weld::Container * pPage,weld::DialogController * pController,const SfxItemSet & rArgSet)681 ScTPValidationHelp::ScTPValidationHelp(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& rArgSet)
682     : SfxTabPage(pPage, pController, "modules/scalc/ui/validationhelptabpage.ui", "ValidationHelpTabPage", &rArgSet)
683     , m_xTsbHelp(m_xBuilder->weld_check_button("tsbhelp"))
684     , m_xEdtTitle(m_xBuilder->weld_entry("title"))
685     , m_xEdInputHelp(m_xBuilder->weld_text_view("inputhelp"))
686 {
687     m_xEdInputHelp->set_size_request(m_xEdInputHelp->get_approximate_digit_width() * 40, m_xEdInputHelp->get_height_rows(13));
688 }
689 
~ScTPValidationHelp()690 ScTPValidationHelp::~ScTPValidationHelp()
691 {
692 }
693 
Create(weld::Container * pPage,weld::DialogController * pController,const SfxItemSet * rArgSet)694 std::unique_ptr<SfxTabPage> ScTPValidationHelp::Create(weld::Container* pPage, weld::DialogController* pController,
695                                               const SfxItemSet* rArgSet)
696 {
697     return std::make_unique<ScTPValidationHelp>(pPage, pController, *rArgSet);
698 }
699 
Reset(const SfxItemSet * rArgSet)700 void ScTPValidationHelp::Reset( const SfxItemSet* rArgSet )
701 {
702     const SfxPoolItem* pItem;
703 
704     if ( rArgSet->GetItemState( FID_VALID_SHOWHELP, true, &pItem ) == SfxItemState::SET )
705         m_xTsbHelp->set_state( static_cast<const SfxBoolItem*>(pItem)->GetValue() ? TRISTATE_TRUE : TRISTATE_FALSE );
706     else
707         m_xTsbHelp->set_state( TRISTATE_FALSE );
708 
709     if ( rArgSet->GetItemState( FID_VALID_HELPTITLE, true, &pItem ) == SfxItemState::SET )
710         m_xEdtTitle->set_text( static_cast<const SfxStringItem*>(pItem)->GetValue() );
711     else
712         m_xEdtTitle->set_text( EMPTY_OUSTRING );
713 
714     if ( rArgSet->GetItemState( FID_VALID_HELPTEXT, true, &pItem ) == SfxItemState::SET )
715         m_xEdInputHelp->set_text( static_cast<const SfxStringItem*>(pItem)->GetValue() );
716     else
717         m_xEdInputHelp->set_text( EMPTY_OUSTRING );
718 }
719 
FillItemSet(SfxItemSet * rArgSet)720 bool ScTPValidationHelp::FillItemSet( SfxItemSet* rArgSet )
721 {
722     rArgSet->Put( SfxBoolItem( FID_VALID_SHOWHELP, m_xTsbHelp->get_state() == TRISTATE_TRUE ) );
723     rArgSet->Put( SfxStringItem( FID_VALID_HELPTITLE, m_xEdtTitle->get_text() ) );
724     rArgSet->Put( SfxStringItem( FID_VALID_HELPTEXT, m_xEdInputHelp->get_text() ) );
725 
726     return true;
727 }
728 
729 // Error Alert Page
730 
ScTPValidationError(weld::Container * pPage,weld::DialogController * pController,const SfxItemSet & rArgSet)731 ScTPValidationError::ScTPValidationError(weld::Container* pPage, weld::DialogController* pController,
732                                          const SfxItemSet& rArgSet)
733 
734     :   SfxTabPage      ( pPage, pController,
735                           "modules/scalc/ui/erroralerttabpage.ui", "ErrorAlertTabPage",
736                           &rArgSet )
737     , m_xTsbShow(m_xBuilder->weld_check_button("tsbshow"))
738     , m_xLbAction(m_xBuilder->weld_combo_box("actionCB"))
739     , m_xBtnSearch(m_xBuilder->weld_button("browseBtn"))
740     , m_xEdtTitle(m_xBuilder->weld_entry("erroralert_title"))
741     , m_xFtError(m_xBuilder->weld_label("errormsg_label"))
742     , m_xEdError(m_xBuilder->weld_text_view("errorMsg"))
743 {
744     m_xEdError->set_size_request(m_xEdError->get_approximate_digit_width() * 40, m_xEdError->get_height_rows(12));
745     Init();
746 }
747 
~ScTPValidationError()748 ScTPValidationError::~ScTPValidationError()
749 {
750 }
751 
Init()752 void ScTPValidationError::Init()
753 {
754     m_xLbAction->connect_changed(LINK(this, ScTPValidationError, SelectActionHdl));
755     m_xBtnSearch->connect_clicked(LINK( this, ScTPValidationError, ClickSearchHdl));
756 
757     m_xLbAction->set_active(0);
758 
759     SelectActionHdl(*m_xLbAction);
760 }
761 
Create(weld::Container * pPage,weld::DialogController * pController,const SfxItemSet * rArgSet)762 std::unique_ptr<SfxTabPage> ScTPValidationError::Create(weld::Container* pPage, weld::DialogController* pController,
763                                                const SfxItemSet* rArgSet)
764 {
765     return std::make_unique<ScTPValidationError>(pPage, pController, *rArgSet);
766 }
767 
Reset(const SfxItemSet * rArgSet)768 void ScTPValidationError::Reset( const SfxItemSet* rArgSet )
769 {
770     const SfxPoolItem* pItem;
771 
772     if ( rArgSet->GetItemState( FID_VALID_SHOWERR, true, &pItem ) == SfxItemState::SET )
773         m_xTsbShow->set_state( static_cast<const SfxBoolItem*>(pItem)->GetValue() ? TRISTATE_TRUE : TRISTATE_FALSE );
774     else
775         m_xTsbShow->set_state( TRISTATE_TRUE );   // check by default
776 
777     if ( rArgSet->GetItemState( FID_VALID_ERRSTYLE, true, &pItem ) == SfxItemState::SET )
778         m_xLbAction->set_active( static_cast<const SfxUInt16Item*>(pItem)->GetValue() );
779     else
780         m_xLbAction->set_active( 0 );
781 
782     if ( rArgSet->GetItemState( FID_VALID_ERRTITLE, true, &pItem ) == SfxItemState::SET )
783         m_xEdtTitle->set_text( static_cast<const SfxStringItem*>(pItem)->GetValue() );
784     else
785         m_xEdtTitle->set_text( EMPTY_OUSTRING );
786 
787     if ( rArgSet->GetItemState( FID_VALID_ERRTEXT, true, &pItem ) == SfxItemState::SET )
788         m_xEdError->set_text( static_cast<const SfxStringItem*>(pItem)->GetValue() );
789     else
790         m_xEdError->set_text( EMPTY_OUSTRING );
791 
792     SelectActionHdl(*m_xLbAction);
793 }
794 
FillItemSet(SfxItemSet * rArgSet)795 bool ScTPValidationError::FillItemSet( SfxItemSet* rArgSet )
796 {
797     rArgSet->Put( SfxBoolItem( FID_VALID_SHOWERR, m_xTsbShow->get_state() == TRISTATE_TRUE ) );
798     rArgSet->Put( SfxUInt16Item( FID_VALID_ERRSTYLE, m_xLbAction->get_active() ) );
799     rArgSet->Put( SfxStringItem( FID_VALID_ERRTITLE, m_xEdtTitle->get_text() ) );
800     rArgSet->Put( SfxStringItem( FID_VALID_ERRTEXT, m_xEdError->get_text() ) );
801 
802     return true;
803 }
804 
IMPL_LINK_NOARG(ScTPValidationError,SelectActionHdl,weld::ComboBox &,void)805 IMPL_LINK_NOARG(ScTPValidationError, SelectActionHdl, weld::ComboBox&, void)
806 {
807     ScValidErrorStyle eStyle = static_cast<ScValidErrorStyle>(m_xLbAction->get_active());
808     bool bMacro = ( eStyle == SC_VALERR_MACRO );
809 
810     m_xBtnSearch->set_sensitive( bMacro );
811     m_xFtError->set_sensitive( !bMacro );
812     m_xEdError->set_sensitive( !bMacro );
813 }
814 
IMPL_LINK_NOARG(ScTPValidationError,ClickSearchHdl,weld::Button &,void)815 IMPL_LINK_NOARG(ScTPValidationError, ClickSearchHdl, weld::Button&, void)
816 {
817     // Use static SfxApplication method to bring up selector dialog for
818     // choosing a script
819     OUString aScriptURL = SfxApplication::ChooseScript(GetFrameWeld());
820 
821     if ( !aScriptURL.isEmpty() )
822     {
823         m_xEdtTitle->set_text( aScriptURL );
824     }
825 }
826 
EnterRefStatus()827 bool ScValidationDlg::EnterRefStatus()
828 {
829     ScTabViewShell *pTabViewShell = GetTabViewShell();
830 
831     if( !pTabViewShell ) return false;
832 
833     sal_uInt16 nId  = SLOTID;
834     SfxViewFrame* pViewFrm = pTabViewShell->GetViewFrame();
835     SfxChildWindow* pWnd = pViewFrm->GetChildWindow( nId );
836 
837     if (pWnd && pWnd->GetController().get() != this) pWnd = nullptr;
838 
839     SC_MOD()->SetRefDialog( nId, pWnd == nullptr );
840 
841     return true;
842 }
843 
LeaveRefStatus()844 bool ScValidationDlg::LeaveRefStatus()
845 {
846     ScTabViewShell *pTabViewShell = GetTabViewShell();
847 
848     if( !pTabViewShell ) return false;
849 
850     sal_uInt16 nId  = SLOTID;
851     SfxViewFrame* pViewFrm = pTabViewShell->GetViewFrame();
852     if ( pViewFrm->GetChildWindow( nId ) )
853     {
854         DoClose( nId );
855     }
856     return true;
857 }
858 
SetupRefDlg()859 bool ScValidationDlg::SetupRefDlg()
860 {
861     if ( m_bOwnRefHdlr ) return false;
862     if( EnterRefMode() )
863     {
864         SetModal( false );
865         return  m_bOwnRefHdlr = true && EnterRefStatus();
866     }
867 
868     return false;
869 }
870 
RemoveRefDlg(bool bRestoreModal)871 bool ScValidationDlg::RemoveRefDlg( bool bRestoreModal /* = true */ )
872 {
873     bool bVisLock = false;
874     bool bFreeWindowLock = false;
875 
876     ScTabViewShell *pTabVwSh = GetTabViewShell();
877 
878     if( !pTabVwSh ) return false;
879 
880     if ( SfxChildWindow* pWnd = pTabVwSh->GetViewFrame()->GetChildWindow( SID_VALIDITY_REFERENCE ) )
881     {
882         bVisLock = static_cast<ScValidityRefChildWin*>(pWnd)->LockVisible( true );
883         bFreeWindowLock = static_cast<ScValidityRefChildWin*>(pWnd)->LockFreeWindow( true );
884     }
885 
886     if ( !m_bOwnRefHdlr ) return false;
887     if( LeaveRefStatus() && LeaveRefMode() )
888     {
889         m_bOwnRefHdlr = false;
890 
891         if( bRestoreModal )
892         {
893             SetModal( true );
894         }
895     }
896 
897     if ( SfxChildWindow* pWnd = pTabVwSh->GetViewFrame()->GetChildWindow( SID_VALIDITY_REFERENCE ) )
898     {
899         static_cast<ScValidityRefChildWin*>(pWnd)->LockVisible( bVisLock );
900         static_cast<ScValidityRefChildWin*>(pWnd)->LockFreeWindow( bFreeWindowLock );
901     }
902 
903     return true;
904 }
905 
IMPL_LINK_NOARG(ScTPValidationValue,ClickHdl,formula::RefButton &,void)906 IMPL_LINK_NOARG(ScTPValidationValue, ClickHdl, formula::RefButton&, void)
907 {
908     SetupRefDlg();
909 }
910 
IsChildFocus() const911 bool ScValidationDlg::IsChildFocus() const
912 {
913     return m_xDialog->has_toplevel_focus();
914 }
915 
916 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
917