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 .
20 #include "tablespage.hxx"
21 #include "dbu_dlg.hrc"
22 #include "dsitems.hxx"
23 #include "browserids.hxx"
24 #include "datasourceconnector.hxx"
25 #include <comphelper/types.hxx>
26 #include <connectivity/dbtools.hxx>
27 #include <connectivity/dbexception.hxx>
28 #include "stringlistitem.hxx"
29 #include <svl/eitem.hxx>
30 #include <svl/stritem.hxx>
31 #include "dbustrings.hrc"
32 #include <vcl/svapp.hxx>
33 #include <vcl/settings.hxx>
34 #include <vcl/waitobj.hxx>
35 #include <com/sun/star/i18n/Collator.hpp>
36 #include <com/sun/star/sdb/SQLContext.hpp>
37 #include <com/sun/star/sdbcx/XTablesSupplier.hpp>
38 #include <com/sun/star/sdbcx/XAppend.hpp>
39 #include <com/sun/star/util/XModifiable.hpp>
40 #include <com/sun/star/sdbcx/XDrop.hpp>
41 #include <com/sun/star/sdbcx/XDataDefinitionSupplier.hpp>
42 #include "sqlmessage.hxx"
43 #include <vcl/msgbox.hxx>
44 #include "dbaccess_helpid.hrc"
45 #include "UITools.hxx"
46 #include <osl/mutex.hxx>
47 #include <osl/diagnose.h>
48 #include <svtools/imgdef.hxx>
49 #include "svtools/treelistentry.hxx"
50 #include "TablesSingleDlg.hxx"
51 #include <tools/diagnose_ex.h>
52 #include <comphelper/processfactory.hxx>
53 #include <cppuhelper/exc_hlp.hxx>
58 using namespace ::com::sun::star::uno
;
59 using namespace ::com::sun::star::sdbc
;
60 using namespace ::com::sun::star::sdbcx
;
61 using namespace ::com::sun::star::sdb
;
62 using namespace ::com::sun::star::beans
;
63 using namespace ::com::sun::star::lang
;
64 using namespace ::com::sun::star::i18n
;
65 using namespace ::com::sun::star::container
;
66 using namespace ::com::sun::star::frame
;
67 using namespace ::com::sun::star::util
;
68 using namespace ::dbtools
;
69 using namespace ::comphelper
;
71 // OTableSubscriptionPage
72 OTableSubscriptionPage::OTableSubscriptionPage(vcl::Window
* pParent
, const SfxItemSet
& _rCoreAttrs
,
73 OTableSubscriptionDialog
* _pTablesDlg
)
74 : OGenericAdministrationPage(pParent
, "TablesFilterPage",
75 "dbaccess/ui/tablesfilterpage.ui", _rCoreAttrs
)
76 , m_bCatalogAtStart(true)
77 , m_pTablesDlg(_pTablesDlg
)
79 get(m_pTables
, "TablesFilterPage");
81 get(m_pTablesList
, "treeview");
82 m_pTablesList
->init(true);
83 m_pTablesList
->set_width_request(56 * m_pTablesList
->approximate_char_width());
84 m_pTablesList
->set_height_request(12 * m_pTablesList
->GetTextHeight());
86 m_pTablesList
->SetCheckHandler(getControlModifiedLink());
88 // initialize the TabListBox
89 m_pTablesList
->SetSelectionMode( MULTIPLE_SELECTION
);
90 m_pTablesList
->SetDragDropMode( DragDropMode::NONE
);
91 m_pTablesList
->EnableInplaceEditing( false );
92 m_pTablesList
->SetStyle(m_pTablesList
->GetStyle() | WB_BORDER
| WB_HASLINES
| WB_HASLINESATROOT
| WB_SORT
| WB_HASBUTTONS
| WB_HSCROLL
|WB_HASBUTTONSATROOT
);
94 m_pTablesList
->Clear();
96 m_pTablesList
->SetCheckButtonHdl(LINK(this, OTableSubscriptionPage
, OnTreeEntryChecked
));
97 m_pTablesList
->SetCheckHandler(LINK(this, OTableSubscriptionPage
, OnTreeEntryChecked
));
100 OTableSubscriptionPage::~OTableSubscriptionPage()
105 void OTableSubscriptionPage::dispose()
107 // just to make sure that our connection will be removed
110 ::comphelper::disposeComponent(m_xCurrentConnection
);
112 catch (RuntimeException
&) { }
114 m_pTablesList
.clear();
115 m_pTablesDlg
.clear();
116 OGenericAdministrationPage::dispose();
119 void OTableSubscriptionPage::StateChanged( StateChangedType nType
)
121 OGenericAdministrationPage::StateChanged( nType
);
123 if ( nType
== StateChangedType::ControlBackground
)
125 // Check if we need to get new images for normal/high contrast mode
126 m_pTablesList
->notifyHiContrastChanged();
129 void OTableSubscriptionPage::DataChanged( const DataChangedEvent
& rDCEvt
)
131 OGenericAdministrationPage::DataChanged( rDCEvt
);
133 if ((( rDCEvt
.GetType() == DataChangedEventType::SETTINGS
) ||
134 ( rDCEvt
.GetType() == DataChangedEventType::DISPLAY
)) &&
135 ( rDCEvt
.GetFlags() & AllSettingsFlags::STYLE
))
137 // Check if we need to get new images for normal/high contrast mode
138 m_pTablesList
->notifyHiContrastChanged();
141 void OTableSubscriptionPage::resizeControls(const Size
& _rDiff
)
143 if ( _rDiff
.Height() )
145 Size aOldSize
= m_pTablesList
->GetSizePixel();
146 aOldSize
.Height() -= _rDiff
.Height();
147 m_pTablesList
->SetPosSizePixel(
148 m_pTablesList
->GetPosPixel()+Point(0,_rDiff
.Height()),
153 void OTableSubscriptionPage::implCheckTables(const Sequence
< OUString
>& _rTables
)
155 // the meta data for the current connection, used for splitting up table names
156 Reference
< XDatabaseMetaData
> xMeta
;
159 if (m_xCurrentConnection
.is())
160 xMeta
= m_xCurrentConnection
->getMetaData();
164 OSL_FAIL("OTableSubscriptionPage::implCheckTables : could not retrieve the current connection's meta data!");
170 // check the ones which are in the list
171 OUString sCatalog
, sSchema
, sName
;
173 SvTreeListEntry
* pRootEntry
= m_pTablesList
->getAllObjectsEntry();
175 const OUString
* pIncludeTable
= _rTables
.getConstArray();
176 for (sal_Int32 i
=0; i
<_rTables
.getLength(); ++i
, ++pIncludeTable
)
179 qualifiedNameComponents(xMeta
, pIncludeTable
->getStr(), sCatalog
, sSchema
, sName
,::dbtools::eInDataManipulation
);
181 sName
= pIncludeTable
->getStr();
183 bool bAllTables
= (1 == sName
.getLength()) && ('%' == sName
[0]);
184 bool bAllSchemas
= (1 == sSchema
.getLength()) && ('%' == sSchema
[0]);
187 SvTreeListEntry
* pCatalog
= m_pTablesList
->GetEntryPosByName(sCatalog
, pRootEntry
);
188 if (!(pCatalog
|| sCatalog
.isEmpty()))
189 // the table (resp. its catalog) referred in this filter entry does not exist anymore
192 if (bAllSchemas
&& pCatalog
)
194 m_pTablesList
->checkWildcard(pCatalog
);
199 SvTreeListEntry
* pSchema
= m_pTablesList
->GetEntryPosByName(sSchema
, (pCatalog
? pCatalog
: pRootEntry
));
200 if (!(pSchema
|| sSchema
.isEmpty()))
201 // the table (resp. its schema) referred in this filter entry does not exist anymore
204 if (bAllTables
&& pSchema
)
206 m_pTablesList
->checkWildcard(pSchema
);
210 SvTreeListEntry
* pEntry
= m_pTablesList
->GetEntryPosByName(sName
, pSchema
? pSchema
: (pCatalog
? pCatalog
: pRootEntry
) );
212 m_pTablesList
->SetCheckButtonState(pEntry
, SV_BUTTON_CHECKED
);
214 m_pTablesList
->CheckButtons();
217 void OTableSubscriptionPage::implCompleteTablesCheck( const ::com::sun::star::uno::Sequence
< OUString
>& _rTableFilter
)
219 if (!_rTableFilter
.getLength())
220 { // no tables visible
225 if ((1 == _rTableFilter
.getLength()) && _rTableFilter
[0] == "%")
226 { // all tables visible
230 implCheckTables( _rTableFilter
);
234 void OTableSubscriptionPage::implInitControls(const SfxItemSet
& _rSet
, bool _bSaveValue
)
236 // check whether or not the selection is invalid or readonly (invalid implies readonly, but not vice versa)
237 bool bValid
, bReadonly
;
238 getFlags(_rSet
, bValid
, bReadonly
);
240 // get the name of the data source we're working for
241 SFX_ITEMSET_GET(_rSet
, pNameItem
, SfxStringItem
, DSID_NAME
, true);
242 OSL_ENSURE(pNameItem
, "OTableSubscriptionPage::implInitControls: missing the name attribute!");
243 OUString sDSName
= pNameItem
->GetValue();
245 if (bValid
&& !sDSName
.isEmpty() && !m_xCurrentConnection
.is() )
246 { // get the current table list from the connection for the current settings
248 // the PropertyValues for the current dialog settings
249 Sequence
< PropertyValue
> aConnectionParams
;
250 OSL_ENSURE(m_pTablesDlg
, "OTableSubscriptionPage::implInitControls: need a parent dialog doing the translation!");
253 if (!m_pTablesDlg
->getCurrentSettings(aConnectionParams
))
255 m_pTablesList
->Clear();
256 m_pTablesDlg
->endExecution();
261 if (!m_xCollator
.is())
263 // the collator for the string compares
266 m_xCollator
= Collator::create(m_xORB
);
267 m_xCollator
->loadDefaultCollator(Application::GetSettings().GetLanguageTag().getLocale(), 0);
269 catch(const Exception
&)
271 DBG_UNHANDLED_EXCEPTION();
275 // fill the table list with this connection information
276 SQLExceptionInfo aErrorInfo
;
280 sURL
= m_pTablesDlg
->getConnectionURL();
284 WaitObject
aWaitCursor(this);
285 m_pTablesList
->GetModel()->SetSortMode(SortAscending
);
286 m_pTablesList
->GetModel()->SetCompareHdl(LINK(this, OTableSubscriptionPage
, OnTreeEntryCompare
));
288 Reference
< XDriver
> xDriver
;
289 Reference
<XPropertySet
> xProp
= m_pTablesDlg
->getCurrentDataSource();
290 OSL_ENSURE(xProp
.is(),"No data source set!");
293 Any aTableFilter
= xProp
->getPropertyValue(PROPERTY_TABLEFILTER
);
294 Any aTableTypeFilter
= xProp
->getPropertyValue(PROPERTY_TABLETYPEFILTER
);
296 Reference
<XModifiable
> xModi(getDataSourceOrModel(xProp
),UNO_QUERY
);
297 bool bModified
= ( xModi
.is() && xModi
->isModified() );
299 Sequence
< OUString
> aNewTableFilter(1);
300 aNewTableFilter
[0] = "%";
301 xProp
->setPropertyValue(PROPERTY_TABLEFILTER
,makeAny(aNewTableFilter
));
303 xProp
->setPropertyValue( PROPERTY_TABLETYPEFILTER
, makeAny( Sequence
< OUString
>() ) );
304 Reference
< ::com::sun::star::lang::XEventListener
> xEvt
;
305 aErrorInfo
= ::dbaui::createConnection(xProp
, m_xORB
, xEvt
, m_xCurrentConnection
);
307 xProp
->setPropertyValue(PROPERTY_TABLEFILTER
,aTableFilter
);
308 xProp
->setPropertyValue(PROPERTY_TABLETYPEFILTER
,aTableTypeFilter
);
310 if ( xModi
.is() && !bModified
)
311 xModi
->setModified(sal_False
);
315 if ( m_xCurrentConnection
.is() )
317 m_pTablesList
->UpdateTableList( m_xCurrentConnection
);
319 m_pTablesDlg
->successfullyConnected();
322 catch (const SQLException
&)
324 aErrorInfo
= ::cppu::getCaughtException();
327 if (aErrorInfo
.isValid())
329 // establishing the connection failed. Show an error window and exit.
330 ScopedVclPtrInstance
< OSQLMessageBox
> aMessageBox( GetParentDialog(), aErrorInfo
);
331 aMessageBox
->Execute();
332 m_pTables
->Enable(false);
333 m_pTablesList
->Clear();
337 m_pTablesDlg
->clearPassword();
338 m_pTablesDlg
->endExecution();
343 // in addition, we need some infos about the connection used
344 m_sCatalogSeparator
= "."; // (default)
345 m_bCatalogAtStart
= true; // (default)
348 Reference
< XDatabaseMetaData
> xMeta
;
349 if (m_xCurrentConnection
.is())
350 xMeta
= m_xCurrentConnection
->getMetaData();
351 if (xMeta
.is() && xMeta
->supportsCatalogsInDataManipulation())
353 m_sCatalogSeparator
= xMeta
->getCatalogSeparator();
354 m_bCatalogAtStart
= xMeta
->isCatalogAtStart();
359 DBG_UNHANDLED_EXCEPTION();
364 // get the current table filter
365 SFX_ITEMSET_GET(_rSet
, pTableFilter
, OStringListItem
, DSID_TABLEFILTER
, true);
366 Sequence
< OUString
> aTableFilter
;
368 aTableFilter
= pTableFilter
->getList();
370 implCompleteTablesCheck( aTableFilter
);
372 // expand the first entry by default
373 SvTreeListEntry
* pExpand
= m_pTablesList
->getAllObjectsEntry();
376 m_pTablesList
->Expand(pExpand
);
377 pExpand
= m_pTablesList
->FirstChild(pExpand
);
378 if (pExpand
&& SvTreeList::NextSibling(pExpand
))
382 // update the toolbox according the current selection and check state
383 OGenericAdministrationPage::implInitControls(_rSet
, _bSaveValue
);
386 void OTableSubscriptionPage::CheckAll( bool _bCheck
)
388 SvButtonState eState
= _bCheck
? SV_BUTTON_CHECKED
: SV_BUTTON_UNCHECKED
;
389 SvTreeListEntry
* pEntry
= m_pTablesList
->First();
392 m_pTablesList
->SetCheckButtonState( pEntry
, eState
);
393 pEntry
= m_pTablesList
->Next(pEntry
);
396 if (_bCheck
&& m_pTablesList
->getAllObjectsEntry())
397 m_pTablesList
->checkWildcard(m_pTablesList
->getAllObjectsEntry());
400 SfxTabPage::sfxpg
OTableSubscriptionPage::DeactivatePage(SfxItemSet
* _pSet
)
402 sfxpg nResult
= OGenericAdministrationPage::DeactivatePage(_pSet
);
404 // dispose the connection, we don't need it anymore, so we're not wasting resources
407 ::comphelper::disposeComponent(m_xCurrentConnection
);
409 catch (RuntimeException
&) { }
413 IMPL_LINK( OTableSubscriptionPage
, OnTreeEntryChecked
, Control
*, _pControl
)
415 return OnControlModified(_pControl
);
417 IMPL_LINK( OTableSubscriptionPage
, OnTreeEntryCompare
, const SvSortData
*, _pSortData
)
419 const SvTreeListEntry
* pLHS
= static_cast<const SvTreeListEntry
*>(_pSortData
->pLeft
);
420 const SvTreeListEntry
* pRHS
= static_cast<const SvTreeListEntry
*>(_pSortData
->pRight
);
421 OSL_ENSURE(pLHS
&& pRHS
, "SbaTableQueryBrowser::OnTreeEntryCompare: invalid tree entries!");
423 const SvLBoxString
* pLeftTextItem
= static_cast<const SvLBoxString
*>(pLHS
->GetFirstItem(SV_ITEM_ID_LBOXSTRING
));
424 const SvLBoxString
* pRightTextItem
= static_cast<const SvLBoxString
*>(pRHS
->GetFirstItem(SV_ITEM_ID_LBOXSTRING
));
425 OSL_ENSURE(pLeftTextItem
&& pRightTextItem
, "SbaTableQueryBrowser::OnTreeEntryCompare: invalid text items!");
427 OUString sLeftText
= pLeftTextItem
->GetText();
428 OUString sRightText
= pRightTextItem
->GetText();
430 sal_Int32 nCompareResult
= 0; // equal by default
432 if (m_xCollator
.is())
436 nCompareResult
= m_xCollator
->compareString(sLeftText
, sRightText
);
443 // default behaviour if we do not have a collator -> do the simple string compare
444 nCompareResult
= sLeftText
.compareTo(sRightText
);
446 return nCompareResult
;
449 Sequence
< OUString
> OTableSubscriptionPage::collectDetailedSelection() const
451 Sequence
< OUString
> aTableFilter
;
452 static const char sDot
[] = ".";
453 static const char sWildcard
[] = "%";
455 OUString sComposedName
;
456 const SvTreeListEntry
* pAllObjectsEntry
= m_pTablesList
->getAllObjectsEntry();
457 if (!pAllObjectsEntry
)
459 SvTreeListEntry
* pEntry
= m_pTablesList
->GetModel()->Next(const_cast<SvTreeListEntry
*>(pAllObjectsEntry
));
462 bool bCatalogWildcard
= false;
463 bool bSchemaWildcard
= false;
464 SvTreeListEntry
* pSchema
= NULL
;
465 SvTreeListEntry
* pCatalog
= NULL
;
467 if (m_pTablesList
->GetCheckButtonState(pEntry
) == SV_BUTTON_CHECKED
&& !m_pTablesList
->GetModel()->HasChildren(pEntry
))
468 { // checked and a leaf, which means it's no catalog, no schema, but a real table
470 if(m_pTablesList
->GetModel()->HasParent(pEntry
))
472 pSchema
= m_pTablesList
->GetModel()->GetParent(pEntry
);
473 if (pAllObjectsEntry
== pSchema
)
474 // do not want to have the root entry
478 { // it's a real schema entry, not the "all objects" root
479 if(m_pTablesList
->GetModel()->HasParent(pSchema
))
481 pCatalog
= m_pTablesList
->GetModel()->GetParent(pSchema
);
482 if (pAllObjectsEntry
== pCatalog
)
483 // do not want to have the root entry
487 { // it's a real catalog entry, not the "all objects" root
488 bCatalogWildcard
= OTableTreeListBox::isWildcardChecked(pCatalog
);
489 if (m_bCatalogAtStart
)
491 sComposedName
+= m_pTablesList
->GetEntryText( pCatalog
);
492 sComposedName
+= m_sCatalogSeparator
;
493 if (bCatalogWildcard
)
494 sComposedName
+= sWildcard
;
498 if (bCatalogWildcard
)
499 sCatalog
= sWildcard
;
502 sCatalog
+= m_sCatalogSeparator
;
503 sCatalog
+= m_pTablesList
->GetEntryText( pCatalog
);
507 bSchemaWildcard
= OTableTreeListBox::isWildcardChecked(pSchema
);
508 sComposedName
+= m_pTablesList
->GetEntryText( pSchema
);
509 sComposedName
+= sDot
;
513 sComposedName
+= sWildcard
;
515 if (!bSchemaWildcard
&& !bCatalogWildcard
)
516 sComposedName
+= m_pTablesList
->GetEntryText( pEntry
);
518 if (!m_bCatalogAtStart
&& !bCatalogWildcard
)
519 sComposedName
+= sCatalog
;
522 sal_Int32 nOldLen
= aTableFilter
.getLength();
523 aTableFilter
.realloc(nOldLen
+ 1);
525 aTableFilter
[nOldLen
] = sComposedName
;
527 // reset the composed name
528 sComposedName
.clear();
531 if (bCatalogWildcard
)
532 pEntry
= implNextSibling(pCatalog
);
533 else if (bSchemaWildcard
)
534 pEntry
= implNextSibling(pSchema
);
536 pEntry
= m_pTablesList
->GetModel()->Next(pEntry
);
542 SvTreeListEntry
* OTableSubscriptionPage::implNextSibling(SvTreeListEntry
* _pEntry
) const
544 SvTreeListEntry
* pReturn
= NULL
;
547 pReturn
= SvTreeList::NextSibling(_pEntry
);
549 pReturn
= implNextSibling(m_pTablesList
->GetParent(_pEntry
));
554 bool OTableSubscriptionPage::FillItemSet( SfxItemSet
* _rCoreAttrs
)
556 bool bValid
, bReadonly
;
557 getFlags(*_rCoreAttrs
, bValid
, bReadonly
);
559 if (!bValid
|| bReadonly
)
560 // don't store anything if the data we're working with is invalid or readonly
563 // create the output string which contains all the table names
564 if ( m_xCurrentConnection
.is() )
565 { // collect the table filter data only if we have a connection - else no tables are displayed at all
566 Sequence
< OUString
> aTableFilter
;
567 if (dbaui::OTableTreeListBox::isWildcardChecked(m_pTablesList
->getAllObjectsEntry()))
569 aTableFilter
.realloc(1);
570 aTableFilter
[0] = "%";
574 aTableFilter
= collectDetailedSelection();
576 _rCoreAttrs
->Put( OStringListItem(DSID_TABLEFILTER
, aTableFilter
) );
582 void OTableSubscriptionPage::fillControls(::std::vector
< ISaveValueWrapper
* >& /*_rControlList*/)
586 void OTableSubscriptionPage::fillWindows(::std::vector
< ISaveValueWrapper
* >& _rControlList
)
588 _rControlList
.push_back(new ODisableWrapper
<VclContainer
>(m_pTables
));
592 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */