1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
21 #include <sal/config.h>
25 #include <comphelper/string.hxx>
26 #include <unotools/charclass.hxx>
27 #include <vcl/svapp.hxx>
28 #include <vcl/weld.hxx>
30 #include <reffact.hxx>
31 #include <document.hxx>
32 #include <globstr.hrc>
33 #include <scresid.hxx>
34 #include <rangenam.hxx>
35 #include <globalnames.hxx>
36 #include <dbnamdlg.hxx>
37 #include <dbdocfun.hxx>
45 static std::unique_ptr
<DBSaveData
> xSaveObj
;
49 void ERRORBOX(weld::Window
* pParent
, const OUString
& rString
)
51 std::unique_ptr
<weld::MessageDialog
> xBox(Application::CreateMessageDialog(pParent
,
52 VclMessageType::Warning
, VclButtonsType::Ok
,
61 DBSaveData( formula::RefEdit
& rEd
, weld::CheckButton
& rHdr
, weld::CheckButton
& rTot
, weld::CheckButton
& rSize
, weld::CheckButton
& rFmt
,
62 weld::CheckButton
& rStrip
, ScRange
& rArea
)
82 formula::RefEdit
& rEdAssign
;
83 weld::CheckButton
& rBtnHeader
;
84 weld::CheckButton
& rBtnTotals
;
85 weld::CheckButton
& rBtnSize
;
86 weld::CheckButton
& rBtnFormat
;
87 weld::CheckButton
& rBtnStrip
;
101 void DBSaveData::Save()
104 aStr
= rEdAssign
.GetText();
105 bHeader
= rBtnHeader
.get_active();
106 bTotals
= rBtnTotals
.get_active();
107 bSize
= rBtnSize
.get_active();
108 bFormat
= rBtnFormat
.get_active();
109 bStrip
= rBtnStrip
.get_active();
113 void DBSaveData::Restore()
118 rEdAssign
.SetText( aStr
);
119 rBtnHeader
.set_active ( bHeader
);
120 rBtnTotals
.set_active ( bTotals
);
121 rBtnSize
.set_active ( bSize
);
122 rBtnFormat
.set_active ( bFormat
);
123 rBtnStrip
.set_active ( bStrip
);
129 ScDbNameDlg::ScDbNameDlg(SfxBindings
* pB
, SfxChildWindow
* pCW
, weld::Window
* pParent
,
130 ScViewData
& rViewData
)
131 : ScAnyRefDlgController(pB
, pCW
, pParent
,
132 "modules/scalc/ui/definedatabaserangedialog.ui", "DefineDatabaseRangeDialog")
133 , m_rViewData(rViewData
)
134 , rDoc(rViewData
.GetDocument())
135 , bRefInputMode(false)
136 , aAddrDetails(rDoc
.GetAddressConvention(), 0, 0)
137 , aLocalDbCol(*(rDoc
.GetDBCollection()))
138 , m_xEdName(m_xBuilder
->weld_entry_tree_view("entrygrid", "entry", "entry-list"))
139 , m_xAssignFrame(m_xBuilder
->weld_frame("RangeFrame"))
140 , m_xEdAssign(new formula::RefEdit(m_xBuilder
->weld_entry("assign")))
141 , m_xRbAssign(new formula::RefButton(m_xBuilder
->weld_button("assignrb")))
142 , m_xOptions(m_xBuilder
->weld_widget("Options"))
143 , m_xBtnHeader(m_xBuilder
->weld_check_button("ContainsColumnLabels"))
144 , m_xBtnTotals(m_xBuilder
->weld_check_button("ContainsTotalsRow"))
145 , m_xBtnDoSize(m_xBuilder
->weld_check_button("InsertOrDeleteCells"))
146 , m_xBtnKeepFmt(m_xBuilder
->weld_check_button("KeepFormatting"))
147 , m_xBtnStripData(m_xBuilder
->weld_check_button("DontSaveImportedData"))
148 , m_xFTSource(m_xBuilder
->weld_label("Source"))
149 , m_xFTOperations(m_xBuilder
->weld_label("Operations"))
150 , m_xBtnOk(m_xBuilder
->weld_button("ok"))
151 , m_xBtnCancel(m_xBuilder
->weld_button("cancel"))
152 , m_xBtnAdd(m_xBuilder
->weld_button("add"))
153 , m_xBtnRemove(m_xBuilder
->weld_button("delete"))
154 , m_xModifyPB(m_xBuilder
->weld_button("modify"))
155 , m_xInvalidFT(m_xBuilder
->weld_label("invalid"))
156 , m_xFrameLabel(m_xAssignFrame
->weld_label_widget())
157 , m_xExpander(m_xBuilder
->weld_expander("more"))
159 m_xEdName
->set_height_request_by_rows(4);
160 m_xEdAssign
->SetReferences(this, m_xFrameLabel
.get());
161 m_xRbAssign
->SetReferences(this, m_xEdAssign
.get());
162 aStrAdd
= m_xBtnAdd
->get_label();
163 aStrModify
= m_xModifyPB
->get_label();
164 aStrInvalid
= m_xInvalidFT
->get_label();
166 // so that the strings in the resource can stay with fixed texts:
167 aStrSource
= m_xFTSource
->get_label();
168 aStrOperations
= m_xFTOperations
->get_label();
170 xSaveObj
.reset(new DBSaveData( *m_xEdAssign
, *m_xBtnHeader
, *m_xBtnTotals
,
171 *m_xBtnDoSize
, *m_xBtnKeepFmt
, *m_xBtnStripData
, theCurArea
));
175 ScDbNameDlg::~ScDbNameDlg()
180 void ScDbNameDlg::Init()
182 m_xBtnHeader
->set_active(true); // Default: with column headers
183 m_xBtnTotals
->set_active( false ); // Default: without totals row
184 m_xBtnDoSize
->set_active(true);
185 m_xBtnKeepFmt
->set_active(true);
187 m_xBtnOk
->connect_clicked ( LINK( this, ScDbNameDlg
, OkBtnHdl
) );
188 m_xBtnCancel
->connect_clicked ( LINK( this, ScDbNameDlg
, CancelBtnHdl
) );
189 m_xBtnAdd
->connect_clicked ( LINK( this, ScDbNameDlg
, AddBtnHdl
) );
190 m_xBtnRemove
->connect_clicked ( LINK( this, ScDbNameDlg
, RemoveBtnHdl
) );
191 m_xEdName
->connect_changed( LINK( this, ScDbNameDlg
, NameModifyHdl
) );
192 m_xEdAssign
->SetModifyHdl ( LINK( this, ScDbNameDlg
, AssModifyHdl
) );
204 ScDBCollection
* pDBColl
= rDoc
.GetDBCollection();
206 m_rViewData
.GetSimpleArea( nStartCol
, nStartRow
, nStartTab
,
207 nEndCol
, nEndRow
, nEndTab
);
209 theCurArea
= ScRange( nStartCol
, nStartRow
, nStartTab
, nEndCol
, nEndRow
, nEndTab
);
211 theAreaStr
= theCurArea
.Format(rDoc
, ScRefFlags::RANGE_ABS_3D
, aAddrDetails
);
215 // determine if the defined DB area has been marked:
216 ScDBData
* pDBData
= pDBColl
->GetDBAtCursor( nStartCol
, nStartRow
, nStartTab
, ScDBDataPortion::TOP_LEFT
);
219 ScAddress
& rStart
= theCurArea
.aStart
;
220 ScAddress
& rEnd
= theCurArea
.aEnd
;
227 pDBData
->GetArea( nTab
, nCol1
, nRow1
, nCol2
, nRow2
);
229 if ( (rStart
.Tab() == nTab
)
230 && (rStart
.Col() == nCol1
) && (rStart
.Row() == nRow1
)
231 && (rEnd
.Col() == nCol2
) && (rEnd
.Row() == nRow2
) )
233 OUString aDBName
= pDBData
->GetName();
234 if ( aDBName
!= STR_DB_LOCAL_NONAME
)
235 m_xEdName
->set_entry_text(aDBName
);
237 m_xBtnHeader
->set_active( pDBData
->HasHeader() );
238 m_xBtnTotals
->set_active( pDBData
->HasTotals() );
239 m_xBtnDoSize
->set_active( pDBData
->IsDoSize() );
240 m_xBtnKeepFmt
->set_active( pDBData
->IsKeepFmt() );
241 m_xBtnStripData
->set_active( pDBData
->IsStripData() );
242 SetInfoStrings( pDBData
);
247 m_xEdAssign
->SetText( theAreaStr
);
248 m_xEdName
->grab_focus();
251 NameModifyHdl( *m_xEdName
);
255 void ScDbNameDlg::SetInfoStrings( const ScDBData
* pDBData
)
258 aBuf
.append(aStrSource
);
262 aBuf
.append(pDBData
->GetSourceString());
264 m_xFTSource
->set_label(aBuf
.makeStringAndClear());
266 aBuf
.append(aStrOperations
);
270 aBuf
.append(pDBData
->GetOperations());
272 m_xFTOperations
->set_label(aBuf
.makeStringAndClear());
275 // Transfer of a table area selected with the mouse, which is then displayed
276 // as a new selection in the reference window.
278 void ScDbNameDlg::SetReference( const ScRange
& rRef
, ScDocument
& rDocP
)
280 if (!m_xEdAssign
->GetWidget()->get_sensitive())
283 if ( rRef
.aStart
!= rRef
.aEnd
)
284 RefInputStart(m_xEdAssign
.get());
288 OUString
aRefStr(theCurArea
.Format(rDocP
, ScRefFlags::RANGE_ABS_3D
, aAddrDetails
));
289 m_xEdAssign
->SetRefString( aRefStr
);
290 m_xOptions
->set_sensitive(true);
291 m_xBtnAdd
->set_sensitive(true);
296 void ScDbNameDlg::Close()
298 DoClose( ScDbNameDlgWrapper::GetChildWindowId() );
301 void ScDbNameDlg::SetActive()
303 m_xEdAssign
->GrabFocus();
305 // No NameModifyHdl, because otherwise areas can not be changed
306 // (the old content would be displayed again after the reference selection is pulled)
307 // (the selected DB name has not changed either)
312 void ScDbNameDlg::UpdateNames()
314 typedef ScDBCollection::NamedDBs DBsType
;
316 const DBsType
& rDBs
= aLocalDbCol
.getNamedDBs();
321 m_xEdAssign
->SetText( OUString() );
325 for (const auto& rxDB
: rDBs
)
326 m_xEdName
->append_text(rxDB
->GetName());
330 m_xBtnAdd
->set_label( aStrAdd
);
331 m_xBtnAdd
->set_sensitive(false);
332 m_xBtnRemove
->set_sensitive(false);
338 void ScDbNameDlg::UpdateDBData( const OUString
& rStrName
)
341 const ScDBData
* pData
= aLocalDbCol
.getNamedDBs().findByUpperName(ScGlobal::getCharClass().uppercase(rStrName
));
351 pData
->GetArea( nTab
, nColStart
, nRowStart
, nColEnd
, nRowEnd
);
352 theCurArea
= ScRange( ScAddress( nColStart
, nRowStart
, nTab
),
353 ScAddress( nColEnd
, nRowEnd
, nTab
) );
354 OUString
theArea(theCurArea
.Format(rDoc
, ScRefFlags::RANGE_ABS_3D
, aAddrDetails
));
355 m_xEdAssign
->SetText( theArea
);
356 m_xBtnAdd
->set_label( aStrModify
);
357 m_xBtnHeader
->set_active( pData
->HasHeader() );
358 m_xBtnTotals
->set_active( pData
->HasTotals() );
359 m_xBtnDoSize
->set_active( pData
->IsDoSize() );
360 m_xBtnKeepFmt
->set_active( pData
->IsKeepFmt() );
361 m_xBtnStripData
->set_active( pData
->IsStripData() );
362 SetInfoStrings( pData
);
365 m_xBtnAdd
->set_label( aStrModify
);
366 m_xBtnAdd
->set_sensitive(true);
367 m_xBtnRemove
->set_sensitive(true);
368 m_xOptions
->set_sensitive(true);
371 bool ScDbNameDlg::IsRefInputMode() const
373 return bRefInputMode
;
378 IMPL_LINK_NOARG(ScDbNameDlg
, OkBtnHdl
, weld::Button
&, void)
381 AddBtnHdl(*m_xBtnAdd
);
383 // Pass the changes and the remove list to the view: both are
384 // transferred as a reference only, so that no dead memory can
385 // be created at this point:
388 ScDBDocFunc
aFunc(*m_rViewData
.GetDocShell());
389 aFunc
.ModifyAllDBData(aLocalDbCol
, aRemoveList
);
394 IMPL_LINK_NOARG(ScDbNameDlg
, CancelBtnHdl
, weld::Button
&, void)
396 response(RET_CANCEL
);
399 IMPL_LINK_NOARG(ScDbNameDlg
, AddBtnHdl
, weld::Button
&, void)
401 OUString aNewName
= comphelper::string::strip(m_xEdName
->get_active_text(), ' ');
402 OUString aNewArea
= m_xEdAssign
->GetText();
404 if ( aNewName
.isEmpty() || aNewArea
.isEmpty() )
407 if (ScRangeData::IsNameValid(aNewName
, rDoc
) == ScRangeData::IsNameValidType::NAME_VALID
408 && aNewName
!= STR_DB_LOCAL_NONAME
)
410 // because editing can be done now, parsing is needed first
412 OUString aText
= m_xEdAssign
->GetText();
413 if ( aTmpRange
.ParseAny( aText
, rDoc
, aAddrDetails
) & ScRefFlags::VALID
)
415 theCurArea
= aTmpRange
;
416 ScAddress aStart
= theCurArea
.aStart
;
417 ScAddress aEnd
= theCurArea
.aEnd
;
419 ScDBData
* pOldEntry
= aLocalDbCol
.getNamedDBs().findByUpperName(ScGlobal::getCharClass().uppercase(aNewName
));
424 pOldEntry
->MoveTo( aStart
.Tab(), aStart
.Col(), aStart
.Row(),
425 aEnd
.Col(), aEnd
.Row() );
426 pOldEntry
->SetByRow( true );
427 pOldEntry
->SetHeader( m_xBtnHeader
->get_active() );
428 pOldEntry
->SetTotals( m_xBtnTotals
->get_active() );
429 pOldEntry
->SetDoSize( m_xBtnDoSize
->get_active() );
430 pOldEntry
->SetKeepFmt( m_xBtnKeepFmt
->get_active() );
431 pOldEntry
->SetStripData( m_xBtnStripData
->get_active() );
437 std::unique_ptr
<ScDBData
> pNewEntry(new ScDBData( aNewName
, aStart
.Tab(),
438 aStart
.Col(), aStart
.Row(),
439 aEnd
.Col(), aEnd
.Row(),
440 true, m_xBtnHeader
->get_active(),
441 m_xBtnTotals
->get_active() ));
442 pNewEntry
->SetDoSize( m_xBtnDoSize
->get_active() );
443 pNewEntry
->SetKeepFmt( m_xBtnKeepFmt
->get_active() );
444 pNewEntry
->SetStripData( m_xBtnStripData
->get_active() );
446 bool ins
= aLocalDbCol
.getNamedDBs().insert(std::move(pNewEntry
));
447 assert(ins
); (void)ins
;
452 m_xEdName
->set_entry_text( OUString() );
453 m_xEdName
->grab_focus();
454 m_xBtnAdd
->set_label( aStrAdd
);
455 m_xBtnAdd
->set_sensitive(false);
456 m_xBtnRemove
->set_sensitive(false);
457 m_xEdAssign
->SetText( OUString() );
458 m_xBtnHeader
->set_active(true); // Default: with column headers
459 m_xBtnTotals
->set_active( false ); // Default: without totals row
460 m_xBtnDoSize
->set_active( false );
461 m_xBtnKeepFmt
->set_active( false );
462 m_xBtnStripData
->set_active( false );
463 SetInfoStrings( nullptr ); // empty
464 theCurArea
= ScRange();
467 NameModifyHdl( *m_xEdName
);
471 ERRORBOX(m_xDialog
.get(), aStrInvalid
);
472 m_xEdAssign
->SelectAll();
473 m_xEdAssign
->GrabFocus();
479 ERRORBOX(m_xDialog
.get(), ScResId(STR_INVALIDNAME
));
480 m_xEdName
->select_entry_region(0, -1);
481 m_xEdName
->grab_focus();
490 const OUString
& mrName
;
492 explicit FindByName(const OUString
& rName
) : mrName(rName
) {}
493 bool operator() (std::unique_ptr
<ScDBData
> const& p
) const
495 return p
->GetName() == mrName
;
501 IMPL_LINK_NOARG(ScDbNameDlg
, RemoveBtnHdl
, weld::Button
&, void)
503 OUString aStrEntry
= m_xEdName
->get_active_text();
504 ScDBCollection::NamedDBs
& rDBs
= aLocalDbCol
.getNamedDBs();
505 ScDBCollection::NamedDBs::iterator itr
=
506 ::std::find_if(rDBs
.begin(), rDBs
.end(), FindByName(aStrEntry
));
508 if (itr
== rDBs
.end())
511 OUString aStrDelMsg
= ScResId( STR_QUERY_DELENTRY
);
512 OUString sMsg
{ aStrDelMsg
.getToken(0, '#') + aStrEntry
+ aStrDelMsg
.getToken(1, '#') };
513 std::unique_ptr
<weld::MessageDialog
> xQueryBox(Application::CreateMessageDialog(m_xDialog
.get(),
514 VclMessageType::Question
, VclButtonsType::YesNo
,
516 xQueryBox
->set_default_response(RET_YES
);
517 if (RET_YES
!= xQueryBox
->run())
521 SCCOL nColStart
, nColEnd
;
522 SCROW nRowStart
, nRowEnd
;
523 (*itr
)->GetArea( nTab
, nColStart
, nRowStart
, nColEnd
, nRowEnd
);
524 aRemoveList
.emplace_back( ScAddress( nColStart
, nRowStart
, nTab
),
525 ScAddress( nColEnd
, nRowEnd
, nTab
) );
531 m_xEdName
->set_entry_text( OUString() );
532 m_xEdName
->grab_focus();
533 m_xBtnAdd
->set_label( aStrAdd
);
534 m_xBtnAdd
->set_sensitive(false);
535 m_xBtnRemove
->set_sensitive(false);
536 m_xEdAssign
->SetText( OUString() );
537 theCurArea
= ScRange();
538 m_xBtnHeader
->set_active(true); // Default: with column headers
539 m_xBtnTotals
->set_active( false ); // Default: without totals row
540 m_xBtnDoSize
->set_active( false );
541 m_xBtnKeepFmt
->set_active( false );
542 m_xBtnStripData
->set_active( false );
543 SetInfoStrings( nullptr ); // empty
546 NameModifyHdl( *m_xEdName
);
549 IMPL_LINK_NOARG(ScDbNameDlg
, NameModifyHdl
, weld::ComboBox
&, void)
551 OUString theName
= m_xEdName
->get_active_text();
552 bool bNameFound
= m_xEdName
->find_text(theName
) != -1;
554 if ( theName
.isEmpty() )
556 if (m_xBtnAdd
->get_label() != aStrAdd
)
557 m_xBtnAdd
->set_label( aStrAdd
);
558 m_xBtnAdd
->set_sensitive(false);
559 m_xBtnRemove
->set_sensitive(false);
560 m_xAssignFrame
->set_sensitive(false);
561 m_xOptions
->set_sensitive(false);
563 //xSaveObj->Restore();
564 //@BugID 54702 enable/disable in the base class only
565 //SFX_APPWINDOW->Disable(sal_False); //! general method in ScAnyRefDlg
566 bRefInputMode
= false;
572 if (m_xBtnAdd
->get_label() != aStrModify
)
573 m_xBtnAdd
->set_label( aStrModify
);
580 UpdateDBData( theName
);
584 if (m_xBtnAdd
->get_label() != aStrAdd
)
585 m_xBtnAdd
->set_label( aStrAdd
);
590 if ( !m_xEdAssign
->GetText().isEmpty() )
592 m_xBtnAdd
->set_sensitive(true);
593 m_xOptions
->set_sensitive(true);
597 m_xBtnAdd
->set_sensitive(false);
598 m_xOptions
->set_sensitive(false);
600 m_xBtnRemove
->set_sensitive(false);
603 m_xAssignFrame
->set_sensitive(true);
605 //@BugID 54702 enable/disable in the base class only
606 //SFX_APPWINDOW->set_sensitive(true);
607 bRefInputMode
= true;
611 IMPL_LINK_NOARG(ScDbNameDlg
, AssModifyHdl
, formula::RefEdit
&, void)
613 // parse here for Save(), etc.
616 OUString aText
= m_xEdAssign
->GetText();
617 if ( aTmpRange
.ParseAny( aText
, rDoc
, aAddrDetails
) & ScRefFlags::VALID
)
618 theCurArea
= aTmpRange
;
620 if (!aText
.isEmpty() && !m_xEdName
->get_active_text().isEmpty())
622 m_xBtnAdd
->set_sensitive(true);
623 m_xBtnHeader
->set_sensitive(true);
624 m_xBtnTotals
->set_sensitive(true);
625 m_xBtnDoSize
->set_sensitive(true);
626 m_xBtnKeepFmt
->set_sensitive(true);
627 m_xBtnStripData
->set_sensitive(true);
628 m_xFTSource
->set_sensitive(true);
629 m_xFTOperations
->set_sensitive(true);
633 m_xBtnAdd
->set_sensitive(false);
634 m_xBtnHeader
->set_sensitive(false);
635 m_xBtnTotals
->set_sensitive(false);
636 m_xBtnDoSize
->set_sensitive(false);
637 m_xBtnKeepFmt
->set_sensitive(false);
638 m_xBtnStripData
->set_sensitive(false);
639 m_xFTSource
->set_sensitive(false);
640 m_xFTOperations
->set_sensitive(false);
644 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */