diff options
Diffstat (limited to 'dbaccess/source/ui/control')
-rw-r--r-- | dbaccess/source/ui/control/ColumnControlWindow.cxx | 163 | ||||
-rw-r--r-- | dbaccess/source/ui/control/FieldControls.cxx | 60 | ||||
-rw-r--r-- | dbaccess/source/ui/control/FieldDescControl.cxx | 1391 | ||||
-rw-r--r-- | dbaccess/source/ui/control/RelationControl.cxx | 695 | ||||
-rw-r--r-- | dbaccess/source/ui/control/ScrollHelper.cxx | 52 | ||||
-rw-r--r-- | dbaccess/source/ui/control/SqlNameEdit.cxx | 84 | ||||
-rw-r--r-- | dbaccess/source/ui/control/TableGrantCtrl.cxx | 461 | ||||
-rw-r--r-- | dbaccess/source/ui/control/VertSplitView.cxx | 180 | ||||
-rw-r--r-- | dbaccess/source/ui/control/charsetlistbox.cxx | 69 | ||||
-rw-r--r-- | dbaccess/source/ui/control/curledit.cxx | 89 | ||||
-rw-r--r-- | dbaccess/source/ui/control/dbtreelistbox.cxx | 584 | ||||
-rw-r--r-- | dbaccess/source/ui/control/listviewitems.cxx | 68 | ||||
-rw-r--r-- | dbaccess/source/ui/control/marktree.cxx | 206 | ||||
-rw-r--r-- | dbaccess/source/ui/control/opendoccontrols.cxx | 196 | ||||
-rw-r--r-- | dbaccess/source/ui/control/sqledit.cxx | 248 | ||||
-rw-r--r-- | dbaccess/source/ui/control/tabletree.cxx | 1006 | ||||
-rw-r--r-- | dbaccess/source/ui/control/undosqledit.cxx | 34 |
17 files changed, 5586 insertions, 0 deletions
diff --git a/dbaccess/source/ui/control/ColumnControlWindow.cxx b/dbaccess/source/ui/control/ColumnControlWindow.cxx new file mode 100644 index 000000000..28a77291c --- /dev/null +++ b/dbaccess/source/ui/control/ColumnControlWindow.cxx @@ -0,0 +1,163 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <ColumnControlWindow.hxx> +#include <unotools/syslocale.hxx> +#include <i18nlangtag/languagetag.hxx> +#include <connectivity/dbtools.hxx> +#include <UITools.hxx> +#include <core_resource.hxx> +#include <strings.hrc> +#include <com/sun/star/util/NumberFormatter.hpp> + +using namespace ::dbaui; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::beans; +using namespace ::com::sun::star::container; +using namespace ::com::sun::star::util; +using namespace ::com::sun::star::sdbc; +using namespace ::com::sun::star::lang; + +// OColumnControlWindow +OColumnControlWindow::OColumnControlWindow(vcl::Window* pParent + ,const Reference<XComponentContext>& _rxContext) + : OFieldDescControl(nullptr, pParent, nullptr) + , m_xContext(_rxContext) + , m_sTypeNames(DBA_RES(STR_TABLEDESIGN_DBFIELDTYPES)) + , m_bAutoIncrementEnabled(true) +{ + m_aLocale = SvtSysLocale().GetLanguageTag().getLocale(); +} + +void OColumnControlWindow::ActivateAggregate( EControlType eType ) +{ + switch(eType ) + { + case tpFormat: + case tpDefault: + case tpColumnName: + break; + default: + OFieldDescControl::ActivateAggregate( eType ); + } +} + +void OColumnControlWindow::DeactivateAggregate( EControlType eType ) +{ + switch(eType ) + { + case tpFormat: + case tpDefault: + case tpColumnName: + break; + default: + OFieldDescControl::DeactivateAggregate( eType ); + } +} + +void OColumnControlWindow::CellModified(long /*nRow*/, sal_uInt16 /*nColId*/ ) +{ + saveCurrentFieldDescData(); +} + +css::lang::Locale OColumnControlWindow::GetLocale() const +{ + return m_aLocale; +} + +Reference< XNumberFormatter > OColumnControlWindow::GetFormatter() const +{ + if ( !m_xFormatter.is() ) + try + { + Reference< XNumberFormatsSupplier > xSupplier(::dbtools::getNumberFormats(m_xConnection, true, m_xContext)); + + if ( xSupplier.is() ) + { + // create a new formatter + m_xFormatter.set( NumberFormatter::create(m_xContext), UNO_QUERY_THROW); + m_xFormatter->attachNumberFormatsSupplier(xSupplier); + } + } + catch(Exception&) + { + } + return m_xFormatter; +} + +TOTypeInfoSP OColumnControlWindow::getTypeInfo(sal_Int32 _nPos) +{ + return ( _nPos >= 0 && _nPos < static_cast<sal_Int32>(m_aDestTypeInfoIndex.size())) ? m_aDestTypeInfoIndex[_nPos]->second : TOTypeInfoSP(); +} + +const OTypeInfoMap* OColumnControlWindow::getTypeInfo() const +{ + return &m_aDestTypeInfo; +} + +Reference< XDatabaseMetaData> OColumnControlWindow::getMetaData() +{ + if ( m_xConnection.is() ) + return m_xConnection->getMetaData(); + return Reference< XDatabaseMetaData>(); +} + +Reference< XConnection> OColumnControlWindow::getConnection() +{ + return m_xConnection; +} + +void OColumnControlWindow::setConnection(const Reference< XConnection>& _xCon) +{ + m_xConnection = _xCon; + m_xFormatter = nullptr; + m_aDestTypeInfoIndex.clear(); + m_aDestTypeInfo.clear(); + + if ( m_xConnection.is() ) + { + Init(); + + ::dbaui::fillTypeInfo(m_xConnection,m_sTypeNames,m_aDestTypeInfo,m_aDestTypeInfoIndex); + // read autoincrement value set in the datasource + ::dbaui::fillAutoIncrementValue(m_xConnection,m_bAutoIncrementEnabled,m_sAutoIncrementValue); + } +} + +bool OColumnControlWindow::isAutoIncrementValueEnabled() const +{ + return m_bAutoIncrementEnabled; +} + +OUString OColumnControlWindow::getAutoIncrementValue() const +{ + return m_sAutoIncrementValue; +} + +TOTypeInfoSP const & OColumnControlWindow::getDefaultTyp() const +{ + if ( !m_pTypeInfo ) + { + m_pTypeInfo = std::make_shared<OTypeInfo>(); + m_pTypeInfo->aUIName = m_sTypeNames.getToken(TYPE_OTHER, ';'); + } + return m_pTypeInfo; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/control/FieldControls.cxx b/dbaccess/source/ui/control/FieldControls.cxx new file mode 100644 index 000000000..866014a99 --- /dev/null +++ b/dbaccess/source/ui/control/FieldControls.cxx @@ -0,0 +1,60 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <FieldControls.hxx> +#include <SqlNameEdit.hxx> +#include <core_resource.hxx> + +namespace dbaui { + +OPropColumnEditCtrl::OPropColumnEditCtrl(std::unique_ptr<weld::Entry> xEntry, + OUString const & _rAllowedChars, + const char* pHelpId, + short nPosition) + : OSQLNameEntry(std::move(xEntry), _rAllowedChars) + , m_nPos(nPosition) +{ + m_strHelpText = DBA_RES(pHelpId); +} + +OPropEditCtrl::OPropEditCtrl(std::unique_ptr<weld::Entry> xEntry, const char* pHelpId, short nPosition) + : OWidgetBase(xEntry.get()) + , m_xEntry(std::move(xEntry)) + , m_nPos(nPosition) +{ + m_strHelpText = DBA_RES(pHelpId); +} + +OPropNumericEditCtrl::OPropNumericEditCtrl(std::unique_ptr<weld::SpinButton> xSpinButton, const char* pHelpId, short nPosition) + : OWidgetBase(xSpinButton.get()) + , m_xSpinButton(std::move(xSpinButton)) + , m_nPos(nPosition) +{ + m_strHelpText = DBA_RES(pHelpId); +} + +OPropListBoxCtrl::OPropListBoxCtrl(std::unique_ptr<weld::ComboBox> xComboBox, const char* pHelpId, short nPosition) + : OWidgetBase(xComboBox.get()) + , m_xComboBox(std::move(xComboBox)) + , m_nPos(nPosition) +{ + m_strHelpText = DBA_RES(pHelpId); +} + +} // end namespace dbaui diff --git a/dbaccess/source/ui/control/FieldDescControl.cxx b/dbaccess/source/ui/control/FieldDescControl.cxx new file mode 100644 index 000000000..c7bb190ab --- /dev/null +++ b/dbaccess/source/ui/control/FieldDescControl.cxx @@ -0,0 +1,1391 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <core_resource.hxx> +#include <FieldDescControl.hxx> +#include <FieldControls.hxx> +#include <tools/diagnose_ex.h> +#include <TableDesignHelpBar.hxx> +#include <vcl/svapp.hxx> +#include <FieldDescriptions.hxx> +#include <svl/zforlist.hxx> +#include <svl/numuno.hxx> +#include <vcl/transfer.hxx> +#include <com/sun/star/sdbc/ColumnValue.hpp> +#include <com/sun/star/util/NumberFormat.hpp> +#include <com/sun/star/util/XNumberFormatPreviewer.hpp> +#include <com/sun/star/util/XNumberFormatTypes.hpp> +#include <com/sun/star/beans/XPropertySet.hpp> +#include <QEnumTypes.hxx> +#include <helpids.h> +#include <connectivity/dbtools.hxx> +#include <connectivity/dbconversion.hxx> +#include <comphelper/numbers.hxx> +#include <comphelper/types.hxx> +#include <UITools.hxx> +#include <strings.hrc> +#include <osl/diagnose.h> + +using namespace dbaui; +using namespace dbtools; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::beans; +using namespace ::com::sun::star::lang; +using namespace ::com::sun::star::sdbc; +using namespace ::com::sun::star::util; + +namespace +{ + template< typename T1, typename T2> void lcl_HideAndDeleteControl(short& _nPos,std::unique_ptr<T1>& _pControl, std::unique_ptr<T2>& _pControlText) + { + if ( _pControl ) + { + --_nPos; + _pControl->hide(); + _pControlText->hide(); + _pControl.reset(); + _pControlText.reset(); + } + } +} + +OFieldDescControl::OFieldDescControl(weld::Container* pPage, vcl::Window* pParent, OTableDesignHelpBar* pHelpBar) + :TabPage(pPage ? Application::GetDefDialogParent() : pParent, WB_3DLOOK | WB_DIALOGCONTROL) + ,pHelp( pHelpBar ) + ,m_pLastFocusWindow(nullptr) + ,m_pActFocusWindow(nullptr) + ,m_pPreviousType() + ,m_nPos(-1) + ,aYes(DBA_RES(STR_VALUE_YES)) + ,aNo(DBA_RES(STR_VALUE_NO)) + ,m_nEditWidth(50) + ,m_bAdded(false) + ,pActFieldDescr(nullptr) +{ + if (pPage) + m_xBuilder.reset(Application::CreateBuilder(pPage, "dbaccess/ui/fielddescpage.ui")); + else + { + m_xVclContentArea = VclPtr<VclVBox>::Create(this); + m_xVclContentArea->Show(); + m_xBuilder.reset(Application::CreateInterimBuilder(m_xVclContentArea, "dbaccess/ui/fielddescpage.ui")); + + m_aLayoutIdle.SetPriority(TaskPriority::RESIZE); + m_aLayoutIdle.SetInvokeHandler( LINK( this, OFieldDescControl, ImplHandleLayoutTimerHdl ) ); + m_aLayoutIdle.SetDebugName( "OFieldDescControl m_aLayoutIdle" ); + } + + m_xContainer = m_xBuilder->weld_container("FieldDescPage"); +} + +void OFieldDescControl::queue_resize(StateChangedType eReason) +{ + TabPage::queue_resize(eReason); + if (!m_xVclContentArea) + return; + if (m_aLayoutIdle.IsActive()) + return; + m_aLayoutIdle.Start(); +} + +void OFieldDescControl::Resize() +{ + TabPage::Resize(); + if (!m_xVclContentArea) + return; + queue_resize(); +} + +IMPL_LINK_NOARG(OFieldDescControl, ImplHandleLayoutTimerHdl, Timer*, void) +{ + m_xVclContentArea->SetPosSizePixel(Point(0,0), GetSizePixel()); +} + +OFieldDescControl::~OFieldDescControl() +{ + disposeOnce(); +} + +void OFieldDescControl::dispose() +{ + m_aLayoutIdle.Stop(); + + if ( m_bAdded ) + ::dbaui::notifySystemWindow(this,this,::comphelper::mem_fun(&TaskPaneList::RemoveWindow)); + + // Destroy children + DeactivateAggregate( tpDefault ); + DeactivateAggregate( tpRequired ); + DeactivateAggregate( tpTextLen ); + DeactivateAggregate( tpNumType ); + DeactivateAggregate( tpScale ); + DeactivateAggregate( tpLength ); + DeactivateAggregate( tpFormat ); + DeactivateAggregate( tpAutoIncrement ); + DeactivateAggregate( tpBoolDefault ); + DeactivateAggregate( tpColumnName ); + DeactivateAggregate( tpType ); + DeactivateAggregate( tpAutoIncrementValue ); + pHelp.clear(); + m_pLastFocusWindow = nullptr; + m_pActFocusWindow = nullptr; + m_xDefaultText.reset(); + m_xRequiredText.reset(); + m_xAutoIncrementText.reset(); + m_xTextLenText.reset(); + m_xNumTypeText.reset(); + m_xLengthText.reset(); + m_xScaleText.reset(); + m_xFormatText.reset(); + m_xBoolDefaultText.reset(); + m_xColumnNameText.reset(); + m_xTypeText.reset(); + m_xAutoIncrementValueText.reset(); + m_xRequired.reset(); + m_xNumType.reset(); + m_xAutoIncrement.reset(); + m_xDefault.reset(); + m_xTextLen.reset(); + m_xLength.reset(); + m_xScale.reset(); + m_xFormatSample.reset(); + m_xBoolDefault.reset(); + m_xColumnName.reset(); + m_xType.reset(); + m_xAutoIncrementValue.reset(); + m_xFormat.reset(); + m_xContainer.reset(); + m_xBuilder.reset(); + m_xVclContentArea.disposeAndClear(); + TabPage::dispose(); +} + +OUString OFieldDescControl::BoolStringPersistent(const OUString& rUIString) const +{ + if (rUIString == aNo) + return OUString('0'); + if (rUIString == aYes) + return OUString('1'); + return OUString(); +} + +OUString OFieldDescControl::BoolStringUI(const OUString& rPersistentString) const +{ + // Older versions may store a language dependent string as a default + if (rPersistentString == aYes || rPersistentString == aNo) + return rPersistentString; + + if (rPersistentString == "0") + return aNo; + if (rPersistentString == "1") + return aYes; + + return DBA_RES(STR_VALUE_NONE); +} + +void OFieldDescControl::Init() +{ + Reference< css::util::XNumberFormatter > xFormatter = GetFormatter(); + ::dbaui::setEvalDateFormatForFormatter(xFormatter); +} + +void OFieldDescControl::SetReadOnly( bool bReadOnly ) +{ + // Enable/disable Controls + OWidgetBase* ppAggregates[] = { m_xRequired.get(), m_xNumType.get() + , m_xAutoIncrement.get(), m_xDefault.get() + , m_xTextLen.get(), m_xLength.get() + , m_xScale.get(), m_xColumnName.get() + , m_xType.get(), m_xAutoIncrementValue.get() + }; + weld::Widget* ppAggregatesText[] = { m_xRequiredText.get(), m_xNumTypeText.get() + , m_xAutoIncrementText.get(), m_xDefaultText.get() + , m_xTextLenText.get(), m_xLengthText.get() + , m_xScaleText.get(), m_xColumnNameText.get() + , m_xTypeText.get(), m_xAutoIncrementValueText.get() + }; + + OSL_ENSURE(SAL_N_ELEMENTS(ppAggregates) == SAL_N_ELEMENTS(ppAggregatesText),"Lists are not identical!"); + + for (size_t i=0; i<SAL_N_ELEMENTS(ppAggregates); ++i) + { + if ( ppAggregatesText[i] ) + ppAggregatesText[i]->set_sensitive( !bReadOnly ); + if ( ppAggregates[i] ) + ppAggregates[i]->set_sensitive( !bReadOnly ); + } + + if (m_xFormat) + { + assert(m_xFormatText); + m_xFormat->set_sensitive(!bReadOnly); + m_xFormatText->set_sensitive(!bReadOnly); + } +} + +void OFieldDescControl::SetControlText( sal_uInt16 nControlId, const OUString& rText ) +{ + // Set the Controls' texts + switch( nControlId ) + { + case FIELD_PROPERTY_BOOL_DEFAULT: + if (m_xBoolDefault) + { + OUString sOld = m_xBoolDefault->get_active_text(); + m_xBoolDefault->set_active_text(rText); + if (sOld != rText) + ChangeHdl(m_xBoolDefault->GetComboBox()); + } + break; + case FIELD_PROPERTY_DEFAULT: + if (m_xDefault) + { + m_xDefault->set_text(rText); + UpdateFormatSample(pActFieldDescr); + } + break; + + case FIELD_PROPERTY_REQUIRED: + if (m_xRequired) + m_xRequired->set_active_text(rText); + break; + + case FIELD_PROPERTY_TEXTLEN: + if (m_xTextLen) + m_xTextLen->set_text(rText); + break; + + case FIELD_PROPERTY_NUMTYPE: + if (m_xNumType) + m_xNumType->set_active_text(rText); + break; + + case FIELD_PROPERTY_AUTOINC: + if (m_xAutoIncrement) + { + OUString sOld = m_xAutoIncrement->get_active_text(); + m_xAutoIncrement->set_active_text(rText); + if (sOld != rText) + ChangeHdl(m_xAutoIncrement->GetComboBox()); + } + break; + + case FIELD_PROPERTY_LENGTH: + if (m_xLength) + m_xLength->set_text(rText); + break; + + case FIELD_PROPERTY_SCALE: + if (m_xScale) + m_xScale->set_text(rText); + break; + + case FIELD_PROPERTY_FORMAT: + if (pActFieldDescr) + UpdateFormatSample(pActFieldDescr); + break; + case FIELD_PROPERTY_COLUMNNAME: + if (m_xColumnName) + m_xColumnName->set_text(rText); + break; + case FIELD_PROPERTY_TYPE: + if (m_xType) + m_xType->set_active_text(rText); + break; + case FIELD_PROPERTY_AUTOINCREMENT: + if (m_xAutoIncrementValue) + m_xAutoIncrementValue->set_text(rText); + break; + } +} + +IMPL_LINK_NOARG(OFieldDescControl, FormatClickHdl, weld::Button&, void) +{ + // Create temporary Column, which is used for data exchange with Dialog + if( !pActFieldDescr ) + return; + + sal_Int32 nOldFormatKey(pActFieldDescr->GetFormatKey()); + SvxCellHorJustify rOldJustify = pActFieldDescr->GetHorJustify(); + Reference< XNumberFormatsSupplier > xSupplier = GetFormatter()->getNumberFormatsSupplier(); + SvNumberFormatsSupplierObj* pSupplierImpl = comphelper::getUnoTunnelImplementation<SvNumberFormatsSupplierObj>( xSupplier ); + if (!pSupplierImpl) + return; + + SvNumberFormatter* pFormatter = pSupplierImpl->GetNumberFormatter(); + if(!::dbaui::callColumnFormatDialog(this,pFormatter,pActFieldDescr->GetType(),nOldFormatKey,rOldJustify,true)) + return; + + bool bModified = false; + if(nOldFormatKey != pActFieldDescr->GetFormatKey()) + { + pActFieldDescr->SetFormatKey( nOldFormatKey ); + bModified = true; + } + if(rOldJustify != pActFieldDescr->GetHorJustify()) + { + pActFieldDescr->SetHorJustify( rOldJustify ); + bModified = true; + } + + if(bModified) + { + SetModified(true); + UpdateFormatSample(pActFieldDescr); + } +} + +void OFieldDescControl::SetModified(bool /*bModified*/) +{ +} + +IMPL_LINK(OFieldDescControl, ChangeHdl, weld::ComboBox&, rListBox, void) +{ + if (!pActFieldDescr) + return; + + if (rListBox.get_value_changed_from_saved()) + SetModified(true); + + // Special treatment for Bool fields + if (m_xRequired && &rListBox == m_xRequired->GetWidget() && m_xBoolDefault) + { + // If m_xRequired = sal_True then the sal_Bool field must NOT contain <<none>> + OUString sDef = BoolStringUI(::comphelper::getString(pActFieldDescr->GetControlDefault())); + + if (m_xRequired->get_active() == 0) // Yes + { + m_xBoolDefault->remove_text(DBA_RES(STR_VALUE_NONE)); + if (sDef != aYes && sDef != aNo) + m_xBoolDefault->set_active(1); // No as a default + else + m_xBoolDefault->set_active_text(sDef); + } + else if (m_xBoolDefault->get_count() < 3) + { + m_xBoolDefault->append_text(DBA_RES(STR_VALUE_NONE)); + m_xBoolDefault->set_active_text(sDef); + } + } + + // A special treatment only for AutoIncrement + if (m_xAutoIncrement && &rListBox == m_xAutoIncrement->GetWidget()) + { + if (rListBox.get_active() == 1) + { // no + DeactivateAggregate( tpAutoIncrementValue ); + if(pActFieldDescr->IsPrimaryKey()) + DeactivateAggregate( tpRequired ); + else if( pActFieldDescr->getTypeInfo()->bNullable ) + { + ActivateAggregate( tpRequired ); + if (m_xRequired) + { + if( pActFieldDescr->IsNullable() ) + m_xRequired->set_active(1); // no + else + m_xRequired->set_active(0); // yes + } + } + ActivateAggregate( tpDefault ); + } + else + { + DeactivateAggregate( tpRequired ); + DeactivateAggregate( tpDefault ); + ActivateAggregate( tpAutoIncrementValue ); + } + } + + if (m_xType && &rListBox == m_xType->GetWidget()) + { + TOTypeInfoSP pTypeInfo = getTypeInfo(m_xType->get_active()); + pActFieldDescr->FillFromTypeInfo(pTypeInfo,true,false); // SetType(pTypeInfo); + + DisplayData(pActFieldDescr); + CellModified(-1, m_xType->GetPos()); + } +} + +void OFieldDescControl::ActivateAggregate( EControlType eType ) +{ + // Create Controls + switch( eType ) + { + case tpDefault: + if (m_xDefault) + return; + m_nPos++; + m_xDefaultText = m_xBuilder->weld_label("DefaultValueText"); + m_xDefaultText->show(); + m_xDefault = std::make_unique<OPropEditCtrl>( + m_xBuilder->weld_entry("DefaultValue"), STR_HELP_DEFAULT_VALUE, FIELD_PROPERTY_DEFAULT); + InitializeControl(m_xDefault->GetWidget(),HID_TAB_ENT_DEFAULT); + m_xDefault->show(); + break; + case tpAutoIncrementValue: + if (m_xAutoIncrementValue || !isAutoIncrementValueEnabled()) + return; + m_nPos++; + m_xAutoIncrementValueText = m_xBuilder->weld_label("AutoIncrementValueText"); + m_xAutoIncrementValueText->show(); + m_xAutoIncrementValue = std::make_unique<OPropEditCtrl>( + m_xBuilder->weld_spin_button("AutoIncrementValue"), STR_HELP_AUTOINCREMENT_VALUE, + FIELD_PROPERTY_AUTOINCREMENT); + m_xAutoIncrementValue->set_text( getAutoIncrementValue() ); + InitializeControl(m_xAutoIncrementValue->GetWidget(),HID_TAB_AUTOINCREMENTVALUE); + m_xAutoIncrementValue->show(); + break; + + case tpRequired: + { + if (m_xRequired) + return; + Reference< XDatabaseMetaData> xMetaData = getMetaData(); + + if(xMetaData.is() && xMetaData->supportsNonNullableColumns()) + { + m_nPos++; + m_xRequiredText = m_xBuilder->weld_label("RequiredText"); + m_xRequiredText->show(); + m_xRequired = std::make_unique<OPropListBoxCtrl>( + m_xBuilder->weld_combo_box("Required"), STR_HELP_AUTOINCREMENT_VALUE, + FIELD_PROPERTY_AUTOINCREMENT); + m_xRequired->append_text(aYes); + m_xRequired->append_text(aNo); + m_xRequired->set_active(1); + + InitializeControl(m_xRequired.get(),HID_TAB_ENT_REQUIRED, true); + m_xRequired->show(); + } + } + break; + case tpAutoIncrement: + { + if (m_xAutoIncrement) + return; + m_nPos++; + m_xAutoIncrementText = m_xBuilder->weld_label("AutoIncrementText"); + m_xAutoIncrementText->show(); + m_xAutoIncrement = std::make_unique<OPropListBoxCtrl>( + m_xBuilder->weld_combo_box("AutoIncrement"), STR_HELP_AUTOINCREMENT, + FIELD_PROPERTY_AUTOINC); + m_xAutoIncrement->append_text(aYes); + m_xAutoIncrement->append_text(aNo); + m_xAutoIncrement->set_active(0); + InitializeControl(m_xAutoIncrement.get(),HID_TAB_ENT_AUTOINCREMENT, true); + m_xAutoIncrement->show(); + } + break; + case tpTextLen: + if (m_xTextLen) + return; + m_nPos++; + m_xTextLenText = m_xBuilder->weld_label("TextLengthText"); + m_xTextLenText->show(); + m_xTextLen = CreateNumericControl("TextLength", STR_HELP_TEXT_LENGTH, FIELD_PROPERTY_TEXTLEN,HID_TAB_ENT_TEXT_LEN); + break; + + case tpType: + if (m_xType) + return; + m_nPos++; + m_xTypeText = m_xBuilder->weld_label("TypeText"); + m_xTypeText->show(); + m_xType = std::make_unique<OPropListBoxCtrl>( + m_xBuilder->weld_combo_box("Type"), STR_HELP_AUTOINCREMENT, FIELD_PROPERTY_TYPE); + { + const OTypeInfoMap* pTypeInfo = getTypeInfo(); + for (auto const& elem : *pTypeInfo) + m_xType->append_text(elem.second->aUIName); + } + m_xType->set_active(0); + InitializeControl(m_xType.get(),HID_TAB_ENT_TYPE, true); + m_xType->show(); + break; + case tpColumnName: + if (m_xColumnName) + return; + m_nPos++; + { + sal_Int32 nMax(0); + OUString aTmpString; + try + { + Reference< XDatabaseMetaData> xMetaData = getMetaData(); + if ( xMetaData.is() ) + { + nMax = xMetaData->getMaxColumnNameLength(); + aTmpString = xMetaData->getExtraNameCharacters(); + } + } + catch (const Exception&) + { + DBG_UNHANDLED_EXCEPTION("dbaccess"); + } + m_xColumnNameText = m_xBuilder->weld_label("ColumnNameText"); + m_xColumnNameText->show(); + m_xColumnName = std::make_unique<OPropColumnEditCtrl>( + m_xBuilder->weld_entry("ColumnName"), aTmpString, + STR_HELP_DEFAULT_VALUE, FIELD_PROPERTY_COLUMNNAME); + m_xColumnName->set_max_length(nMax); + m_xColumnName->setCheck( isSQL92CheckEnabled(getConnection()) ); + } + + InitializeControl(m_xColumnName->GetWidget(),HID_TAB_ENT_COLUMNNAME); + m_xColumnName->show(); + break; + case tpNumType: + if (m_xNumType) + return; + m_nPos++; + m_xNumTypeText = m_xBuilder->weld_label("NumTypeText"); + m_xNumTypeText->show(); + m_xNumType = std::make_unique<OPropListBoxCtrl>( + m_xBuilder->weld_combo_box("NumType"), STR_HELP_NUMERIC_TYPE, FIELD_PROPERTY_NUMTYPE); + m_xNumType->append_text("Byte"); + m_xNumType->append_text("SmallInt"); + m_xNumType->append_text("Integer"); + m_xNumType->append_text("Single"); + m_xNumType->append_text("Double"); + m_xNumType->set_active(2); + InitializeControl(m_xNumType.get(),HID_TAB_ENT_NUMTYP, true); + m_xNumType->show(); + break; + + case tpLength: + if (m_xLength) + return; + m_nPos++; + m_xLengthText = m_xBuilder->weld_label("LengthText"); + m_xLengthText->show(); + m_xLength = CreateNumericControl("Length", STR_HELP_LENGTH, FIELD_PROPERTY_LENGTH,HID_TAB_ENT_LEN); + break; + + case tpScale: + if (m_xScale) + return; + m_nPos++; + m_xScaleText = m_xBuilder->weld_label("ScaleText"); + m_xScaleText->show(); + m_xScale = CreateNumericControl("Scale", STR_HELP_SCALE, FIELD_PROPERTY_SCALE,HID_TAB_ENT_SCALE); + break; + + case tpFormat: + if (!m_xFormat) + { + m_nPos++; + m_xFormatText = m_xBuilder->weld_label("FormatTextText"); + m_xFormatText->show(); + + m_xFormatSample = std::make_unique<OPropEditCtrl>( + m_xBuilder->weld_entry("FormatText"), STR_HELP_FORMAT_CODE, -1); + m_xFormatSample->set_editable(false); + m_xFormatSample->set_sensitive(false); + InitializeControl(m_xFormatSample->GetWidget(),HID_TAB_ENT_FORMAT_SAMPLE); + m_xFormatSample->show(); + + m_xFormat = m_xBuilder->weld_button("FormatButton"); + m_xFormat->connect_clicked( LINK( this, OFieldDescControl, FormatClickHdl ) ); + InitializeControl(m_xFormat.get(),HID_TAB_ENT_FORMAT); + m_xFormat->show(); + } + + UpdateFormatSample(pActFieldDescr); + break; + case tpBoolDefault: + if (m_xBoolDefault) + return; + + m_nPos++; + m_xBoolDefaultText = m_xBuilder->weld_label("BoolDefaultText"); + m_xBoolDefaultText->show(); + m_xBoolDefault = std::make_unique<OPropListBoxCtrl>( + m_xBuilder->weld_combo_box("BoolDefault"), STR_HELP_BOOL_DEFAULT, + FIELD_PROPERTY_BOOL_DEFAULT); + m_xBoolDefault->append_text(DBA_RES(STR_VALUE_NONE)); + m_xBoolDefault->append_text(aYes); + m_xBoolDefault->append_text(aNo); + InitializeControl(m_xBoolDefault->GetWidget(),HID_TAB_ENT_BOOL_DEFAULT); + m_xBoolDefault->show(); + break; + } + + queue_resize(); +} + +void OFieldDescControl::InitializeControl(OPropListBoxCtrl* _pControl,const OString& _sHelpId,bool _bAddChangeHandler) +{ + if ( _bAddChangeHandler ) + _pControl->GetComboBox().connect_changed(LINK(this,OFieldDescControl,ChangeHdl)); + + InitializeControl(_pControl->GetWidget(), _sHelpId); +} + +void OFieldDescControl::InitializeControl(weld::Widget* pControl,const OString& _sHelpId) +{ + pControl->set_help_id(_sHelpId); + pControl->connect_focus_in(LINK(this, OFieldDescControl, OnControlFocusGot)); + pControl->connect_focus_out(LINK(this, OFieldDescControl, OnControlFocusLost)); + + if (dynamic_cast<weld::Entry*>(pControl)) + { + int nWidthRequest = LogicToPixel(Size(m_nEditWidth, 0), MapMode(MapUnit::MapAppFont)).Width(); + pControl->set_size_request(nWidthRequest, -1); + } +} + +std::unique_ptr<OPropNumericEditCtrl> OFieldDescControl::CreateNumericControl(const OString& rId, const char* pHelpId, short _nProperty, const OString& _sHelpId) +{ + auto xControl = std::make_unique<OPropNumericEditCtrl>( + m_xBuilder->weld_spin_button(rId), pHelpId, _nProperty); + xControl->set_digits(0); + xControl->set_range(0, 0x7FFFFFFF); // Should be changed outside, if needed + xControl->show(); + + InitializeControl(xControl->GetWidget(),_sHelpId); + + return xControl; +} + +void OFieldDescControl::DeactivateAggregate( EControlType eType ) +{ + m_pLastFocusWindow = nullptr; + // Destroy Controls + switch( eType ) + { + case tpDefault: + lcl_HideAndDeleteControl(m_nPos,m_xDefault,m_xDefaultText); + break; + + case tpAutoIncrementValue: + lcl_HideAndDeleteControl(m_nPos,m_xAutoIncrementValue,m_xAutoIncrementValueText); + break; + + case tpColumnName: + lcl_HideAndDeleteControl(m_nPos,m_xColumnName,m_xColumnNameText); + break; + + case tpType: + lcl_HideAndDeleteControl(m_nPos,m_xType,m_xTypeText); + break; + + case tpAutoIncrement: + lcl_HideAndDeleteControl(m_nPos,m_xAutoIncrement,m_xAutoIncrementText); + break; + + case tpRequired: + lcl_HideAndDeleteControl(m_nPos,m_xRequired,m_xRequiredText); + break; + + case tpTextLen: + lcl_HideAndDeleteControl(m_nPos,m_xTextLen,m_xTextLenText); + break; + + case tpNumType: + lcl_HideAndDeleteControl(m_nPos,m_xNumType,m_xNumTypeText); + break; + + case tpLength: + lcl_HideAndDeleteControl(m_nPos,m_xLength,m_xLengthText); + break; + + case tpScale: + lcl_HideAndDeleteControl(m_nPos,m_xScale,m_xScaleText); + break; + + case tpFormat: + // TODO: we have to check if we have to increment m_nPos again + lcl_HideAndDeleteControl(m_nPos,m_xFormat,m_xFormatText); + if (m_xFormatSample) + { + m_xFormatSample->hide(); + m_xFormatSample.reset(); + } + break; + case tpBoolDefault: + lcl_HideAndDeleteControl(m_nPos,m_xBoolDefault,m_xBoolDefaultText); + break; + } + + queue_resize(); +} + +void OFieldDescControl::DisplayData(OFieldDescription* pFieldDescr ) +{ + pActFieldDescr = pFieldDescr; + if(!pFieldDescr) + { + DeactivateAggregate( tpDefault ); + DeactivateAggregate( tpRequired ); + DeactivateAggregate( tpTextLen ); + DeactivateAggregate( tpNumType ); + DeactivateAggregate( tpScale ); + DeactivateAggregate( tpLength ); + DeactivateAggregate( tpFormat ); + DeactivateAggregate( tpAutoIncrement ); + DeactivateAggregate( tpBoolDefault ); + DeactivateAggregate( tpColumnName ); + DeactivateAggregate( tpType ); + DeactivateAggregate( tpAutoIncrementValue ); + m_pPreviousType = TOTypeInfoSP(); + // Reset the saved focus' pointer + m_pLastFocusWindow = nullptr; + if ( m_bAdded ) + { + ::dbaui::notifySystemWindow(this,this,::comphelper::mem_fun(&TaskPaneList::RemoveWindow)); + m_bAdded = false; + } + return; + } + + if ( !m_bAdded ) + { + ::dbaui::notifySystemWindow(this,this,::comphelper::mem_fun(&TaskPaneList::AddWindow)); + m_bAdded = true; + } + + TOTypeInfoSP pFieldType(pFieldDescr->getTypeInfo()); + + ActivateAggregate( tpColumnName ); + ActivateAggregate( tpType ); + + OSL_ENSURE(pFieldType.get(),"We need a type information here!"); + // If the type has changed, substitute Controls + if( m_pPreviousType != pFieldType ) + { + // Reset the saved focus' pointer + m_pLastFocusWindow = nullptr; + + // Controls, which must NOT be displayed again + DeactivateAggregate( tpNumType ); + + // determine which controls we should show and which not + + // 1. the required control + if ( pFieldType->bNullable ) + ActivateAggregate( tpRequired ); + else + DeactivateAggregate( tpRequired ); + + // 2. the autoincrement + if ( pFieldType->bAutoIncrement ) + { + DeactivateAggregate( tpRequired ); + DeactivateAggregate( tpDefault ); + ActivateAggregate( tpAutoIncrement ); + ActivateAggregate( tpAutoIncrementValue ); + } + else + { + DeactivateAggregate( tpAutoIncrement ); + DeactivateAggregate( tpAutoIncrementValue ); + if(pFieldType->bNullable) + ActivateAggregate( tpRequired ); + else + DeactivateAggregate( tpRequired ); + ActivateAggregate( tpDefault ); + } + // 3. the scale and precision + if (pFieldType->nPrecision) + { + ActivateAggregate( tpLength ); + m_xLength->set_max(std::max<sal_Int32>(pFieldType->nPrecision,pFieldDescr->GetPrecision())); + m_xLength->set_editable(!pFieldType->aCreateParams.isEmpty()); + } + else + DeactivateAggregate( tpLength ); + + if (pFieldType->nMaximumScale) + { + ActivateAggregate( tpScale ); + m_xScale->set_range(pFieldType->nMinimumScale, + std::max<sal_Int32>(pFieldType->nMaximumScale,pFieldDescr->GetScale())); + m_xScale->set_editable(!pFieldType->aCreateParams.isEmpty() && pFieldType->aCreateParams != "PRECISION"); + } + else + DeactivateAggregate( tpScale ); + + // and now look for type specific things + switch( pFieldType->nType ) + { + case DataType::CHAR: + case DataType::VARCHAR: + case DataType::LONGVARCHAR: + DeactivateAggregate( tpLength ); + DeactivateAggregate( tpBoolDefault ); + + ActivateAggregate( tpDefault ); + ActivateAggregate( tpFormat ); + if (pFieldType->nPrecision) + { + ActivateAggregate( tpTextLen ); + m_xTextLen->set_max(std::max<sal_Int32>(pFieldType->nPrecision,pFieldDescr->GetPrecision())); + m_xTextLen->set_editable(!pFieldType->aCreateParams.isEmpty()); + } + else + DeactivateAggregate( tpTextLen ); + break; + case DataType::DATE: + case DataType::TIME: + case DataType::TIMESTAMP: + DeactivateAggregate( tpLength ); // we don't need a length for date types + DeactivateAggregate( tpTextLen ); + DeactivateAggregate( tpBoolDefault ); + + ActivateAggregate( tpDefault ); + ActivateAggregate( tpFormat ); + break; + case DataType::BIT: + if ( !pFieldType->aCreateParams.isEmpty() ) + { + DeactivateAggregate( tpFormat ); + DeactivateAggregate( tpTextLen ); + DeactivateAggregate( tpBoolDefault ); + break; + } + [[fallthrough]]; + case DataType::BOOLEAN: + DeactivateAggregate( tpTextLen ); + DeactivateAggregate( tpFormat ); + DeactivateAggregate( tpDefault ); + + ActivateAggregate( tpBoolDefault ); + break; + case DataType::DECIMAL: + case DataType::NUMERIC: + case DataType::BIGINT: + case DataType::FLOAT: + case DataType::DOUBLE: + case DataType::TINYINT: + case DataType::SMALLINT: + case DataType::INTEGER: + case DataType::REAL: + DeactivateAggregate( tpTextLen ); + DeactivateAggregate( tpBoolDefault ); + + ActivateAggregate( tpFormat ); + break; + case DataType::BINARY: + case DataType::VARBINARY: + DeactivateAggregate( tpDefault ); + DeactivateAggregate( tpRequired ); + DeactivateAggregate( tpTextLen ); + DeactivateAggregate( tpBoolDefault ); + + ActivateAggregate( tpFormat ); + break; + case DataType::LONGVARBINARY: + case DataType::SQLNULL: + case DataType::OBJECT: + case DataType::DISTINCT: + case DataType::STRUCT: + case DataType::ARRAY: + case DataType::BLOB: + case DataType::CLOB: + case DataType::REF: + case DataType::OTHER: + DeactivateAggregate( tpFormat ); + DeactivateAggregate( tpTextLen ); + DeactivateAggregate( tpBoolDefault ); + + break; + default: + OSL_FAIL("Unknown type"); + } + m_pPreviousType = pFieldType; + } + + if (pFieldDescr->IsPrimaryKey()) + { + DeactivateAggregate(tpRequired); + } + else if (!m_xAutoIncrement && pFieldType) + { + if (pFieldType->bNullable) + ActivateAggregate(tpRequired); + else + DeactivateAggregate(tpRequired); + } + // Initialize Controls + if (m_xAutoIncrement) + { + if ( pFieldDescr->IsAutoIncrement() ) + { + m_xAutoIncrement->set_active(0); // yes + ActivateAggregate( tpAutoIncrementValue ); + if (m_xAutoIncrementValue) + m_xAutoIncrementValue->set_text(pFieldDescr->GetAutoIncrementValue()); + DeactivateAggregate( tpRequired ); + DeactivateAggregate( tpDefault ); + } + else + { + // disable autoincrement value because it should only be visible when autoincrement is to true + DeactivateAggregate( tpAutoIncrementValue ); + m_xAutoIncrement->set_active(1); // no + ActivateAggregate( tpDefault ); + // Affects pRequired + if(!pFieldDescr->IsPrimaryKey()) + ActivateAggregate( tpRequired ); + } + } + + if (m_xDefault) + { + m_xDefault->set_text(getControlDefault(pFieldDescr)); + m_xDefault->save_value(); + } + + if (m_xBoolDefault) + { + // If m_xRequired = sal_True then the sal_Bool field must NOT contain <<none>> + OUString sValue; + pFieldDescr->GetControlDefault() >>= sValue; + OUString sDef = BoolStringUI(sValue); + + // Make sure that <<none>> is only present if the field can be NULL + if ( ( pFieldType && !pFieldType->bNullable ) || !pFieldDescr->IsNullable() ) + { + pFieldDescr->SetIsNullable(ColumnValue::NO_NULLS); // The type says so + + m_xBoolDefault->remove_text(DBA_RES(STR_VALUE_NONE)); + if ( sDef != aYes && sDef != aNo ) + m_xBoolDefault->set_active(1); // No as a default + else + m_xBoolDefault->set_active_text(sDef); + + pFieldDescr->SetControlDefault(makeAny(BoolStringPersistent(m_xBoolDefault->get_active_text()))); + } + else if (m_xBoolDefault->get_count() < 3) + { + m_xBoolDefault->append_text(DBA_RES(STR_VALUE_NONE)); + m_xBoolDefault->set_active_text(sDef); + } + else + m_xBoolDefault->set_active_text(sDef); + } + + if (m_xRequired) + { + if( pFieldDescr->IsNullable() ) + m_xRequired->set_active(1); // no + else + m_xRequired->set_active(0); // yes + } + + if (m_xTextLen) + { + m_xTextLen->set_text(OUString::number(pFieldDescr->GetPrecision())); + m_xTextLen->save_value(); + } + + if( m_xNumType ) + { + OSL_FAIL("OFieldDescControl::DisplayData: invalid num type!"); + } + + if (m_xLength) + m_xLength->set_text(OUString::number(pFieldDescr->GetPrecision())); + + if (m_xScale) + m_xScale->set_text(OUString::number(pFieldDescr->GetScale())); + + if (m_xFormat) + UpdateFormatSample(pFieldDescr); + + if (m_xColumnName) + m_xColumnName->set_text(pFieldDescr->GetName()); + + if (m_xType) + { + sal_Int32 nPos = pFieldType ? m_xType->find_text(pFieldDescr->getTypeInfo()->aUIName) : -1; + if (nPos == -1) + { + const OTypeInfoMap* pMap = getTypeInfo(); + OTypeInfoMap::const_iterator aIter = pMap->find(pFieldType ? pFieldDescr->getTypeInfo()->nType : pFieldDescr->GetType()); + if(aIter == pMap->end() && !pMap->empty()) + { + aIter = pMap->begin(); + if(pFieldDescr->GetPrecision() > aIter->second->nPrecision) + pFieldDescr->SetPrecision(aIter->second->nPrecision); + if(pFieldDescr->GetScale() > aIter->second->nMaximumScale) + pFieldDescr->SetScale(0); + if(!aIter->second->bNullable && pFieldDescr->IsNullable()) + pFieldDescr->SetIsNullable(ColumnValue::NO_NULLS); + if(!aIter->second->bAutoIncrement && pFieldDescr->IsAutoIncrement()) + pFieldDescr->SetAutoIncrement(false); + } + if ( aIter != pMap->end() ) + { + pFieldDescr->SetType(aIter->second); + } + } + m_xType->set_active_text(pFieldDescr->getTypeInfo()->aUIName); + } + + // Enable/disable Controls + bool bRead(IsReadOnly()); + + SetReadOnly( bRead ); +} + +IMPL_LINK(OFieldDescControl, OnControlFocusGot, weld::Widget&, rControl, void ) +{ + OUString strHelpText; + + if (m_xTextLen && &rControl == m_xTextLen->GetWidget()) + { + m_xTextLen->save_value(); + strHelpText = m_xTextLen->GetHelp(); + } + else if (m_xLength && &rControl == m_xLength->GetWidget()) + { + m_xLength->save_value(); + strHelpText = m_xLength->GetHelp(); + } + else if (m_xScale && &rControl == m_xScale->GetWidget()) + { + m_xScale->save_value(); + strHelpText = m_xScale->GetHelp(); + } + else if (m_xColumnName && &rControl == m_xColumnName->GetWidget()) + { + m_xColumnName->save_value(); + strHelpText = m_xColumnName->GetHelp(); + } + else if (m_xDefault && &rControl == m_xDefault->GetWidget()) + { + m_xDefault->save_value(); + strHelpText = m_xDefault->GetHelp(); + } + else if (m_xFormatSample && &rControl == m_xFormatSample->GetWidget()) + { + m_xFormatSample->save_value(); + strHelpText = m_xFormatSample->GetHelp(); + } + else if (m_xAutoIncrementValue && &rControl == m_xAutoIncrementValue->GetWidget()) + { + m_xAutoIncrementValue->save_value(); + strHelpText = m_xAutoIncrementValue->GetHelp(); + } + else if (m_xRequired && &rControl == m_xRequired->GetWidget()) + { + m_xRequired->save_value(); + strHelpText = m_xRequired->GetHelp(); + } + else if (m_xNumType && &rControl == m_xNumType->GetWidget()) + { + m_xNumType->save_value(); + strHelpText = m_xNumType->GetHelp(); + } + else if (m_xAutoIncrement && &rControl == m_xAutoIncrement->GetWidget()) + { + m_xAutoIncrement->save_value(); + strHelpText = m_xAutoIncrement->GetHelp(); + } + else if (m_xBoolDefault && &rControl == m_xBoolDefault->GetWidget()) + { + m_xBoolDefault->save_value(); + strHelpText = m_xBoolDefault->GetHelp(); + } + else if (m_xType && &rControl == m_xType->GetWidget()) + { + m_xType->save_value(); + strHelpText = m_xType->GetHelp(); + } + else if (m_xFormat && &rControl == m_xFormat.get()) + strHelpText = DBA_RES(STR_HELP_FORMAT_BUTTON); + + if (!strHelpText.isEmpty() && (pHelp != nullptr)) + pHelp->SetHelpText(strHelpText); + + m_pActFocusWindow = &rControl; +} + +IMPL_LINK(OFieldDescControl, OnControlFocusLost, weld::Widget&, rControl, void ) +{ + if (m_xLength && &rControl == m_xLength->GetWidget() && m_xLength->get_value_changed_from_saved()) + CellModified(-1, m_xLength->GetPos()); + else if (m_xTextLen && &rControl == m_xTextLen->GetWidget() && m_xTextLen->get_value_changed_from_saved()) + CellModified(-1, m_xTextLen->GetPos()); + else if (m_xScale && &rControl == m_xScale->GetWidget() && m_xScale->get_value_changed_from_saved()) + CellModified(-1, m_xScale->GetPos()); + else if (m_xColumnName && &rControl == m_xColumnName->GetWidget() && m_xColumnName->get_value_changed_from_saved()) + CellModified(-1, m_xColumnName->GetPos()); + else if (m_xDefault && &rControl == m_xDefault->GetWidget() && m_xDefault->get_value_changed_from_saved()) + CellModified(-1, m_xDefault->GetPos()); + else if (m_xFormatSample && &rControl == m_xFormatSample->GetWidget() && m_xFormatSample->get_value_changed_from_saved()) + CellModified(-1, m_xFormatSample->GetPos()); + else if (m_xAutoIncrementValue && &rControl == m_xAutoIncrementValue->GetWidget() && m_xAutoIncrementValue->get_value_changed_from_saved()) + CellModified(-1, m_xAutoIncrementValue->GetPos()); + else if (m_xRequired && &rControl == m_xRequired->GetWidget() && m_xRequired->get_value_changed_from_saved()) + CellModified(-1, m_xRequired->GetPos()); + else if (m_xNumType && &rControl == m_xNumType->GetWidget() && m_xNumType->get_value_changed_from_saved()) + CellModified(-1, m_xNumType->GetPos()); + else if (m_xAutoIncrement && &rControl == m_xAutoIncrement->GetWidget() && m_xAutoIncrement->get_value_changed_from_saved()) + CellModified(-1, m_xAutoIncrement->GetPos()); + else if (m_xBoolDefault && &rControl == m_xBoolDefault->GetWidget() && m_xBoolDefault->get_value_changed_from_saved()) + CellModified(-1, m_xBoolDefault->GetPos()); + else if (m_xType && &rControl == m_xType->GetWidget() && m_xType->get_value_changed_from_saved()) + CellModified(-1, m_xType->GetPos()); + else if (m_xDefault && &rControl == m_xDefault->GetWidget()) + UpdateFormatSample(pActFieldDescr); + + implFocusLost(&rControl); +} + +void OFieldDescControl::SaveData( OFieldDescription* pFieldDescr ) +{ + if( !pFieldDescr ) + return; + + // Read out Controls + OUString sDefault; + if (m_xDefault) + { + sDefault = m_xDefault->get_text(); + } + else if (m_xBoolDefault) + { + sDefault = BoolStringPersistent(m_xBoolDefault->get_active_text()); + } + + if ( !sDefault.isEmpty() ) + pFieldDescr->SetControlDefault(makeAny(sDefault)); + else + pFieldDescr->SetControlDefault(Any()); + + if((m_xRequired && m_xRequired->get_active() == 0) || pFieldDescr->IsPrimaryKey() || (m_xBoolDefault && m_xBoolDefault->get_count() == 2)) // yes + pFieldDescr->SetIsNullable( ColumnValue::NO_NULLS ); + else + pFieldDescr->SetIsNullable( ColumnValue::NULLABLE ); + + if (m_xAutoIncrement) + pFieldDescr->SetAutoIncrement(m_xAutoIncrement->get_active() == 0); + + if( m_xTextLen ) + pFieldDescr->SetPrecision( static_cast<sal_Int32>(m_xTextLen->get_value()) ); + else if (m_xLength) + pFieldDescr->SetPrecision( static_cast<sal_Int32>(m_xLength->get_value()) ); + if (m_xScale) + pFieldDescr->SetScale( static_cast<sal_Int32>(m_xScale->get_value()) ); + + if (m_xColumnName) + pFieldDescr->SetName(m_xColumnName->get_text()); + + if (m_xAutoIncrementValue && isAutoIncrementValueEnabled()) + pFieldDescr->SetAutoIncrementValue(m_xAutoIncrementValue->get_text()); +} + +void OFieldDescControl::UpdateFormatSample(OFieldDescription const * pFieldDescr) +{ + if (pFieldDescr && m_xFormatSample) + m_xFormatSample->set_text(getControlDefault(pFieldDescr,false)); +} + +void OFieldDescControl::GetFocus() +{ + // Set the Focus to the Control that has been active last + TabPage::GetFocus(); + if (m_pLastFocusWindow) + { + m_pLastFocusWindow->grab_focus(); + m_pLastFocusWindow = nullptr; + } +} + +void OFieldDescControl::implFocusLost(weld::Widget* _pWhich) +{ + // Remember the active Control + if (!m_pLastFocusWindow) + m_pLastFocusWindow = _pWhich; + + // Reset HelpText + if (pHelp && !pHelp->HasChildPathFocus()) + pHelp->SetHelpText( OUString() ); +} + +void OFieldDescControl::LoseFocus() +{ + implFocusLost(nullptr); + + TabPage::LoseFocus(); +} + +bool OFieldDescControl::IsFocusInEditableWidget() const +{ + if (m_xDefault && m_pActFocusWindow == m_xDefault->GetWidget()) + return true; + if (m_xFormatSample && m_pActFocusWindow == m_xFormatSample->GetWidget()) + return true; + if (m_xTextLen && m_pActFocusWindow == m_xTextLen->GetWidget()) + return true; + if (m_xLength && m_pActFocusWindow == m_xLength->GetWidget()) + return true; + if (m_xScale && m_pActFocusWindow == m_xScale->GetWidget()) + return true; + if (m_xColumnName && m_pActFocusWindow == m_xColumnName->GetWidget()) + return true; + if (m_xAutoIncrementValue && m_pActFocusWindow == m_xAutoIncrementValue->GetWidget()) + return true; + return false; +} + +bool OFieldDescControl::isCopyAllowed() const +{ + int nStartPos, nEndPos; + bool bAllowed = (m_pActFocusWindow != nullptr) && IsFocusInEditableWidget() && + dynamic_cast<weld::Entry&>(*m_pActFocusWindow).get_selection_bounds(nStartPos, nEndPos); + return bAllowed; +} + +bool OFieldDescControl::isCutAllowed() const +{ + int nStartPos, nEndPos; + bool bAllowed = (m_pActFocusWindow != nullptr) && IsFocusInEditableWidget() && + dynamic_cast<weld::Entry&>(*m_pActFocusWindow).get_selection_bounds(nStartPos, nEndPos); + return bAllowed; +} + +bool OFieldDescControl::isPasteAllowed() const +{ + bool bAllowed = (m_pActFocusWindow != nullptr) && IsFocusInEditableWidget(); + if ( bAllowed ) + { + TransferableDataHelper aTransferData(TransferableDataHelper::CreateFromSystemClipboard(GetParent())); + bAllowed = aTransferData.HasFormat(SotClipboardFormatId::STRING); + } + return bAllowed; +} + +void OFieldDescControl::cut() +{ + if (isCutAllowed()) + dynamic_cast<weld::Entry&>(*m_pActFocusWindow).cut_clipboard(); +} + +void OFieldDescControl::copy() +{ + if (isCopyAllowed()) // this only checks if the focus window is valid + dynamic_cast<weld::Entry&>(*m_pActFocusWindow).copy_clipboard(); +} + +void OFieldDescControl::paste() +{ + if (m_pActFocusWindow) // this only checks if the focus window is valid + dynamic_cast<weld::Entry&>(*m_pActFocusWindow).paste_clipboard(); +} + +bool OFieldDescControl::isTextFormat(const OFieldDescription* _pFieldDescr, sal_uInt32& _nFormatKey) const +{ + _nFormatKey = _pFieldDescr->GetFormatKey(); + bool bTextFormat = true; + + try + { + if (!_nFormatKey) + { + Reference< css::util::XNumberFormatTypes> xNumberTypes(GetFormatter()->getNumberFormatsSupplier()->getNumberFormats(),UNO_QUERY); + OSL_ENSURE(xNumberTypes.is(),"XNumberFormatTypes is null!"); + + _nFormatKey = ::dbtools::getDefaultNumberFormat( _pFieldDescr->GetType(), + _pFieldDescr->GetScale(), + _pFieldDescr->IsCurrency(), + xNumberTypes, + GetLocale()); + } + sal_Int32 nNumberFormat = ::comphelper::getNumberFormatType(GetFormatter(),_nFormatKey); + bTextFormat = (nNumberFormat == css::util::NumberFormat::TEXT); + } + catch(const Exception&) + { + + } + + return bTextFormat; +} + +OUString OFieldDescControl::getControlDefault( const OFieldDescription* _pFieldDescr, bool _bCheck) const +{ + OUString sDefault; + bool bCheck = !_bCheck || _pFieldDescr->GetControlDefault().hasValue(); + if ( bCheck ) + { + sal_uInt32 nFormatKey; + + try + { + double nValue = 0.0; + bool bTextFormat = isTextFormat(_pFieldDescr,nFormatKey); + if ( _pFieldDescr->GetControlDefault() >>= sDefault ) + { + if ( !bTextFormat ) + { + if ( !sDefault.isEmpty() ) + { + try + { + nValue = GetFormatter()->convertStringToNumber(nFormatKey,sDefault); + } + catch(const Exception&) + { + return OUString(); // return empty string for format example + } + } + } + } + else + _pFieldDescr->GetControlDefault() >>= nValue; + + Reference< css::util::XNumberFormatter> xNumberFormatter = GetFormatter(); + Reference<XPropertySet> xFormSet = xNumberFormatter->getNumberFormatsSupplier()->getNumberFormats()->getByKey(nFormatKey); + OSL_ENSURE(xFormSet.is(),"XPropertySet is null!"); + OUString sFormat; + xFormSet->getPropertyValue("FormatString") >>= sFormat; + + if ( !bTextFormat ) + { + Locale aLocale; + ::comphelper::getNumberFormatProperty(xNumberFormatter,nFormatKey,"Locale") >>= aLocale; + + sal_Int32 nNumberFormat = ::comphelper::getNumberFormatType(xNumberFormatter,nFormatKey); + if( (nNumberFormat & css::util::NumberFormat::DATE) == css::util::NumberFormat::DATE + || (nNumberFormat & css::util::NumberFormat::DATETIME) == css::util::NumberFormat::DATETIME ) + { + nValue = DBTypeConversion::toNullDate(DBTypeConversion::getNULLDate(xNumberFormatter->getNumberFormatsSupplier()),nValue); + } + + Reference< css::util::XNumberFormatPreviewer> xPreviewer(xNumberFormatter,UNO_QUERY); + OSL_ENSURE(xPreviewer.is(),"XNumberFormatPreviewer is null!"); + sDefault = xPreviewer->convertNumberToPreviewString(sFormat,nValue,aLocale,true); + } + else if ( !(_bCheck && sDefault.isEmpty()) ) + sDefault = xNumberFormatter->formatString(nFormatKey, sDefault.isEmpty() ? sFormat : sDefault); + } + catch(const Exception&) + { + + } + } + + return sDefault; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/control/RelationControl.cxx b/dbaccess/source/ui/control/RelationControl.cxx new file mode 100644 index 000000000..69f0a00ca --- /dev/null +++ b/dbaccess/source/ui/control/RelationControl.cxx @@ -0,0 +1,695 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <RelationControl.hxx> + +#include <svtools/editbrowsebox.hxx> +#include <com/sun/star/beans/XPropertySet.hpp> +#include <tools/diagnose_ex.h> +#include <toolkit/helper/vclunohelper.hxx> +#include <TableConnectionData.hxx> +#include <TableConnection.hxx> +#include <TableWindow.hxx> +#include <com/sun/star/awt/XWindow.hpp> +#include <com/sun/star/container/XNameAccess.hpp> +#include <com/sun/star/sdbcx/XColumnsSupplier.hpp> +#include <RelControliFace.hxx> +#include <helpids.h> +#include <o3tl/safeint.hxx> +#include <osl/diagnose.h> + +#include <vector> +#include <utility> +using std::pair; +using std::make_pair; + +#define SOURCE_COLUMN 1 +#define DEST_COLUMN 2 + +namespace dbaui +{ + using namespace ::com::sun::star::uno; + using namespace ::com::sun::star::beans; + using namespace ::com::sun::star::sdbc; + using namespace ::com::sun::star::sdbcx; + using namespace ::com::sun::star::container; + using namespace svt; + + typedef ::svt::EditBrowseBox ORelationControl_Base; + class ORelationControl : public ORelationControl_Base + { + friend class OTableListBoxControl; + + VclPtr< ::svt::ListBoxControl> m_pListCell; + TTableConnectionData::value_type m_pConnData; + OTableListBoxControl* m_pBoxControl; + long m_nDataPos; + Reference< XPropertySet> m_xSourceDef; + Reference< XPropertySet> m_xDestDef; + enum opcode { DELETE, INSERT, MODIFY }; + typedef std::vector< pair < opcode, pair < OConnectionLineDataVec::size_type, OConnectionLineDataVec::size_type> > > ops_type; + ops_type m_ops; + + void fillListBox(const Reference< XPropertySet>& _xDest); + /** returns the column id for the editbrowsebox + @param _nColId + the column id SOURCE_COLUMN or DEST_COLUMN + + @return the current column id either SOURCE_COLUMN or DEST_COLUMN depends on the connection data + */ + sal_uInt16 getColumnIdent( sal_uInt16 _nColId ) const; + public: + explicit ORelationControl(const css::uno::Reference<css::awt::XWindow>& rParent); + void SetController(OTableListBoxControl* pController) + { + m_pBoxControl = pController; + } + + /** searches for a connection between these two tables + @param _pSource + the left table + @param _pDest + the right window + */ + void setWindowTables(const OTableWindow* _pSource,const OTableWindow* _pDest); + + /** allows to access the connection data from outside + + @return the connection data + */ + const TTableConnectionData::value_type& getData() const { return m_pConnData; } + + void lateInit(); + + protected: + virtual ~ORelationControl() override { disposeOnce(); } + virtual void dispose() override { m_pListCell.disposeAndClear(); ORelationControl_Base::dispose(); } + virtual void Resize() override; + virtual Size GetOptimalSize() const override; + virtual bool PreNotify(NotifyEvent& rNEvt ) override; + + virtual bool IsTabAllowed(bool bForward) const override; + + void Init(const TTableConnectionData::value_type& _pConnData); + using ORelationControl_Base::Init; + virtual void InitController( ::svt::CellControllerRef& rController, long nRow, sal_uInt16 nCol ) override; + virtual ::svt::CellController* GetController( long nRow, sal_uInt16 nCol ) override; + virtual void PaintCell( OutputDevice& rDev, const tools::Rectangle& rRect, sal_uInt16 nColId ) const override; + virtual bool SeekRow( long nRow ) override; + virtual bool SaveModified() override; + virtual OUString GetCellText( long nRow, sal_uInt16 nColId ) const override; + + virtual void CellModified() override; + + DECL_LINK( AsynchDeactivate, void*, void ); + private: + + DECL_LINK( AsynchActivate, void*, void ); + + }; + + ORelationControl::ORelationControl(const css::uno::Reference<css::awt::XWindow>& rParent) + : EditBrowseBox(VCLUnoHelper::GetWindow(rParent), + EditBrowseBoxFlags::SMART_TAB_TRAVEL | EditBrowseBoxFlags::NO_HANDLE_COLUMN_CONTENT, + WB_TABSTOP | WB_BORDER, + BrowserMode::AUTOSIZE_LASTCOL) + , m_pBoxControl(nullptr) + , m_nDataPos(0) + { + } + + void ORelationControl::Init(const TTableConnectionData::value_type& _pConnData) + { + + m_pConnData = _pConnData; + OSL_ENSURE(m_pConnData, "No data supplied!"); + + m_pConnData->normalizeLines(); + } + + void ORelationControl::lateInit() + { + if ( !m_pConnData ) + return; + m_xSourceDef = m_pConnData->getReferencingTable()->getTable(); + m_xDestDef = m_pConnData->getReferencedTable()->getTable(); + + if ( ColCount() == 0 ) + { + InsertDataColumn( SOURCE_COLUMN, m_pConnData->getReferencingTable()->GetWinName(), 100); + InsertDataColumn( DEST_COLUMN, m_pConnData->getReferencedTable()->GetWinName(), 100); + // If the Defs do not yet exits, we need to set them with SetSource-/-DestDef + + m_pListCell.reset( VclPtr<ListBoxControl>::Create( &GetDataWindow() ) ); + + // set browse mode + SetMode( BrowserMode::COLUMNSELECTION | + BrowserMode::HLINES | + BrowserMode::VLINES | + BrowserMode::HIDECURSOR | + BrowserMode::HIDESELECT | + BrowserMode::AUTO_HSCROLL | + BrowserMode::AUTO_VSCROLL); + } + else + // not the first call + RowRemoved(0, GetRowCount()); + + RowInserted(0, m_pConnData->GetConnLineDataList().size() + 1); // add one extra row + } + + void ORelationControl::Resize() + { + EditBrowseBox::Resize(); + long nOutputWidth = GetOutputSizePixel().Width() - 1; + SetColumnWidth(1, (nOutputWidth / 2)); + SetColumnWidth(2, (nOutputWidth / 2)); + } + + bool ORelationControl::PreNotify(NotifyEvent& rNEvt) + { + if (rNEvt.GetType() == MouseNotifyEvent::LOSEFOCUS && !HasChildPathFocus() && !ControlHasFocus()) + PostUserEvent(LINK(this, ORelationControl, AsynchDeactivate), nullptr, true); + else if (rNEvt.GetType() == MouseNotifyEvent::GETFOCUS) + PostUserEvent(LINK(this, ORelationControl, AsynchActivate), nullptr, true); + + return EditBrowseBox::PreNotify(rNEvt); + } + + IMPL_LINK_NOARG(ORelationControl, AsynchActivate, void*, void) + { + ActivateCell(); + } + + IMPL_LINK_NOARG(ORelationControl, AsynchDeactivate, void*, void) + { + DeactivateCell(); + } + + bool ORelationControl::IsTabAllowed(bool bForward) const + { + long nRow = GetCurRow(); + sal_uInt16 nCol = GetCurColumnId(); + + bool bRet = !( ( bForward && (nCol == DEST_COLUMN) && (nRow == GetRowCount() - 1)) + || (!bForward && (nCol == SOURCE_COLUMN) && (nRow == 0))); + + return bRet && EditBrowseBox::IsTabAllowed(bForward); + } + + bool ORelationControl::SaveModified() + { + long nRow = GetCurRow(); + if ( nRow != BROWSER_ENDOFSELECTION ) + { + weld::ComboBox& rListBox = m_pListCell->get_widget(); + OUString sFieldName(rListBox.get_active_text()); + OConnectionLineDataVec& rLines = m_pConnData->GetConnLineDataList(); + if ( rLines.size() <= o3tl::make_unsigned(nRow) ) + { + rLines.push_back(new OConnectionLineData()); + nRow = rLines.size() - 1; + // add new past-rLines row + m_ops.emplace_back(INSERT, make_pair(nRow+1, nRow+2)); + } + + OConnectionLineDataRef pConnLineData = rLines[nRow]; + + switch( getColumnIdent( GetCurColumnId() ) ) + { + case SOURCE_COLUMN: + pConnLineData->SetSourceFieldName( sFieldName ); + break; + case DEST_COLUMN: + pConnLineData->SetDestFieldName( sFieldName ); + break; + } + // the modification we just did does *not* need to be registered in m_ops; + // it is already taken into account (by the codepath that called us) + //m_ops.push_back(make_pair(MODIFY, make_pair(nRow, nRow+1))); + } + + const OConnectionLineDataVec::size_type oldSize = m_pConnData->GetConnLineDataList().size(); + OConnectionLineDataVec::size_type line = m_pConnData->normalizeLines(); + const OConnectionLineDataVec::size_type newSize = m_pConnData->GetConnLineDataList().size(); + assert(newSize <= oldSize); + m_ops.emplace_back(MODIFY, make_pair(line, newSize)); + m_ops.emplace_back(DELETE, make_pair(newSize, oldSize)); + + return true; + } + + sal_uInt16 ORelationControl::getColumnIdent( sal_uInt16 _nColId ) const + { + sal_uInt16 nId = _nColId; + if ( m_pConnData->getReferencingTable() != m_pBoxControl->getReferencingTable() ) + nId = ( _nColId == SOURCE_COLUMN) ? DEST_COLUMN : SOURCE_COLUMN; + return nId; + } + + OUString ORelationControl::GetCellText( long nRow, sal_uInt16 nColId ) const + { + OUString sText; + if ( m_pConnData->GetConnLineDataList().size() > o3tl::make_unsigned(nRow) ) + { + OConnectionLineDataRef pConnLineData = m_pConnData->GetConnLineDataList()[nRow]; + switch( getColumnIdent( nColId ) ) + { + case SOURCE_COLUMN: + sText = pConnLineData->GetSourceFieldName(); + break; + case DEST_COLUMN: + sText = pConnLineData->GetDestFieldName(); + break; + } + } + return sText; + } + + void ORelationControl::InitController( CellControllerRef& /*rController*/, long nRow, sal_uInt16 nColumnId ) + { + + OString sHelpId( HID_RELATIONDIALOG_LEFTFIELDCELL ); + + Reference< XPropertySet> xDef; + switch ( getColumnIdent(nColumnId) ) + { + case SOURCE_COLUMN: + xDef = m_xSourceDef; + sHelpId = HID_RELATIONDIALOG_LEFTFIELDCELL; + break; + case DEST_COLUMN: + xDef = m_xDestDef; + sHelpId = HID_RELATIONDIALOG_RIGHTFIELDCELL; + break; + default: + // ????????? + break; + } + + if ( !xDef.is() ) + return; + + fillListBox(xDef); + OUString sName = GetCellText( nRow, nColumnId ); + weld::ComboBox& rList = m_pListCell->get_widget(); + rList.set_active_text(sName); + if (rList.get_active_text() != sName) + { + rList.append_text(sName); + rList.set_active_text(sName); + } + + rList.set_help_id(sHelpId); + } + + CellController* ORelationControl::GetController( long /*nRow*/, sal_uInt16 /*nColumnId*/ ) + { + return new ListBoxCellController( m_pListCell.get() ); + } + + bool ORelationControl::SeekRow( long nRow ) + { + m_nDataPos = nRow; + return true; + } + + void ORelationControl::PaintCell( OutputDevice& rDev, const tools::Rectangle& rRect, sal_uInt16 nColumnId ) const + { + OUString aText = GetCellText( m_nDataPos, nColumnId ); + + Point aPos( rRect.TopLeft() ); + Size aTextSize( GetDataWindow().GetTextWidth( aText ), GetDataWindow().GetTextHeight() ); + + if( aPos.X() < rRect.Left() || aPos.X() + aTextSize.Width() > rRect.Right() || + aPos.Y() < rRect.Top() || aPos.Y() + aTextSize.Height() > rRect.Bottom() ) + { + rDev.SetClipRegion(vcl::Region(rRect)); + } + + rDev.DrawText( aPos, aText ); + + if( rDev.IsClipRegion() ) + rDev.SetClipRegion(); + } + void ORelationControl::fillListBox(const Reference< XPropertySet>& _xDest) + { + weld::ComboBox& rList = m_pListCell->get_widget(); + rList.clear(); + try + { + if ( _xDest.is() ) + { + //sal_Int32 nRows = GetRowCount(); + Reference<XColumnsSupplier> xSup(_xDest,UNO_QUERY); + Reference<XNameAccess> xColumns = xSup->getColumns(); + Sequence< OUString> aNames = xColumns->getElementNames(); + const OUString* pIter = aNames.getConstArray(); + const OUString* pEnd = pIter + aNames.getLength(); + for(;pIter != pEnd;++pIter) + { + rList.append_text(*pIter); + } + rList.insert_text(0, OUString()); + } + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("dbaccess"); + } + } + void ORelationControl::setWindowTables(const OTableWindow* _pSource,const OTableWindow* _pDest) + { + // If I edit here, hide + bool bWasEditing = IsEditing(); + if ( bWasEditing ) + DeactivateCell(); + + if ( _pSource && _pDest ) + { + m_xSourceDef = _pSource->GetTable(); + SetColumnTitle(1, _pSource->GetName()); + + m_xDestDef = _pDest->GetTable(); + SetColumnTitle(2, _pDest->GetName()); + + const OJoinTableView* pView = _pSource->getTableView(); + OTableConnection* pConn = pView->GetTabConn(_pSource,_pDest); + if ( pConn && !m_pConnData->GetConnLineDataList().empty() ) + { + m_pConnData->CopyFrom(*pConn->GetData()); + m_pBoxControl->getContainer()->notifyConnectionChange(); + } + else + { + // no connection found so we clear our data + OConnectionLineDataVec& rLines = m_pConnData->GetConnLineDataList(); + for( const auto& rLine : rLines ) + { + rLine->Reset(); + } + + m_pConnData->setReferencingTable(_pSource->GetData()); + m_pConnData->setReferencedTable(_pDest->GetData()); + } + m_pConnData->normalizeLines(); + + } + // Repaint + Invalidate(); + + if ( bWasEditing ) + { + GoToRow(0); + ActivateCell(); + } + } + + void ORelationControl::CellModified() + { + EditBrowseBox::CellModified(); + SaveModified(); + assert(m_pBoxControl); + m_pBoxControl->NotifyCellChange(); + } + + Size ORelationControl::GetOptimalSize() const + { + return LogicToPixel(Size(140, 80), MapMode(MapUnit::MapAppFont)); + } + + OTableListBoxControl::OTableListBoxControl(weld::Builder* _pParent, + const OJoinTableView::OTableWindowMap* _pTableMap, + IRelationControlInterface* _pParentDialog) + : m_xLeftTable(_pParent->weld_combo_box("table1")) + , m_xRightTable(_pParent->weld_combo_box("table2")) + , m_xTable(_pParent->weld_container("relations")) + , m_xTableCtrlParent(m_xTable->CreateChildFrame()) + , m_xRC_Tables(VclPtr<ORelationControl>::Create(m_xTableCtrlParent)) + , m_pTableMap(_pTableMap) + , m_pParentDialog(_pParentDialog) + { + Size aPrefSize = m_xRC_Tables->GetOptimalSize(); + m_xTable->set_size_request(aPrefSize.Width(), aPrefSize.Height()); + + m_xRC_Tables->SetController(this); + m_xRC_Tables->Init(); + + lateUIInit(); + + Link<weld::ComboBox&,void> aLink(LINK(this, OTableListBoxControl, OnTableChanged)); + m_xLeftTable->connect_changed(aLink); + m_xRightTable->connect_changed(aLink); + } + + OTableListBoxControl::~OTableListBoxControl() + { + m_xRC_Tables.disposeAndClear(); + m_xTableCtrlParent->dispose(); + m_xTableCtrlParent.clear(); + } + + void OTableListBoxControl::fillListBoxes() + { + OSL_ENSURE( !m_pTableMap->empty(), "OTableListBoxControl::fillListBoxes: no table window!"); + OTableWindow* pInitialLeft = nullptr; + OTableWindow* pInitialRight = nullptr; + + // Collect the names of all TabWins + for (auto const& elem : *m_pTableMap) + { + m_xLeftTable->append_text(elem.first); + m_xRightTable->append_text(elem.first); + + if (!pInitialLeft) + { + pInitialLeft = elem.second; + m_strCurrentLeft = elem.first; + } + else if (!pInitialRight) + { + pInitialRight = elem.second; + m_strCurrentRight = elem.first; + } + } + + if ( !pInitialRight ) + { + pInitialRight = pInitialLeft; + m_strCurrentRight = m_strCurrentLeft; + } + + // The corresponding Defs for my Controls + m_xRC_Tables->setWindowTables(pInitialLeft,pInitialRight); + + // The table selected in a ComboBox must not be available in the other + + if ( m_pTableMap->size() > 2 ) + { + m_xLeftTable->remove_text(m_strCurrentRight); + m_xRightTable->remove_text(m_strCurrentLeft); + } + + // Select the first one on the left side and on the right side, + // select the second one + m_xLeftTable->set_active_text(m_strCurrentLeft); + m_xRightTable->set_active_text(m_strCurrentRight); + + m_xLeftTable->grab_focus(); + } + + IMPL_LINK(OTableListBoxControl, OnTableChanged, weld::ComboBox&, rListBox, void) + { + OUString strSelected(rListBox.get_active_text()); + OTableWindow* pLeft = nullptr; + OTableWindow* pRight = nullptr; + + // Special treatment: If there are only two tables, we need to switch the other one too when changing in a LB + if ( m_pTableMap->size() == 2 ) + { + weld::ComboBox* pOther; + if (&rListBox == m_xLeftTable.get()) + pOther = m_xRightTable.get(); + else + pOther = m_xLeftTable.get(); + pOther->set_active(1 - pOther->get_active()); + + OJoinTableView::OTableWindowMap::const_iterator aIter = m_pTableMap->begin(); + OTableWindow* pFirst = aIter->second; + ++aIter; + OTableWindow* pSecond = aIter->second; + + if (m_xLeftTable->get_active_text() == pFirst->GetName()) + { + pLeft = pFirst; + pRight = pSecond; + } + else + { + pLeft = pSecond; + pRight = pFirst; + } + } + else + { + // First we need the TableDef to the Table and with it the TabWin + OJoinTableView::OTableWindowMap::const_iterator aFind = m_pTableMap->find(strSelected); + OTableWindow* pLoop = nullptr; + if( aFind != m_pTableMap->end() ) + pLoop = aFind->second; + OSL_ENSURE(pLoop != nullptr, "ORelationDialog::OnTableChanged: invalid ListBox entry!"); + // We need to find strSelect, because we filled the ListBoxes with the table names with which we compare now + if (&rListBox == m_xLeftTable.get()) + { + // Insert the previously selected Entry on the left side on the right side + m_xRightTable->append_text(m_strCurrentLeft); + // Remove the currently selected Entry + m_xRightTable->remove_text(strSelected); + m_strCurrentLeft = strSelected; + + pLeft = pLoop; + + OJoinTableView::OTableWindowMap::const_iterator aIter = m_pTableMap->find(m_xRightTable->get_active_text()); + OSL_ENSURE( aIter != m_pTableMap->end(), "Invalid name"); + if ( aIter != m_pTableMap->end() ) + pRight = aIter->second; + + m_xLeftTable->grab_focus(); + } + else + { + // Insert the previously selected Entry on the right side on the left side + m_xLeftTable->append_text(m_strCurrentRight); + // Remove the currently selected Entry + m_xLeftTable->remove_text(strSelected); + m_strCurrentRight = strSelected; + + pRight = pLoop; + OJoinTableView::OTableWindowMap::const_iterator aIter = m_pTableMap->find(m_xLeftTable->get_active_text()); + OSL_ENSURE( aIter != m_pTableMap->end(), "Invalid name"); + if ( aIter != m_pTableMap->end() ) + pLeft = aIter->second; + } + } + + rListBox.grab_focus(); + + m_xRC_Tables->setWindowTables(pLeft,pRight); + + NotifyCellChange(); + } + + void OTableListBoxControl::NotifyCellChange() + { + // Enable/disable the OK button, depending on having a valid situation + TTableConnectionData::value_type pConnData = m_xRC_Tables->getData(); + const OConnectionLineDataVec& rLines = pConnData->GetConnLineDataList(); + bool bValid = !rLines.empty(); + if (bValid) + { + for (auto const& line : rLines) + { + bValid = ! (line->GetSourceFieldName().isEmpty() || line->GetDestFieldName().isEmpty()); + if (!bValid) + break; + } + } + m_pParentDialog->setValid(bValid); + + m_xRC_Tables->DeactivateCell(); + for (auto const& elem : m_xRC_Tables->m_ops) + { + switch(elem.first) + { + case ORelationControl::DELETE: + m_xRC_Tables->RowRemoved(elem.second.first, elem.second.second - elem.second.first); + break; + case ORelationControl::INSERT: + m_xRC_Tables->RowInserted(elem.second.first, elem.second.second - elem.second.first); + break; + case ORelationControl::MODIFY: + for(OConnectionLineDataVec::size_type j = elem.second.first; j < elem.second.second; ++j) + m_xRC_Tables->RowModified(j); + break; + } + } + m_xRC_Tables->ActivateCell(); + m_xRC_Tables->m_ops.clear(); + } + + static void fillEntryAndDisable(weld::ComboBox& _rListBox,const OUString& _sEntry) + { + _rListBox.append_text(_sEntry); + _rListBox.set_active(0); + _rListBox.set_sensitive(false); + } + + void OTableListBoxControl::fillAndDisable(const TTableConnectionData::value_type& _pConnectionData) + { + fillEntryAndDisable(*m_xLeftTable, _pConnectionData->getReferencingTable()->GetWinName()); + fillEntryAndDisable(*m_xRightTable, _pConnectionData->getReferencedTable()->GetWinName()); + } + + void OTableListBoxControl::Init(const TTableConnectionData::value_type& _pConnData) + { + m_xRC_Tables->Init(_pConnData); + } + + void OTableListBoxControl::lateUIInit() + { + m_xRC_Tables->Show(); + lateInit(); + } + + void OTableListBoxControl::lateInit() + { + m_xRC_Tables->lateInit(); + } + + void OTableListBoxControl::Disable() + { + m_xLeftTable->set_sensitive(false); + m_xRightTable->set_sensitive(false); + m_xRC_Tables->Disable(); + } + + void OTableListBoxControl::Invalidate() + { + m_xRC_Tables->Invalidate(); + } + + void OTableListBoxControl::SaveModified() + { + m_xRC_Tables->SaveModified(); + } + + TTableWindowData::value_type const & OTableListBoxControl::getReferencingTable() const + { + return m_xRC_Tables->getData()->getReferencingTable(); + } + + void OTableListBoxControl::enableRelation(bool _bEnable) + { + if ( !_bEnable ) + m_xRC_Tables->PostUserEvent(LINK(m_xRC_Tables, ORelationControl, AsynchDeactivate)); + m_xRC_Tables->Enable(_bEnable); + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/control/ScrollHelper.cxx b/dbaccess/source/ui/control/ScrollHelper.cxx new file mode 100644 index 000000000..a9fcacca9 --- /dev/null +++ b/dbaccess/source/ui/control/ScrollHelper.cxx @@ -0,0 +1,52 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <ScrollHelper.hxx> + +#define LISTBOX_SCROLLING_AREA 12 +namespace dbaui +{ + + OScrollHelper::OScrollHelper() + { + } + OScrollHelper::~OScrollHelper() + { + + } + void OScrollHelper::scroll(const Point& _rPoint, const Size& _rOutputSize) + { + // Scrolling Areas + tools::Rectangle aScrollArea( Point(0, _rOutputSize.Height() - LISTBOX_SCROLLING_AREA), + Size(_rOutputSize.Width(), LISTBOX_SCROLLING_AREA) ); + + // if pointer in bottom area begin scroll + if( aScrollArea.IsInside(_rPoint) ) + m_aUpScroll.Call(nullptr); + else + { + aScrollArea.SetPos(Point(0,0)); + // if pointer in top area begin scroll + if( aScrollArea.IsInside(_rPoint) ) + m_aDownScroll.Call(nullptr); + } + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/control/SqlNameEdit.cxx b/dbaccess/source/ui/control/SqlNameEdit.cxx new file mode 100644 index 000000000..c24e9fd3c --- /dev/null +++ b/dbaccess/source/ui/control/SqlNameEdit.cxx @@ -0,0 +1,84 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <SqlNameEdit.hxx> + +namespace dbaui +{ + static bool isCharOk(sal_Unicode _cChar,bool _bFirstChar, const OUString& _sAllowedChars) + { + return ( + (_cChar >= 'A' && _cChar <= 'Z') || + _cChar == '_' || + _sAllowedChars.indexOf(_cChar) != -1 || + (!_bFirstChar && (_cChar >= '0' && _cChar <= '9')) || + (_cChar >= 'a' && _cChar <= 'z') + ); + } + bool OSQLNameChecker::checkString(const OUString& _sToCheck, + OUString& _rsCorrected) + { + bool bCorrected = false; + if ( m_bCheck ) + { + sal_Int32 nMatch = 0; + for (sal_Int32 i = nMatch; i < _sToCheck.getLength(); ++i) + { + if ( !isCharOk( _sToCheck[i], i == 0, m_sAllowedChars ) ) + { + _rsCorrected += _sToCheck.copy(nMatch, i - nMatch); + bCorrected = true; + nMatch = i + 1; + } + } + _rsCorrected += _sToCheck.copy( nMatch ); + } + return bCorrected; + } + void OSQLNameEdit::Modify() + { + OUString sCorrected; + if ( checkString( GetText(),sCorrected ) ) + { + Selection aSel = GetSelection(); + aSel.setMax( aSel.getMin() ); + SetText( sCorrected, aSel ); + + SaveValue(); + } + Edit::Modify(); + } + + IMPL_LINK_NOARG(OSQLNameEntry, ModifyHdl, weld::Entry&, void) + { + OUString sCorrected; + if (checkString(m_xEntry->get_text(), sCorrected)) + { + int nStartPos, nEndPos; + m_xEntry->get_selection_bounds(nStartPos, nEndPos); + int nMin = std::min(nStartPos, nEndPos); + m_xEntry->set_text(sCorrected); + m_xEntry->select_region(nMin, nMin); + + m_xEntry->save_value(); + } + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/control/TableGrantCtrl.cxx b/dbaccess/source/ui/control/TableGrantCtrl.cxx new file mode 100644 index 000000000..373340afd --- /dev/null +++ b/dbaccess/source/ui/control/TableGrantCtrl.cxx @@ -0,0 +1,461 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <TableGrantCtrl.hxx> +#include <core_resource.hxx> +#include <com/sun/star/sdbc/SQLException.hpp> +#include <com/sun/star/sdbcx/XTablesSupplier.hpp> +#include <com/sun/star/sdbcx/Privilege.hpp> +#include <com/sun/star/sdbcx/PrivilegeObject.hpp> +#include <com/sun/star/sdbcx/XUsersSupplier.hpp> +#include <com/sun/star/sdbcx/XAuthorizable.hpp> +#include <connectivity/dbtools.hxx> +#include <toolkit/helper/vclunohelper.hxx> +#include <vcl/button.hxx> +#include <vcl/svapp.hxx> +#include <osl/diagnose.h> +#include <strings.hrc> + +using namespace ::com::sun::star::accessibility; +using namespace ::com::sun::star::container; +using namespace ::com::sun::star::sdbcx; +using namespace ::com::sun::star::sdbc; +using namespace ::com::sun::star::uno; +using namespace ::dbaui; +using namespace ::svt; + +const sal_uInt16 COL_TABLE_NAME = 1; +const sal_uInt16 COL_SELECT = 2; +const sal_uInt16 COL_INSERT = 3; +const sal_uInt16 COL_DELETE = 4; +const sal_uInt16 COL_UPDATE = 5; +const sal_uInt16 COL_ALTER = 6; +const sal_uInt16 COL_REF = 7; +const sal_uInt16 COL_DROP = 8; + + +// OTableGrantControl +OTableGrantControl::OTableGrantControl(const css::uno::Reference<css::awt::XWindow> &rParent) + :EditBrowseBox(VCLUnoHelper::GetWindow(rParent), EditBrowseBoxFlags::SMART_TAB_TRAVEL | EditBrowseBoxFlags::NO_HANDLE_COLUMN_CONTENT, WB_TABSTOP) + ,m_pCheckCell( nullptr ) + ,m_pEdit( nullptr ) + ,m_nDataPos( 0 ) + ,m_nDeactivateEvent(nullptr) +{ + // insert columns + sal_uInt16 i=1; + InsertDataColumn( i, DBA_RES(STR_TABLE_PRIV_NAME), 75); + FreezeColumn(i++); + InsertDataColumn( i++, DBA_RES(STR_TABLE_PRIV_SELECT), 75); + InsertDataColumn( i++, DBA_RES(STR_TABLE_PRIV_INSERT), 75); + InsertDataColumn( i++, DBA_RES(STR_TABLE_PRIV_DELETE), 75); + InsertDataColumn( i++, DBA_RES(STR_TABLE_PRIV_UPDATE), 75); + InsertDataColumn( i++, DBA_RES(STR_TABLE_PRIV_ALTER), 75); + InsertDataColumn( i++, DBA_RES(STR_TABLE_PRIV_REFERENCE), 75); + InsertDataColumn( i++, DBA_RES(STR_TABLE_PRIV_DROP), 75); + + while(--i) + SetColumnWidth(i,GetAutoColumnWidth(i)); +} + +OTableGrantControl::~OTableGrantControl() +{ + disposeOnce(); +} + +void OTableGrantControl::dispose() +{ + if (m_nDeactivateEvent) + { + Application::RemoveUserEvent(m_nDeactivateEvent); + m_nDeactivateEvent = nullptr; + } + + m_pCheckCell.disposeAndClear(); + m_pEdit.disposeAndClear(); + + m_xTables = nullptr; + ::svt::EditBrowseBox::dispose(); +} + +void OTableGrantControl::setTablesSupplier(const Reference< XTablesSupplier >& _xTablesSup) +{ + // first we need the users + Reference< XUsersSupplier> xUserSup(_xTablesSup,UNO_QUERY); + if(xUserSup.is()) + m_xUsers = xUserSup->getUsers(); + + // second we need the tables to determine which privileges the user has + if(_xTablesSup.is()) + m_xTables = _xTablesSup->getTables(); + + if(m_xTables.is()) + m_aTableNames = m_xTables->getElementNames(); + + OSL_ENSURE(m_xUsers.is(),"No user access supported!"); + OSL_ENSURE(m_xTables.is(),"No tables supported!"); +} + +void OTableGrantControl::setComponentContext(const Reference< css::uno::XComponentContext>& _rxContext) +{ + m_xContext = _rxContext; +} + +void OTableGrantControl::UpdateTables() +{ + RemoveRows(); + + if(m_xTables.is()) + RowInserted(0, m_aTableNames.getLength()); + // m_bEnable = m_xDb->GetUser() != ((OUserAdmin*)GetParent())->GetUser(); +} + +void OTableGrantControl::Init() +{ + EditBrowseBox::Init(); + + // instantiate ComboBox + if(!m_pCheckCell) + { + m_pCheckCell = VclPtr<CheckBoxControl>::Create( &GetDataWindow() ); + m_pCheckCell->GetBox().EnableTriState(false); + + m_pEdit = VclPtr<Edit>::Create( &GetDataWindow() ); + m_pEdit->SetReadOnly(); + m_pEdit->Enable(false); + } + + UpdateTables(); + // set browser mode + BrowserMode const nMode = BrowserMode::COLUMNSELECTION | BrowserMode::HLINES | BrowserMode::VLINES | + BrowserMode::HIDECURSOR | BrowserMode::HIDESELECT; + + SetMode(nMode); +} + +bool OTableGrantControl::PreNotify(NotifyEvent& rNEvt) +{ + if (rNEvt.GetType() == MouseNotifyEvent::LOSEFOCUS) + if (!HasChildPathFocus()) + { + if (m_nDeactivateEvent) + Application::RemoveUserEvent(m_nDeactivateEvent); + m_nDeactivateEvent = Application::PostUserEvent(LINK(this, OTableGrantControl, AsynchDeactivate), nullptr, true); + } + if (rNEvt.GetType() == MouseNotifyEvent::GETFOCUS) + { + if (m_nDeactivateEvent) + Application::RemoveUserEvent(m_nDeactivateEvent); + m_nDeactivateEvent = Application::PostUserEvent(LINK(this, OTableGrantControl, AsynchActivate), nullptr, true); + } + return EditBrowseBox::PreNotify(rNEvt); +} + +IMPL_LINK_NOARG(OTableGrantControl, AsynchActivate, void*, void) +{ + m_nDeactivateEvent = nullptr; + ActivateCell(); +} + +IMPL_LINK_NOARG(OTableGrantControl, AsynchDeactivate, void*, void) +{ + m_nDeactivateEvent = nullptr; + DeactivateCell(); +} + +bool OTableGrantControl::IsTabAllowed(bool bForward) const +{ + long nRow = GetCurRow(); + sal_uInt16 nCol = GetCurColumnId(); + + if (bForward && (nCol == 2) && (nRow == GetRowCount() - 1)) + return false; + + if (!bForward && (nCol == 1) && (nRow == 0)) + return false; + + return EditBrowseBox::IsTabAllowed(bForward); +} + +#define GRANT_REVOKE_RIGHT(what) \ + if(m_pCheckCell->GetBox().IsChecked()) \ + xAuth->grantPrivileges(sTableName,PrivilegeObject::TABLE,what);\ + else \ + xAuth->revokePrivileges(sTableName,PrivilegeObject::TABLE,what) + +bool OTableGrantControl::SaveModified() +{ + + sal_Int32 nRow = GetCurRow(); + if(nRow == -1 || nRow >= m_aTableNames.getLength()) + return false; + + OUString sTableName = m_aTableNames[nRow]; + bool bErg = true; + try + { + + if ( m_xUsers->hasByName(m_sUserName) ) + { + Reference<XAuthorizable> xAuth(m_xUsers->getByName(m_sUserName),UNO_QUERY); + if ( xAuth.is() ) + { + switch( GetCurColumnId() ) + { + case COL_INSERT: + GRANT_REVOKE_RIGHT(Privilege::INSERT); + break; + case COL_DELETE: + GRANT_REVOKE_RIGHT(Privilege::DELETE); + break; + case COL_UPDATE: + GRANT_REVOKE_RIGHT(Privilege::UPDATE); + break; + case COL_ALTER: + GRANT_REVOKE_RIGHT(Privilege::ALTER); + break; + case COL_SELECT: + GRANT_REVOKE_RIGHT(Privilege::SELECT); + break; + case COL_REF: + GRANT_REVOKE_RIGHT(Privilege::REFERENCE); + break; + case COL_DROP: + GRANT_REVOKE_RIGHT(Privilege::DROP); + break; + } + fillPrivilege(nRow); + } + } + } + catch(SQLException& e) + { + bErg = false; + ::dbtools::showError(::dbtools::SQLExceptionInfo(e),VCLUnoHelper::GetInterface(GetParent()),m_xContext); + } + if(bErg && Controller().is()) + Controller()->ClearModified(); + if(!bErg) + UpdateTables(); + + return bErg; +} + +OUString OTableGrantControl::GetCellText( long nRow, sal_uInt16 nColId ) const +{ + if(COL_TABLE_NAME == nColId) + return m_aTableNames[nRow]; + + sal_Int32 nPriv = 0; + TTablePrivilegeMap::const_iterator aFind = findPrivilege(nRow); + if(aFind != m_aPrivMap.end()) + nPriv = aFind->second.nRights; + + return OUString::number(isAllowed(nColId,nPriv) ? 1 :0); +} + +void OTableGrantControl::InitController( CellControllerRef& /*rController*/, long nRow, sal_uInt16 nColumnId ) +{ + OUString sTablename = m_aTableNames[nRow]; + // special case for tablename + if(nColumnId == COL_TABLE_NAME) + m_pEdit->SetText(sTablename); + else + { + // get the privileges from the user + TTablePrivilegeMap::const_iterator aFind = findPrivilege(nRow); + m_pCheckCell->GetBox().Check(aFind != m_aPrivMap.end() && isAllowed(nColumnId,aFind->second.nRights)); + } +} + +void OTableGrantControl::fillPrivilege(sal_Int32 _nRow) const +{ + + if ( !m_xUsers->hasByName(m_sUserName) ) + return; + + try + { + Reference<XAuthorizable> xAuth(m_xUsers->getByName(m_sUserName),UNO_QUERY); + if ( xAuth.is() ) + { + // get the privileges + TPrivileges nRights; + nRights.nRights = xAuth->getPrivileges(m_aTableNames[_nRow],PrivilegeObject::TABLE); + if(m_xGrantUser.is()) + nRights.nWithGrant = m_xGrantUser->getGrantablePrivileges(m_aTableNames[_nRow],PrivilegeObject::TABLE); + else + nRights.nWithGrant = 0; + + m_aPrivMap[m_aTableNames[_nRow]] = nRights; + } + } + catch(SQLException& e) + { + ::dbtools::showError(::dbtools::SQLExceptionInfo(e),VCLUnoHelper::GetInterface(GetParent()),m_xContext); + } + catch(Exception& ) + { + } +} + +bool OTableGrantControl::isAllowed(sal_uInt16 _nColumnId,sal_Int32 _nPrivilege) +{ + bool bAllowed = false; + switch (_nColumnId) + { + case COL_INSERT: + bAllowed = (Privilege::INSERT & _nPrivilege) == Privilege::INSERT; + break; + case COL_DELETE: + bAllowed = (Privilege::DELETE & _nPrivilege) == Privilege::DELETE; + break; + case COL_UPDATE: + bAllowed = (Privilege::UPDATE & _nPrivilege) == Privilege::UPDATE; + break; + case COL_ALTER: + bAllowed = (Privilege::ALTER & _nPrivilege) == Privilege::ALTER; + break; + case COL_SELECT: + bAllowed = (Privilege::SELECT & _nPrivilege) == Privilege::SELECT; + break; + case COL_REF: + bAllowed = (Privilege::REFERENCE & _nPrivilege) == Privilege::REFERENCE; + break; + case COL_DROP: + bAllowed = (Privilege::DROP & _nPrivilege) == Privilege::DROP; + break; + } + return bAllowed; +} + +void OTableGrantControl::setUserName(const OUString& _sUserName) +{ + m_sUserName = _sUserName; + m_aPrivMap = TTablePrivilegeMap(); +} + +void OTableGrantControl::setGrantUser(const Reference< XAuthorizable>& _xGrantUser) +{ + OSL_ENSURE(_xGrantUser.is(),"OTableGrantControl::setGrantUser: GrantUser is null!"); + m_xGrantUser = _xGrantUser; +} + +CellController* OTableGrantControl::GetController( long nRow, sal_uInt16 nColumnId ) +{ + + CellController* pController = nullptr; + switch( nColumnId ) + { + case COL_TABLE_NAME: + break; + case COL_INSERT: + case COL_DELETE: + case COL_UPDATE: + case COL_ALTER: + case COL_SELECT: + case COL_REF: + case COL_DROP: + { + TTablePrivilegeMap::const_iterator aFind = findPrivilege(nRow); + if(aFind != m_aPrivMap.end() && isAllowed(nColumnId,aFind->second.nWithGrant)) + pController = new CheckBoxCellController( m_pCheckCell ); + } + break; + default: + ; + } + return pController; +} + +bool OTableGrantControl::SeekRow( long nRow ) +{ + m_nDataPos = nRow; + + return (nRow <= m_aTableNames.getLength()); +} + +void OTableGrantControl::PaintCell( OutputDevice& rDev, const tools::Rectangle& rRect, sal_uInt16 nColumnId ) const +{ + + if(nColumnId != COL_TABLE_NAME) + { + TTablePrivilegeMap::const_iterator aFind = findPrivilege(m_nDataPos); + if(aFind != m_aPrivMap.end()) + PaintTristate(rRect, isAllowed(nColumnId,aFind->second.nRights) ? TRISTATE_TRUE : TRISTATE_FALSE,isAllowed(nColumnId,aFind->second.nWithGrant)); + else + PaintTristate(rRect, TRISTATE_FALSE, false); + } + else + { + OUString aText(GetCellText( m_nDataPos, nColumnId )); + Point aPos( rRect.TopLeft() ); + sal_Int32 nWidth = GetDataWindow().GetTextWidth( aText ); + sal_Int32 nHeight = GetDataWindow().GetTextHeight(); + + if( aPos.X() < rRect.Left() || aPos.X() + nWidth > rRect.Right() || + aPos.Y() < rRect.Top() || aPos.Y() + nHeight > rRect.Bottom() ) + { + rDev.SetClipRegion(vcl::Region(rRect)); + } + + rDev.DrawText( aPos, aText ); + } + + if( rDev.IsClipRegion() ) + rDev.SetClipRegion(); +} + +void OTableGrantControl::CellModified() +{ + EditBrowseBox::CellModified(); + SaveModified(); +} + +OTableGrantControl::TTablePrivilegeMap::const_iterator OTableGrantControl::findPrivilege(sal_Int32 _nRow) const +{ + TTablePrivilegeMap::const_iterator aFind = m_aPrivMap.find(m_aTableNames[_nRow]); + if(aFind == m_aPrivMap.end()) + { + fillPrivilege(_nRow); + aFind = m_aPrivMap.find(m_aTableNames[_nRow]); + } + return aFind; +} + +Reference< XAccessible > OTableGrantControl::CreateAccessibleCell( sal_Int32 _nRow, sal_uInt16 _nColumnPos ) +{ + sal_uInt16 nColumnId = GetColumnId( _nColumnPos ); + if(nColumnId != COL_TABLE_NAME) + { + TriState eState = TRISTATE_FALSE; + TTablePrivilegeMap::const_iterator aFind = findPrivilege(_nRow); + if(aFind != m_aPrivMap.end()) + { + eState = isAllowed(nColumnId,aFind->second.nRights) ? TRISTATE_TRUE : TRISTATE_FALSE; + } + else + eState = TRISTATE_FALSE; + + return EditBrowseBox::CreateAccessibleCheckBoxCell( _nRow, _nColumnPos,eState ); + } + return EditBrowseBox::CreateAccessibleCell( _nRow, _nColumnPos ); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/control/VertSplitView.cxx b/dbaccess/source/ui/control/VertSplitView.cxx new file mode 100644 index 000000000..35616d330 --- /dev/null +++ b/dbaccess/source/ui/control/VertSplitView.cxx @@ -0,0 +1,180 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <VertSplitView.hxx> + +#include <vcl/split.hxx> +#include <vcl/settings.hxx> +#include <vcl/event.hxx> +#include <osl/diagnose.h> + +#define SPLITTER_WIDTH 80 + +using namespace ::dbaui; + +OSplitterView::OSplitterView(vcl::Window* _pParent) : Window(_pParent,WB_DIALOGCONTROL) // ,WB_BORDER + ,m_pSplitter( nullptr ) + ,m_pLeft(nullptr) + ,m_pRight(nullptr) + ,m_pResizeId(nullptr) +{ + ImplInitSettings(); +} + +OSplitterView::~OSplitterView() +{ + disposeOnce(); +} + +void OSplitterView::dispose() +{ + if (m_pResizeId) + { + RemoveUserEvent(m_pResizeId); + m_pResizeId = nullptr; + } + m_pSplitter.clear(); + m_pLeft.clear(); + m_pRight.clear(); + vcl::Window::dispose(); +} + +IMPL_LINK_NOARG( OSplitterView, SplitHdl, Splitter*, void ) +{ + OSL_ENSURE(m_pSplitter, "Splitter is NULL!"); + m_pSplitter->SetPosPixel( Point( m_pSplitter->GetPosPixel().X(),m_pSplitter->GetSplitPosPixel() ) ); + + Resize(); +} + +void OSplitterView::ImplInitSettings() +{ + // FIXME RenderContext + const StyleSettings& rStyleSettings = GetSettings().GetStyleSettings(); + + vcl::Font aFont = rStyleSettings.GetAppFont(); + if ( IsControlFont() ) + aFont.Merge( GetControlFont() ); + SetPointFont(*this, aFont); +// Set/*Zoomed*/PointFont( aFont ); + + Color aTextColor = rStyleSettings.GetButtonTextColor(); + if ( IsControlForeground() ) + aTextColor = GetControlForeground(); + SetTextColor( aTextColor ); + + if( IsControlBackground() ) + SetBackground( GetControlBackground() ); + else + SetBackground( rStyleSettings.GetFaceColor() ); +} + +void OSplitterView::DataChanged( const DataChangedEvent& rDCEvt ) +{ + Window::DataChanged( rDCEvt ); + + if ( (rDCEvt.GetType() == DataChangedEventType::SETTINGS) && + (rDCEvt.GetFlags() & AllSettingsFlags::STYLE) ) + { + ImplInitSettings(); + Invalidate(); + } +} + +void OSplitterView::GetFocus() +{ + Window::GetFocus(); + + // forward the focus to the current cell of the editor control + if ( m_pLeft ) + m_pLeft->GrabFocus(); + else if ( m_pRight ) + m_pRight->GrabFocus(); +} + +IMPL_LINK_NOARG(OSplitterView, ResizeHdl, void*, void) +{ + m_pResizeId = nullptr; + + OSL_ENSURE( m_pRight, "No init called!"); + + Point aSplitPos; + Size aSplitSize; + Point aPlaygroundPos( 0,0 ); + Size aPlaygroundSize( GetOutputSizePixel() ); + + if ( m_pLeft && m_pLeft->IsVisible() && m_pSplitter ) + { + aSplitPos = m_pSplitter->GetPosPixel(); + aSplitSize = m_pSplitter->GetOutputSizePixel(); + aSplitPos.setX( aPlaygroundPos.X() ); + aSplitSize.setWidth( aPlaygroundSize.Width() ); + + if( ( aSplitPos.Y() + aSplitSize.Height() ) > ( aPlaygroundSize.Height() )) + aSplitPos.setY( aPlaygroundSize.Height() - aSplitSize.Height() ); + + if( aSplitPos.Y() <= aPlaygroundPos.Y() ) + aSplitPos.setY( aPlaygroundPos.Y() + sal_Int32(aPlaygroundSize.Height() * 0.3) ); + + // the tree pos and size + Point aTreeViewPos( aPlaygroundPos ); + Size aTreeViewSize( aPlaygroundSize.Width() ,aSplitPos.Y()); + + // set the size of treelistbox + m_pLeft->SetPosSizePixel( aTreeViewPos, aTreeViewSize ); + + //set the size of the splitter + m_pSplitter->SetPosSizePixel( aSplitPos, Size( aPlaygroundSize.Width(), aSplitSize.Height() ) ); + m_pSplitter->SetDragRectPixel( tools::Rectangle(aPlaygroundPos,aPlaygroundSize) ); + } + + if ( m_pRight ) + { + m_pRight->setPosSizePixel( aSplitPos.X(), aPlaygroundPos.Y() + aSplitPos.Y() + aSplitSize.Height(), + aPlaygroundSize.Width() , aPlaygroundSize.Height() - aSplitSize.Height() - aSplitPos.Y()); + } +} + +void OSplitterView::Resize() +{ + Window::Resize(); + if (m_pResizeId) + RemoveUserEvent(m_pResizeId); + m_pResizeId = PostUserEvent(LINK(this, OSplitterView, ResizeHdl), this, true); +} + +void OSplitterView::set(vcl::Window* _pRight,Window* _pLeft) +{ + m_pLeft = _pLeft; + m_pRight = _pRight; +} + +void OSplitterView::setSplitter(Splitter* _pSplitter) +{ + m_pSplitter = _pSplitter; + if ( m_pSplitter ) + { + m_pSplitter->SetSplitPosPixel(LogicToPixel(Size(SPLITTER_WIDTH, 0), MapMode(MapUnit::MapAppFont)).Width()); + m_pSplitter->SetSplitHdl( LINK(this, OSplitterView, SplitHdl) ); + m_pSplitter->Show(); + LINK( this, OSplitterView, SplitHdl ).Call(m_pSplitter); + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/control/charsetlistbox.cxx b/dbaccess/source/ui/control/charsetlistbox.cxx new file mode 100644 index 000000000..8915b65c9 --- /dev/null +++ b/dbaccess/source/ui/control/charsetlistbox.cxx @@ -0,0 +1,69 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <charsetlistbox.hxx> + +#include <svl/itemset.hxx> +#include <svl/stritem.hxx> +#include <osl/diagnose.h> + +namespace dbaui +{ + CharSetListBox::CharSetListBox(std::unique_ptr<weld::ComboBox> xControl) + : m_xControl(std::move(xControl)) + { + for (auto const& charset : m_aCharSets) + { + m_xControl->append_text(charset.getDisplayName()); + } + } + + void CharSetListBox::SelectEntryByIanaName( const OUString& _rIanaName ) + { + OCharsetDisplay::const_iterator aFind = m_aCharSets.findIanaName( _rIanaName ); + if (aFind == m_aCharSets.end()) + { + OSL_FAIL( "CharSetListBox::SelectEntryByIanaName: unknown charset falling back to system language!" ); + aFind = m_aCharSets.findEncoding( RTL_TEXTENCODING_DONTKNOW ); + } + + if (aFind == m_aCharSets.end()) + m_xControl->set_active(-1); + else + m_xControl->set_active_text((*aFind).getDisplayName()); + } + + bool CharSetListBox::StoreSelectedCharSet( SfxItemSet& _rSet, const sal_uInt16 _nItemId ) + { + bool bChangedSomething = false; + if (m_xControl->get_value_changed_from_saved()) + { + OCharsetDisplay::const_iterator aFind = m_aCharSets.findDisplayName(m_xControl->get_active_text()); + OSL_ENSURE( aFind != m_aCharSets.end(), "CharSetListBox::StoreSelectedCharSet: could not translate the selected character set!" ); + if ( aFind != m_aCharSets.end() ) + { + _rSet.Put( SfxStringItem( _nItemId, (*aFind).getIanaName() ) ); + bChangedSomething = true; + } + } + return bChangedSomething; + } +} // namespace dbaui + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/control/curledit.cxx b/dbaccess/source/ui/control/curledit.cxx new file mode 100644 index 000000000..9cccde370 --- /dev/null +++ b/dbaccess/source/ui/control/curledit.cxx @@ -0,0 +1,89 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <curledit.hxx> + +namespace dbaui +{ + +OConnectionURLEdit::OConnectionURLEdit(std::unique_ptr<weld::Entry> xEntry, std::unique_ptr<weld::Label> xForcedPrefix) + : m_pTypeCollection(nullptr) + , m_bShowPrefix(false) + , m_xEntry(std::move(xEntry)) + , m_xForcedPrefix(std::move(xForcedPrefix)) +{ +} + +OConnectionURLEdit::~OConnectionURLEdit() +{ +} + +void OConnectionURLEdit::SetTextNoPrefix(const OUString& _rText) +{ + m_xEntry->set_text(_rText); +} + +OUString OConnectionURLEdit::GetTextNoPrefix() const +{ + return m_xEntry->get_text(); +} + +void OConnectionURLEdit::SetText(const OUString& _rStr) +{ + Selection aNoSelection(0,0); + SetText(_rStr, aNoSelection); +} + +void OConnectionURLEdit::SetText(const OUString& _rStr, const Selection& /*_rNewSelection*/) +{ + m_xForcedPrefix->set_visible(m_bShowPrefix); + + bool bIsEmpty = _rStr.isEmpty(); + // calc the prefix + OUString sPrefix; + if (!bIsEmpty) + { + // determine the type of the new URL described by the new text + sPrefix = m_pTypeCollection->getPrefix(_rStr); + } + + // the fixed text gets the prefix + m_xForcedPrefix->set_label(sPrefix); + + // do the real SetText + OUString sNewText( _rStr ); + if ( !bIsEmpty ) + sNewText = m_pTypeCollection->cutPrefix( _rStr ); + m_xEntry->set_text(sNewText); +} + +OUString OConnectionURLEdit::GetText() const +{ + return m_xForcedPrefix->strip_mnemonic(m_xForcedPrefix->get_label()) + m_xEntry->get_text(); +} + +void OConnectionURLEdit::ShowPrefix(bool _bShowPrefix) +{ + m_bShowPrefix = _bShowPrefix; + m_xForcedPrefix->set_visible(m_bShowPrefix); +} + +} // namespace dbaui + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/control/dbtreelistbox.cxx b/dbaccess/source/ui/control/dbtreelistbox.cxx new file mode 100644 index 000000000..549a27c39 --- /dev/null +++ b/dbaccess/source/ui/control/dbtreelistbox.cxx @@ -0,0 +1,584 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <dbtreelistbox.hxx> +#include <listviewitems.hxx> +#include <callbacks.hxx> + +#include <com/sun/star/ui/XContextMenuInterceptor.hpp> +#include <com/sun/star/uno/XComponentContext.hpp> +#include <com/sun/star/frame/XController.hpp> +#include <com/sun/star/lang/IllegalArgumentException.hpp> +#include <cppuhelper/implbase.hxx> +#include <comphelper/interfacecontainer2.hxx> +#include <comphelper/processfactory.hxx> +#include <comphelper/propertyvalue.hxx> +#include <vcl/help.hxx> +#include <dbaccess/IController.hxx> +#include <framework/actiontriggerhelper.hxx> +#include <toolkit/awt/vclxmenu.hxx> +#include <toolkit/helper/vclunohelper.hxx> +#include <vcl/treelistentry.hxx> +#include <vcl/event.hxx> + +#include <memory> + +namespace dbaui +{ + +using namespace ::com::sun::star; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::beans; +using namespace ::com::sun::star::lang; +using namespace ::com::sun::star::datatransfer; +using namespace ::com::sun::star::ui; +using namespace ::com::sun::star::view; + +#define SPACEBETWEENENTRIES 4 +DBTreeListBox::DBTreeListBox( vcl::Window* pParent, WinBits nWinStyle ) + :SvTreeListBox(pParent,nWinStyle) + ,m_pDragedEntry(nullptr) + ,m_pActionListener(nullptr) + ,m_pContextMenuProvider(nullptr) + ,m_pResetEvent(nullptr) +{ + init(); +} + +void DBTreeListBox::init() +{ + SetSpaceBetweenEntries(SPACEBETWEENENTRIES); + + m_aTimer.SetTimeout(900); + m_aTimer.SetInvokeHandler(LINK(this, DBTreeListBox, OnTimeOut)); + + m_aScrollHelper.setUpScrollMethod( LINK(this, DBTreeListBox, ScrollUpHdl) ); + m_aScrollHelper.setDownScrollMethod( LINK(this, DBTreeListBox, ScrollDownHdl) ); + + SetNodeDefaultImages( ); + + EnableContextMenuHandling(); + + SetQuickSearch( true ); +} + +DBTreeListBox::~DBTreeListBox() +{ + assert(!m_xMenuController.is()); + disposeOnce(); +} + +void DBTreeListBox::dispose() +{ + if (m_pResetEvent) + { + RemoveUserEvent(m_pResetEvent); + m_pResetEvent = nullptr; + } + implStopSelectionTimer(); + SvTreeListBox::dispose(); +} + +SvTreeListEntry* DBTreeListBox::GetEntryPosByName( const OUString& aName, SvTreeListEntry* pStart, const IEntryFilter* _pFilter ) const +{ + SvTreeList* myModel = GetModel(); + std::pair<SvTreeListEntries::const_iterator,SvTreeListEntries::const_iterator> aIters = + myModel->GetChildIterators(pStart); + + SvTreeListEntry* pEntry = nullptr; + SvTreeListEntries::const_iterator it = aIters.first, itEnd = aIters.second; + for (; it != itEnd; ++it) + { + pEntry = (*it).get(); + const SvLBoxString* pItem = static_cast<const SvLBoxString*>( + pEntry->GetFirstItem(SvLBoxItemType::String)); + + if (pItem && pItem->GetText() == aName) + { + if (!_pFilter || _pFilter->includeEntry(pEntry->GetUserData())) + // found + break; + } + pEntry = nullptr; + } + + return pEntry; +} + +void DBTreeListBox::RequestingChildren( SvTreeListEntry* pParent ) +{ + if (m_aPreExpandHandler.IsSet() && !m_aPreExpandHandler.Call(pParent)) + { + // an error occurred. The method calling us will reset the entry flags, so it can't be expanded again. + // But we want that the user may do a second try (i.e. because he mistypes a password in this try), so + // we have to reset these flags controlling the expand ability + m_pResetEvent = PostUserEvent(LINK(this, DBTreeListBox, OnResetEntryHdl), pParent, true); + } +} + +void DBTreeListBox::InitEntry(SvTreeListEntry* _pEntry, const OUString& aStr, const Image& _rCollEntryBmp, const Image& _rExpEntryBmp) +{ + SvTreeListBox::InitEntry( _pEntry, aStr, _rCollEntryBmp,_rExpEntryBmp); + SvLBoxItem* pTextItem(_pEntry->GetFirstItem(SvLBoxItemType::String)); + _pEntry->ReplaceItem(std::make_unique<OBoldListboxString>(aStr), _pEntry->GetPos(pTextItem)); +} + +void DBTreeListBox::implStopSelectionTimer() +{ + if ( m_aTimer.IsActive() ) + m_aTimer.Stop(); +} + +void DBTreeListBox::implStartSelectionTimer() +{ + implStopSelectionTimer(); + m_aTimer.Start(); +} + +void DBTreeListBox::DeselectHdl() +{ + m_aSelectedEntries.erase( GetHdlEntry() ); + SvTreeListBox::DeselectHdl(); + implStartSelectionTimer(); +} + +void DBTreeListBox::SelectHdl() +{ + m_aSelectedEntries.insert( GetHdlEntry() ); + SvTreeListBox::SelectHdl(); + implStartSelectionTimer(); +} + +void DBTreeListBox::MouseButtonDown( const MouseEvent& rMEvt ) +{ + bool bHitEmptySpace = (nullptr == GetEntry(rMEvt.GetPosPixel(), true)); + if (bHitEmptySpace && (rMEvt.GetClicks() == 2) && rMEvt.IsMod1()) + Control::MouseButtonDown(rMEvt); + else + SvTreeListBox::MouseButtonDown(rMEvt); +} + +void DBTreeListBox::EnableExpandHandler(SvTreeListEntry* pEntry) +{ + // set the flag which allows if the entry can be expanded + pEntry->SetFlags( (pEntry->GetFlags() & ~SvTLEntryFlags(SvTLEntryFlags::NO_NODEBMP | SvTLEntryFlags::HAD_CHILDREN)) | SvTLEntryFlags::CHILDREN_ON_DEMAND ); + // redraw the entry + GetModel()->InvalidateEntry(pEntry); +} + +IMPL_LINK(DBTreeListBox, OnResetEntryHdl, void*, p, void) +{ + m_pResetEvent = nullptr; + EnableExpandHandler(static_cast<SvTreeListEntry*>(p)); +} + +void DBTreeListBox::ModelHasEntryInvalidated( SvTreeListEntry* _pEntry ) +{ + SvTreeListBox::ModelHasEntryInvalidated( _pEntry ); + + if (m_aSelectedEntries.find(_pEntry) != m_aSelectedEntries.end()) + { + SvLBoxItem* pTextItem = _pEntry->GetFirstItem(SvLBoxItemType::String); + if ( pTextItem && !static_cast< OBoldListboxString* >( pTextItem )->isEmphasized() ) + { + implStopSelectionTimer(); + m_aSelectedEntries.erase(_pEntry); + // ehm - why? + } + } +} + +void DBTreeListBox::ModelHasRemoved( SvTreeListEntry* _pEntry ) +{ + SvTreeListBox::ModelHasRemoved(_pEntry); + if (m_aSelectedEntries.find(_pEntry) != m_aSelectedEntries.end()) + { + implStopSelectionTimer(); + m_aSelectedEntries.erase(_pEntry); + } +} + +sal_Int8 DBTreeListBox::AcceptDrop( const AcceptDropEvent& _rEvt ) +{ + sal_Int8 nDropOption = DND_ACTION_NONE; + if ( m_pActionListener ) + { + SvTreeListEntry* pDroppedEntry = GetEntry(_rEvt.maPosPixel); + // check if drag is on child entry, which is not allowed + SvTreeListEntry* pParent = nullptr; + if ( _rEvt.mnAction & DND_ACTION_MOVE ) + { + if ( !m_pDragedEntry ) // no entry to move + { + nDropOption = m_pActionListener->queryDrop( _rEvt, GetDataFlavorExVector() ); + m_aMousePos = _rEvt.maPosPixel; + m_aScrollHelper.scroll(m_aMousePos,GetOutputSizePixel()); + return nDropOption; + } + + pParent = pDroppedEntry ? GetParent(pDroppedEntry) : nullptr; + while ( pParent && pParent != m_pDragedEntry ) + pParent = GetParent(pParent); + } + + if ( !pParent ) + { + nDropOption = m_pActionListener->queryDrop( _rEvt, GetDataFlavorExVector() ); + // check if move is allowed + if ( nDropOption & DND_ACTION_MOVE ) + { + if ( m_pDragedEntry == pDroppedEntry || GetEntryPosByName(GetEntryText(m_pDragedEntry),pDroppedEntry) ) + nDropOption = nDropOption & ~DND_ACTION_MOVE;//DND_ACTION_NONE; + } + m_aMousePos = _rEvt.maPosPixel; + m_aScrollHelper.scroll(m_aMousePos,GetOutputSizePixel()); + } + } + + return nDropOption; +} + +sal_Int8 DBTreeListBox::ExecuteDrop( const ExecuteDropEvent& _rEvt ) +{ + if ( m_pActionListener ) + return m_pActionListener->executeDrop( _rEvt ); + + return DND_ACTION_NONE; +} + +void DBTreeListBox::StartDrag( sal_Int8 /*_nAction*/, const Point& _rPosPixel ) +{ + if ( m_pActionListener ) + { + m_pDragedEntry = GetEntry(_rPosPixel); + if ( m_pDragedEntry && m_pActionListener->requestDrag( _rPosPixel ) ) + { + // if the (asynchronous) drag started, stop the selection timer + implStopSelectionTimer(); + // and stop selecting entries by simply moving the mouse + EndSelection(); + } + } +} + +void DBTreeListBox::RequestHelp( const HelpEvent& rHEvt ) +{ + if ( !m_pActionListener ) + { + SvTreeListBox::RequestHelp( rHEvt ); + return; + } + + if( rHEvt.GetMode() & HelpEventMode::QUICK ) + { + Point aPos( ScreenToOutputPixel( rHEvt.GetMousePosPixel() )); + SvTreeListEntry* pEntry = GetEntry( aPos ); + if( pEntry ) + { + OUString sQuickHelpText; + if ( m_pActionListener->requestQuickHelp( pEntry, sQuickHelpText ) ) + { + Size aSize( GetOutputSizePixel().Width(), GetEntryHeight() ); + tools::Rectangle aScreenRect( OutputToScreenPixel( GetEntryPosition( pEntry ) ), aSize ); + + Help::ShowQuickHelp( this, aScreenRect, + sQuickHelpText, QuickHelpFlags::Left | QuickHelpFlags::VCenter ); + return; + } + } + } + + SvTreeListBox::RequestHelp( rHEvt ); +} + +void DBTreeListBox::KeyInput( const KeyEvent& rKEvt ) +{ + KeyFuncType eFunc = rKEvt.GetKeyCode().GetFunction(); + sal_uInt16 nCode = rKEvt.GetKeyCode().GetCode(); + bool bHandled = false; + + if(eFunc != KeyFuncType::DONTKNOW) + { + switch(eFunc) + { + case KeyFuncType::COPY: + bHandled = ( m_aCopyHandler.IsSet() && !m_aSelectedEntries.empty() ); + if ( bHandled ) + m_aCopyHandler.Call( nullptr ); + break; + case KeyFuncType::PASTE: + bHandled = ( m_aPasteHandler.IsSet() && !m_aSelectedEntries.empty() ); + if ( bHandled ) + m_aPasteHandler.Call( nullptr ); + break; + case KeyFuncType::DELETE: + bHandled = ( m_aDeleteHandler.IsSet() && !m_aSelectedEntries.empty() ); + if ( bHandled ) + m_aDeleteHandler.Call( nullptr ); + break; + default: + break; + } + } + + if ( KEY_RETURN == nCode ) + { + bHandled = false; + m_aEnterKeyHdl.Call(this); + // this is a HACK. If the data source browser is opened in the "beamer", while the main frame + // + // contains a writer document, then pressing enter in the DSB would be rerouted to the writer + // + // document if we would not do this hack here. + // The problem is that the Writer uses RETURN as _accelerator_ (which is quite weird itself), + // + // so the SFX framework is _obligated_ to pass it to the Writer if nobody else handled it. There + // + // is no chance to distinguish between + // "accelerators which are to be executed if the main document has the focus" + // and + // "accelerators which are always to be executed" + // + // Thus we cannot prevent the handling of this key in the writer without declaring the key event + // as "handled" herein. + // + // The bad thing about this approach is that it does not scale. Every other accelerator which + // is used by the document will raise a similar bug once somebody discovers it. + // If this is the case, we should discuss a real solution with the framework (SFX) and the + // applications. + } + + if ( !bHandled ) + SvTreeListBox::KeyInput(rKEvt); +} + +bool DBTreeListBox::EditingEntry( SvTreeListEntry* /*pEntry*/, Selection& /*_aSelection*/) +{ + return false; +} + +bool DBTreeListBox::EditedEntry( SvTreeListEntry* pEntry, const OUString& rNewText ) +{ + DBTreeEditedEntry aEntry; + aEntry.aNewText = rNewText; + SetEntryText(pEntry,aEntry.aNewText); + + return false; // we never want that the base change our text +} + +bool DBTreeListBox::DoubleClickHdl() +{ + // continue default processing if the DoubleClickHandler didn't handle it + return !aDoubleClickHdl.Call( this ); +} + +static void scrollWindow(DBTreeListBox* _pListBox, const Point& _rPos,bool _bUp) +{ + SvTreeListEntry* pEntry = _pListBox->GetEntry( _rPos ); + if( pEntry && pEntry != _pListBox->Last() ) + { + _pListBox->ScrollOutputArea( _bUp ? -1 : 1 ); + } +} + +IMPL_LINK_NOARG( DBTreeListBox, ScrollUpHdl, LinkParamNone*, void ) +{ + scrollWindow(this,m_aMousePos,true); +} + +IMPL_LINK_NOARG( DBTreeListBox, ScrollDownHdl, LinkParamNone*, void ) +{ + scrollWindow(this,m_aMousePos,false); +} + +namespace +{ + // SelectionSupplier + typedef ::cppu::WeakImplHelper< XSelectionSupplier + > SelectionSupplier_Base; + class SelectionSupplier : public SelectionSupplier_Base + { + public: + explicit SelectionSupplier( const Any& _rSelection ) + :m_aSelection( _rSelection ) + { + } + + virtual sal_Bool SAL_CALL select( const Any& xSelection ) override; + virtual Any SAL_CALL getSelection( ) override; + virtual void SAL_CALL addSelectionChangeListener( const Reference< XSelectionChangeListener >& xListener ) override; + virtual void SAL_CALL removeSelectionChangeListener( const Reference< XSelectionChangeListener >& xListener ) override; + + protected: + virtual ~SelectionSupplier() override + { + } + + private: + Any m_aSelection; + }; + + sal_Bool SAL_CALL SelectionSupplier::select( const Any& /*_Selection*/ ) + { + throw IllegalArgumentException(); + // API bug: this should be a NoSupportException + } + + Any SAL_CALL SelectionSupplier::getSelection( ) + { + return m_aSelection; + } + + void SAL_CALL SelectionSupplier::addSelectionChangeListener( const Reference< XSelectionChangeListener >& /*_Listener*/ ) + { + OSL_FAIL( "SelectionSupplier::removeSelectionChangeListener: no support!" ); + // API bug: this should be a NoSupportException + } + + void SAL_CALL SelectionSupplier::removeSelectionChangeListener( const Reference< XSelectionChangeListener >& /*_Listener*/ ) + { + OSL_FAIL( "SelectionSupplier::removeSelectionChangeListener: no support!" ); + // API bug: this should be a NoSupportException + } +} + +VclPtr<PopupMenu> DBTreeListBox::CreateContextMenu() +{ + if ( !m_pContextMenuProvider ) + return nullptr; + + OUString aResourceName( m_pContextMenuProvider->getContextMenuResourceName( *this ) ); + if ( aResourceName.isEmpty() ) + return nullptr; + + css::uno::Sequence< css::uno::Any > aArgs( 3 ); + aArgs[0] <<= comphelper::makePropertyValue( "Value", aResourceName ); + aArgs[1] <<= comphelper::makePropertyValue( "Frame", m_pContextMenuProvider->getCommandController().getXController()->getFrame() ); + aArgs[2] <<= comphelper::makePropertyValue( "IsContextMenu", true ); + + css::uno::Reference< css::uno::XComponentContext > xContext = comphelper::getProcessComponentContext(); + m_xMenuController.set( xContext->getServiceManager()->createInstanceWithArgumentsAndContext( + "com.sun.star.comp.framework.ResourceMenuController", aArgs, xContext ), css::uno::UNO_QUERY ); + + if ( !m_xMenuController.is() ) + return nullptr; + + rtl::Reference xPopupMenu( new VCLXPopupMenu ); + m_xMenuController->setPopupMenu( xPopupMenu.get() ); + VclPtr<PopupMenu> pContextMenu( static_cast< PopupMenu* >( xPopupMenu->GetMenu() ) ); + pContextMenu->AddEventListener( LINK( this, DBTreeListBox, MenuEventListener ) ); + + // allow context menu interception + ::comphelper::OInterfaceContainerHelper2* pInterceptors = m_pContextMenuProvider->getContextMenuInterceptors(); + if ( !pInterceptors || !pInterceptors->getLength() ) + return pContextMenu; + + OUString aMenuIdentifier( "private:resource/popupmenu/" + aResourceName ); + + ContextMenuExecuteEvent aEvent; + aEvent.SourceWindow = VCLUnoHelper::GetInterface( this ); + aEvent.ExecutePosition.X = -1; + aEvent.ExecutePosition.Y = -1; + aEvent.ActionTriggerContainer = ::framework::ActionTriggerHelper::CreateActionTriggerContainerFromMenu( + pContextMenu.get(), &aMenuIdentifier ); + aEvent.Selection = new SelectionSupplier( m_pContextMenuProvider->getCurrentSelection( *this ) ); + + ::comphelper::OInterfaceIteratorHelper2 aIter( *pInterceptors ); + bool bModifiedMenu = false; + bool bAskInterceptors = true; + while ( aIter.hasMoreElements() && bAskInterceptors ) + { + Reference< XContextMenuInterceptor > xInterceptor( aIter.next(), UNO_QUERY ); + if ( !xInterceptor.is() ) + continue; + + try + { + ContextMenuInterceptorAction eAction = xInterceptor->notifyContextMenuExecute( aEvent ); + switch ( eAction ) + { + case ContextMenuInterceptorAction_CANCELLED: + return nullptr; + + case ContextMenuInterceptorAction_EXECUTE_MODIFIED: + bModifiedMenu = true; + bAskInterceptors = false; + break; + + case ContextMenuInterceptorAction_CONTINUE_MODIFIED: + bModifiedMenu = true; + bAskInterceptors = true; + break; + + default: + OSL_FAIL( "DBTreeListBox::CreateContextMenu: unexpected return value of the interceptor call!" ); + [[fallthrough]]; + case ContextMenuInterceptorAction_IGNORED: + break; + } + } + catch( const DisposedException& e ) + { + if ( e.Context == xInterceptor ) + aIter.remove(); + } + } + + if ( bModifiedMenu ) + { + pContextMenu->Clear(); + ::framework::ActionTriggerHelper::CreateMenuFromActionTriggerContainer( + pContextMenu, aEvent.ActionTriggerContainer ); + aEvent.ActionTriggerContainer.clear(); + } + + return pContextMenu; +} + +void DBTreeListBox::ExecuteContextMenuAction( sal_uInt16 ) +{ +} + +IMPL_LINK( DBTreeListBox, MenuEventListener, VclMenuEvent&, rMenuEvent, void ) +{ + if ( rMenuEvent.GetId() == VclEventId::ObjectDying ) + { + css::uno::Reference< css::lang::XComponent > xComponent( m_xMenuController, css::uno::UNO_QUERY ); + if ( xComponent.is() ) + xComponent->dispose(); + m_xMenuController.clear(); + } +} + +IMPL_LINK_NOARG(DBTreeListBox, OnTimeOut, Timer*, void) +{ + implStopSelectionTimer(); + + m_aSelChangeHdl.Call( nullptr ); +} + +void DBTreeListBox::StateChanged( StateChangedType nStateChange ) +{ + if ( nStateChange == StateChangedType::Visible ) + implStopSelectionTimer(); +} + +} // namespace dbaui + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/control/listviewitems.cxx b/dbaccess/source/ui/control/listviewitems.cxx new file mode 100644 index 000000000..1036ed3b3 --- /dev/null +++ b/dbaccess/source/ui/control/listviewitems.cxx @@ -0,0 +1,68 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <listviewitems.hxx> +#include <vcl/viewdataentry.hxx> + +namespace dbaui +{ + + void OBoldListboxString::InitViewData( SvTreeListBox* pView,SvTreeListEntry* pEntry, SvViewDataItem* _pViewData) + { + SvLBoxString::InitViewData( pView, pEntry, _pViewData ); + if ( !m_bEmphasized ) + return; + if (!_pViewData) + _pViewData = pView->GetViewDataItem( pEntry, this ); + pView->Push(); + vcl::Font aFont( pView->GetFont()); + aFont.SetWeight(WEIGHT_BOLD); + pView->Control::SetFont( aFont ); + _pViewData->mnWidth = pView->GetTextWidth(GetText()); + _pViewData->mnHeight = pView->GetTextHeight(); + pView->Pop(); + } + + SvLBoxItemType OBoldListboxString::GetType() const + { + return SvLBoxItemType::String; + } + + void OBoldListboxString::Paint(const Point& rPos, SvTreeListBox& rDev, vcl::RenderContext& rRenderContext, + const SvViewDataEntry* pView, const SvTreeListEntry& rEntry) + { + if (m_bEmphasized) + { + rRenderContext.Push(); + vcl::Font aFont(rRenderContext.GetFont()); + aFont.SetWeight(WEIGHT_BOLD); + rRenderContext.SetFont(aFont); + Point aPos(rPos); + rRenderContext.DrawText(aPos, GetText()); + rRenderContext.Pop(); + } + else + { + SvLBoxString::Paint(rPos, rDev, rRenderContext, pView, rEntry); + } + } + +} // namespace dbaui + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/control/marktree.cxx b/dbaccess/source/ui/control/marktree.cxx new file mode 100644 index 000000000..9bf664fa6 --- /dev/null +++ b/dbaccess/source/ui/control/marktree.cxx @@ -0,0 +1,206 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <marktree.hxx> +#include <vcl/treelistentry.hxx> +#include <vcl/svapp.hxx> +#include <vcl/settings.hxx> +#include <vcl/event.hxx> + +namespace dbaui +{ + using namespace ::com::sun::star::uno; + using namespace ::com::sun::star::lang; + + +OMarkableTreeListBox::OMarkableTreeListBox( vcl::Window* pParent, WinBits nWinStyle ) + : DBTreeListBox(pParent, nWinStyle) +{ + + InitButtonData(); +} + +OMarkableTreeListBox::~OMarkableTreeListBox() +{ + disposeOnce(); +} + +void OMarkableTreeListBox::dispose() +{ + m_pCheckButton.reset(); + DBTreeListBox::dispose(); +} + +void OMarkableTreeListBox::Paint(vcl::RenderContext& rRenderContext, const tools::Rectangle& _rRect) +{ + if (!IsEnabled()) + { + vcl::Font aOldFont = rRenderContext.GetFont(); + vcl::Font aNewFont(aOldFont); + + StyleSettings aSystemStyle = Application::GetSettings().GetStyleSettings(); + aNewFont.SetColor(aSystemStyle.GetDisableColor()); + + rRenderContext.SetFont(aNewFont); + DBTreeListBox::Paint(rRenderContext, _rRect); + rRenderContext.SetFont(aOldFont); + } + else + DBTreeListBox::Paint(rRenderContext, _rRect); +} + +void OMarkableTreeListBox::InitButtonData() +{ + m_pCheckButton.reset( new SvLBoxButtonData( this ) ); + EnableCheckButton( m_pCheckButton.get() ); +} + +void OMarkableTreeListBox::KeyInput( const KeyEvent& rKEvt ) +{ + // only if there are spaces + if (rKEvt.GetKeyCode().GetCode() == KEY_SPACE && !rKEvt.GetKeyCode().IsShift() && !rKEvt.GetKeyCode().IsMod1()) + { + SvTreeListEntry* pCurrentHandlerEntry = GetHdlEntry(); + if(pCurrentHandlerEntry) + { + SvButtonState eState = GetCheckButtonState( pCurrentHandlerEntry); + if(eState == SvButtonState::Checked) + SetCheckButtonState( pCurrentHandlerEntry, SvButtonState::Unchecked); + else + SetCheckButtonState( pCurrentHandlerEntry, SvButtonState::Checked); + + CheckButtonHdl(); + } + else + DBTreeListBox::KeyInput(rKEvt); + } + else + DBTreeListBox::KeyInput(rKEvt); +} + +SvButtonState OMarkableTreeListBox::implDetermineState(SvTreeListEntry* _pEntry) +{ + SvButtonState eState = GetCheckButtonState(_pEntry); + if (!GetModel()->HasChildren(_pEntry)) + // nothing to do in this bottom-up routine if there are no children ... + return eState; + + // loop through the children and check their states + sal_uInt16 nCheckedChildren = 0; + sal_uInt16 nChildrenOverall = 0; + + SvTreeListEntry* pChildLoop = GetModel()->FirstChild(_pEntry); + while (pChildLoop) + { + SvButtonState eChildState = implDetermineState(pChildLoop); + if (SvButtonState::Tristate == eChildState) + break; + + if (SvButtonState::Checked == eChildState) + ++nCheckedChildren; + ++nChildrenOverall; + + pChildLoop = pChildLoop->NextSibling(); + } + + if (pChildLoop) + { + // we did not finish the loop because at least one of the children is in tristate + eState = SvButtonState::Tristate; + + // but this means that we did not finish all the siblings of pChildLoop, + // so their checking may be incorrect at the moment + // -> correct this + while (pChildLoop) + { + implDetermineState(pChildLoop); + pChildLoop = pChildLoop->NextSibling(); + } + } + else + // none if the children are in tristate + if (nCheckedChildren) + // we have at least one child checked + if (nCheckedChildren != nChildrenOverall) + // not all children are checked + eState = SvButtonState::Tristate; + else + // all children are checked + eState = SvButtonState::Checked; + else + // no children are checked + eState = SvButtonState::Unchecked; + + // finally set the entry to the state we just determined + SetCheckButtonState(_pEntry, eState); + + return eState; +} + +void OMarkableTreeListBox::CheckButtons() +{ + SvTreeListEntry* pEntry = GetModel()->First(); + while (pEntry) + { + implDetermineState(pEntry); + pEntry = pEntry->NextSibling(); + } +} + +void OMarkableTreeListBox::CheckButtonHdl() +{ + checkedButton_noBroadcast(GetHdlEntry()); +} + +void OMarkableTreeListBox::checkedButton_noBroadcast(SvTreeListEntry* _pEntry) +{ + SvButtonState eState = GetCheckButtonState( _pEntry); + if (GetModel()->HasChildren(_pEntry)) // if it has children, check those too + { + SvTreeListEntry* pChildEntry = GetModel()->Next(_pEntry); + SvTreeListEntry* pSiblingEntry = _pEntry->NextSibling(); + while(pChildEntry && pChildEntry != pSiblingEntry) + { + SetCheckButtonState(pChildEntry, eState); + pChildEntry = GetModel()->Next(pChildEntry); + } + } + + SvTreeListEntry* pEntry = IsSelected(_pEntry) ? FirstSelected() : nullptr; + while(pEntry) + { + SetCheckButtonState(pEntry,eState); + if(GetModel()->HasChildren(pEntry)) // if it has children, check those too + { + SvTreeListEntry* pChildEntry = GetModel()->Next(pEntry); + SvTreeListEntry* pSiblingEntry = pEntry->NextSibling(); + while(pChildEntry && pChildEntry != pSiblingEntry) + { + SetCheckButtonState(pChildEntry,eState); + pChildEntry = GetModel()->Next(pChildEntry); + } + } + pEntry = NextSelected(pEntry); + } + CheckButtons(); +} + +} // namespace + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/control/opendoccontrols.cxx b/dbaccess/source/ui/control/opendoccontrols.cxx new file mode 100644 index 000000000..a80ed3ede --- /dev/null +++ b/dbaccess/source/ui/control/opendoccontrols.cxx @@ -0,0 +1,196 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <opendoccontrols.hxx> + +#include <com/sun/star/uno/Sequence.hxx> +#include <com/sun/star/beans/PropertyValue.hpp> +#include <com/sun/star/lang/XMultiServiceFactory.hpp> +#include <com/sun/star/container/XNameAccess.hpp> +#include <com/sun/star/ui/theModuleUIConfigurationManagerSupplier.hpp> +#include <com/sun/star/ui/XUIConfigurationManager.hpp> +#include <com/sun/star/graphic/XGraphic.hpp> +#include <com/sun/star/ui/XImageManager.hpp> + +#include <comphelper/processfactory.hxx> +#include <vcl/commandinfoprovider.hxx> +#include <unotools/historyoptions.hxx> +#include <comphelper/sequenceashashmap.hxx> +#include <tools/urlobj.hxx> +#include <osl/diagnose.h> + +namespace dbaui +{ + + namespace + { + using ::com::sun::star::uno::Reference; + using ::com::sun::star::uno::Exception; + using ::com::sun::star::uno::Sequence; + using ::com::sun::star::uno::XComponentContext; + using ::com::sun::star::container::XNameAccess; + using ::com::sun::star::beans::PropertyValue; + using ::com::sun::star::ui::theModuleUIConfigurationManagerSupplier; + using ::com::sun::star::ui::XModuleUIConfigurationManagerSupplier; + using ::com::sun::star::ui::XUIConfigurationManager; + using ::com::sun::star::ui::XImageManager; + using ::com::sun::star::graphic::XGraphic; + + Reference< XGraphic> GetCommandIcon( const char* _pCommandURL, const OUString& _rModuleName ) + { + if ( !_pCommandURL || !*_pCommandURL ) + return nullptr; + + OUString sCommandURL = OUString::createFromAscii( _pCommandURL ); + try + { + do + { + // Retrieve popup menu labels + Reference< css::uno::XComponentContext > xContext( ::comphelper::getProcessComponentContext() ); + if ( !xContext.is() ) + break; + + Reference< XModuleUIConfigurationManagerSupplier > xSupplier( + theModuleUIConfigurationManagerSupplier::get(xContext) ); + + Reference< XUIConfigurationManager > xManager( xSupplier->getUIConfigurationManager( _rModuleName ) ); + Reference< XImageManager > xImageManager; + if ( xManager.is() ) + xImageManager.set(xManager->getImageManager(), css::uno::UNO_QUERY); + if ( !xImageManager.is() ) + break; + + Sequence< OUString > aCommandList( &sCommandURL, 1 ); + Sequence<Reference< XGraphic> > xIconList( xImageManager->getImages( 0, aCommandList ) ); + if ( !xIconList.hasElements() ) + break; + + return xIconList[0]; + } + while ( false ); + } + catch ( Exception& ) {} + + return nullptr; + } + } + + // OpenButton + + OpenDocumentButton::OpenDocumentButton(std::unique_ptr<weld::Button> xControl, const char* _pAsciiModuleName) + : m_xControl(std::move(xControl)) + { + impl_init( _pAsciiModuleName ); + } + + void OpenDocumentButton::impl_init( const char* _pAsciiModuleName ) + { + OSL_ENSURE( _pAsciiModuleName, "OpenDocumentButton::impl_init: invalid module name!" ); + m_sModule = OUString::createFromAscii( _pAsciiModuleName ); + + // our label should equal the UI text of the "Open" command + auto aProperties = vcl::CommandInfoProvider::GetCommandProperties(".uno:Open", m_sModule); + OUString sLabel(vcl::CommandInfoProvider::GetLabelForCommand(aProperties)); + m_xControl->set_label(" " + sLabel.replaceAll("~", "")); + + // Place icon left of text and both centered in the button. + m_xControl->set_image(GetCommandIcon(".uno:Open", m_sModule)); + } + + // OpenDocumentListBox + + OpenDocumentListBox::OpenDocumentListBox(std::unique_ptr<weld::ComboBox> xControl, const char* _pAsciiModuleName ) + : m_xControl(std::move(xControl)) + { + // we need to limit the max auto width feature of the filter box + int nWidth = m_xControl->get_approximate_digit_width() * 50; + m_xControl->set_size_request(nWidth, -1); + + impl_init( _pAsciiModuleName ); + } + + void OpenDocumentListBox::impl_init( const char* _pAsciiModuleName ) + { + OSL_ENSURE( _pAsciiModuleName, "OpenDocumentListBox::impl_init: invalid module name!" ); + + Sequence< Sequence< PropertyValue> > aHistory = SvtHistoryOptions().GetList( ePICKLIST ); + Reference< XNameAccess > xFilterFactory; + xFilterFactory.set(::comphelper::getProcessServiceFactory()->createInstance( + "com.sun.star.document.FilterFactory" ), css::uno::UNO_QUERY); + + sal_uInt32 nCount = aHistory.getLength(); + for ( sal_uInt32 nItem = 0; nItem < nCount; ++nItem ) + { + try + { + // Get the current history item's properties. + ::comphelper::SequenceAsHashMap aItemProperties( aHistory[ nItem ] ); + OUString sURL = aItemProperties.getUnpackedValueOrDefault( HISTORY_PROPERTYNAME_URL, OUString() ); + OUString sFilter = aItemProperties.getUnpackedValueOrDefault( HISTORY_PROPERTYNAME_FILTER, OUString() ); + OUString sTitle = aItemProperties.getUnpackedValueOrDefault( HISTORY_PROPERTYNAME_TITLE, OUString() ); + OUString sPassword = aItemProperties.getUnpackedValueOrDefault( HISTORY_PROPERTYNAME_PASSWORD, OUString() ); + + // If the entry is an impress file then insert it into the + // history list and the list box. + Sequence< PropertyValue > aProps; + xFilterFactory->getByName( sFilter ) >>= aProps; + + ::comphelper::SequenceAsHashMap aFilterProperties( aProps ); + OUString sDocumentService = aFilterProperties.getUnpackedValueOrDefault( + "DocumentService", OUString() ); + if ( sDocumentService.equalsAscii( _pAsciiModuleName ) ) + { + // yes, it's a Base document + INetURLObject aURL; + aURL.SetSmartURL( sURL ); + // The password is set only when it is not empty. + if ( !sPassword.isEmpty() ) + aURL.SetPass( sPassword ); + + if ( sTitle.isEmpty() ) + sTitle = aURL.getBase( INetURLObject::LAST_SEGMENT, true, INetURLObject::DecodeMechanism::Unambiguous ); + + OUString sDecodedURL = aURL.GetMainURL( INetURLObject::DecodeMechanism::NONE ); + + m_xControl->append_text(sTitle); + m_aURLs.emplace_back(StringPair(sDecodedURL, sFilter)); + } + } + catch( Exception& ) {} + } + } + + OUString OpenDocumentListBox::GetSelectedDocumentURL() const + { + OUString sURL; + sal_Int32 nSelected = m_xControl->get_active(); + if (nSelected != -1) + sURL = impl_getDocumentAtIndex( nSelected ).first; + return sURL; + } + + OpenDocumentListBox::StringPair OpenDocumentListBox::impl_getDocumentAtIndex( sal_uInt16 _nListIndex ) const + { + return m_aURLs[_nListIndex]; + } + +} // namespace dbaui + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/control/sqledit.cxx b/dbaccess/source/ui/control/sqledit.cxx new file mode 100644 index 000000000..ccbe210af --- /dev/null +++ b/dbaccess/source/ui/control/sqledit.cxx @@ -0,0 +1,248 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <sal/config.h> + +#include <cassert> + +#include <com/sun/star/beans/XMultiPropertySet.hpp> +#include <com/sun/star/beans/XPropertiesChangeListener.hpp> +#include <com/sun/star/container/XHierarchicalNameAccess.hpp> +#include <officecfg/Office/Common.hxx> +#include <sqledit.hxx> +#include <QueryTextView.hxx> +#include <querycontainerwindow.hxx> +#include <helpids.h> +#include <undosqledit.hxx> +#include <QueryDesignView.hxx> +#include <svx/svxids.hrc> +#include <vcl/settings.hxx> +#include <cppuhelper/implbase.hxx> +#include <i18nlangtag/languagetag.hxx> +#include <vcl/event.hxx> +#include <vcl/svapp.hxx> + +using namespace dbaui; + +class OSqlEdit::ChangesListener: + public cppu::WeakImplHelper< css::beans::XPropertiesChangeListener > +{ +public: + explicit ChangesListener(OSqlEdit & editor): editor_(editor) {} + +private: + virtual ~ChangesListener() override {} + + virtual void SAL_CALL disposing(css::lang::EventObject const &) override + { + osl::MutexGuard g(editor_.m_mutex); + editor_.m_notifier.clear(); + } + + virtual void SAL_CALL propertiesChange( + css::uno::Sequence< css::beans::PropertyChangeEvent > const &) override + { + SolarMutexGuard g; + editor_.ImplSetFont(); + } + + OSqlEdit & editor_; +}; + +OSqlEdit::OSqlEdit( OQueryTextView* pParent ) : + MultiLineEditSyntaxHighlight( pParent, WB_LEFT | WB_VSCROLL | WB_BORDER ) + ,m_pView(pParent) + ,m_bAccelAction( false ) + ,m_bStopTimer(false ) +{ + SetHelpId( HID_CTL_QRYSQLEDIT ); + SetModifyHdl( LINK(this, OSqlEdit, ModifyHdl) ); + + m_timerUndoActionCreation.SetTimeout(1000); + m_timerUndoActionCreation.SetInvokeHandler(LINK(this, OSqlEdit, OnUndoActionTimer)); + + m_timerInvalidate.SetTimeout(200); + m_timerInvalidate.SetInvokeHandler(LINK(this, OSqlEdit, OnInvalidateTimer)); + m_timerInvalidate.Start(); + + ImplSetFont(); + // Listen for change of Font and Color Settings: + // Using "this" in ctor is a little fishy, but should work here at least as + // long as there are no derivations: + m_listener = new ChangesListener(*this); + css::uno::Reference< css::beans::XMultiPropertySet > n( + officecfg::Office::Common::Font::SourceViewFont::get(), + css::uno::UNO_QUERY_THROW); + { + osl::MutexGuard g(m_mutex); + m_notifier = n; + } + css::uno::Sequence< OUString > s(2); + s[0] = "FontHeight"; + s[1] = "FontName"; + n->addPropertiesChangeListener(s, m_listener.get()); + m_ColorConfig.AddListener(this); + + //#i97044# + EnableFocusSelectionHide( false ); +} + +OSqlEdit::~OSqlEdit() +{ + disposeOnce(); +} + +void OSqlEdit::dispose() +{ + if (m_timerUndoActionCreation.IsActive()) + m_timerUndoActionCreation.Stop(); + css::uno::Reference< css::beans::XMultiPropertySet > n; + { + osl::MutexGuard g(m_mutex); + n = m_notifier; + } + if (n.is()) { + n->removePropertiesChangeListener(m_listener.get()); + } + m_ColorConfig.RemoveListener(this); + m_pView.clear(); + MultiLineEditSyntaxHighlight::dispose(); +} + +void OSqlEdit::KeyInput( const KeyEvent& rKEvt ) +{ + OJoinController& rController = m_pView->getContainerWindow()->getDesignView()->getController(); + rController.InvalidateFeature(SID_CUT); + rController.InvalidateFeature(SID_COPY); + + // Is this a cut, copy, paste event? + KeyFuncType aKeyFunc = rKEvt.GetKeyCode().GetFunction(); + if( (aKeyFunc==KeyFuncType::CUT)||(aKeyFunc==KeyFuncType::COPY)||(aKeyFunc==KeyFuncType::PASTE) ) + m_bAccelAction = true; + + MultiLineEditSyntaxHighlight::KeyInput( rKEvt ); + + if( m_bAccelAction ) + m_bAccelAction = false; +} + + +void OSqlEdit::GetFocus() +{ + m_strOrigText =GetText(); + MultiLineEditSyntaxHighlight::GetFocus(); +} + +IMPL_LINK_NOARG(OSqlEdit, OnUndoActionTimer, Timer *, void) +{ + OUString aText = GetText(); + if(aText == m_strOrigText) + return; + + OJoinController& rController = m_pView->getContainerWindow()->getDesignView()->getController(); + SfxUndoManager& rUndoMgr = rController.GetUndoManager(); + std::unique_ptr<OSqlEditUndoAct> pUndoAct(new OSqlEditUndoAct( this )); + + pUndoAct->SetOriginalText( m_strOrigText ); + rUndoMgr.AddUndoAction( std::move(pUndoAct) ); + + rController.InvalidateFeature(SID_UNDO); + rController.InvalidateFeature(SID_REDO); + + m_strOrigText =aText; +} + +IMPL_LINK_NOARG(OSqlEdit, OnInvalidateTimer, Timer *, void) +{ + OJoinController& rController = m_pView->getContainerWindow()->getDesignView()->getController(); + rController.InvalidateFeature(SID_CUT); + rController.InvalidateFeature(SID_COPY); + if(!m_bStopTimer) + m_timerInvalidate.Start(); +} + +IMPL_LINK_NOARG(OSqlEdit, ModifyHdl, Edit&, void) +{ + if (m_timerUndoActionCreation.IsActive()) + m_timerUndoActionCreation.Stop(); + m_timerUndoActionCreation.Start(); + + OJoinController& rController = m_pView->getContainerWindow()->getDesignView()->getController(); + if (!rController.isModified()) + rController.setModified( true ); + + rController.InvalidateFeature(SID_SBA_QRY_EXECUTE); + rController.InvalidateFeature(SID_CUT); + rController.InvalidateFeature(SID_COPY); +} + +void OSqlEdit::SetText(const OUString& rNewText) +{ + if (m_timerUndoActionCreation.IsActive()) + { // create the trailing undo-actions + m_timerUndoActionCreation.Stop(); + LINK(this, OSqlEdit, OnUndoActionTimer).Call(nullptr); + } + + MultiLineEditSyntaxHighlight::SetText(rNewText); + m_strOrigText =rNewText; +} + +void OSqlEdit::stopTimer() +{ + m_bStopTimer = true; + if (m_timerInvalidate.IsActive()) + m_timerInvalidate.Stop(); +} + +void OSqlEdit::startTimer() +{ + m_bStopTimer = false; + if (!m_timerInvalidate.IsActive()) + m_timerInvalidate.Start(); +} + +void OSqlEdit::ConfigurationChanged( utl::ConfigurationBroadcaster* pOption, ConfigurationHints ) +{ + assert( pOption == &m_ColorConfig ); + (void) pOption; // avoid warnings + MultiLineEditSyntaxHighlight::UpdateData(); +} + +void OSqlEdit::ImplSetFont() +{ + AllSettings aSettings = GetSettings(); + StyleSettings aStyleSettings = aSettings.GetStyleSettings(); + OUString sFontName( + officecfg::Office::Common::Font::SourceViewFont::FontName::get(). + value_or( OUString() ) ); + if ( sFontName.isEmpty() ) + { + vcl::Font aTmpFont( OutputDevice::GetDefaultFont( DefaultFontType::FIXED, Application::GetSettings().GetUILanguageTag().getLanguageType(), GetDefaultFontFlags::NONE, this ) ); + sFontName = aTmpFont.GetFamilyName(); + } + Size aFontSize( + 0, officecfg::Office::Common::Font::SourceViewFont::FontHeight::get() ); + vcl::Font aFont( sFontName, aFontSize ); + aStyleSettings.SetFieldFont(aFont); + aSettings.SetStyleSettings(aStyleSettings); + SetSettings(aSettings); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/control/tabletree.cxx b/dbaccess/source/ui/control/tabletree.cxx new file mode 100644 index 000000000..b3170487e --- /dev/null +++ b/dbaccess/source/ui/control/tabletree.cxx @@ -0,0 +1,1006 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <core_resource.hxx> +#include <tabletree.hxx> +#include <imageprovider.hxx> +#include <strings.hrc> +#include <connectivity/dbtools.hxx> +#include <com/sun/star/sdb/application/DatabaseObject.hpp> +#include <com/sun/star/sdb/application/DatabaseObjectContainer.hpp> +#include <com/sun/star/sdbcx/XViewsSupplier.hpp> +#include <com/sun/star/sdbcx/XTablesSupplier.hpp> +#include <com/sun/star/sdbc/SQLException.hpp> +#include <com/sun/star/sdbc/XRow.hpp> +#include <com/sun/star/beans/XPropertySet.hpp> +#include <listviewitems.hxx> +#include <tools/diagnose_ex.h> +#include <osl/diagnose.h> +#include <connectivity/dbmetadata.hxx> +#include <vcl/treelistentry.hxx> + +#include <algorithm> + +namespace dbaui +{ + +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::sdb; +using namespace ::com::sun::star::lang; +using namespace ::com::sun::star::sdbc; +using namespace ::com::sun::star::sdbcx; +using namespace ::com::sun::star::beans; +using namespace ::com::sun::star::container; +using namespace ::com::sun::star::sdb::application; + +using namespace ::dbtools; +using namespace ::comphelper; + +namespace DatabaseObject = ::com::sun::star::sdb::application::DatabaseObject; +namespace DatabaseObjectContainer = ::com::sun::star::sdb::application::DatabaseObjectContainer; + +// OTableTreeListBox +OTableTreeListBox::OTableTreeListBox(vcl::Window* pParent, WinBits nWinStyle) + :OMarkableTreeListBox(pParent, nWinStyle) + ,m_xImageProvider( new ImageProvider ) +{ + implSetDefaultImages(); +} + +TableTreeListBox::TableTreeListBox(std::unique_ptr<weld::TreeView> xTreeView) + : m_xImageProvider(new ImageProvider) + , m_bVirtualRoot(false) + , m_bNoEmptyFolders(false) + , m_bShowToggles(true) + , m_nTextColumn(1) + , m_xTreeView(std::move(xTreeView)) +{ +} + +void OTableTreeListBox::implSetDefaultImages() +{ + SetDefaultExpandedEntryBmp( ImageProvider::getFolderImage( DatabaseObject::TABLE ) ); + SetDefaultCollapsedEntryBmp( ImageProvider::getFolderImage( DatabaseObject::TABLE ) ); +} + +bool OTableTreeListBox::isFolderEntry( const SvTreeListEntry* _pEntry ) +{ + sal_Int32 nEntryType = reinterpret_cast< sal_IntPtr >( _pEntry->GetUserData() ); + return ( nEntryType == DatabaseObjectContainer::TABLES ) + || ( nEntryType == DatabaseObjectContainer::CATALOG ) + || ( nEntryType == DatabaseObjectContainer::SCHEMA ); +} + +void OTableTreeListBox::notifyHiContrastChanged() +{ + implSetDefaultImages(); + + SvTreeListEntry* pEntryLoop = First(); + while (pEntryLoop) + { + size_t nCount = pEntryLoop->ItemCount(); + for (size_t i=0;i<nCount;++i) + { + SvLBoxItem& rItem = pEntryLoop->GetItem(i); + if (rItem.GetType() == SvLBoxItemType::ContextBmp) + { + SvLBoxContextBmp& rContextBitmapItem = static_cast< SvLBoxContextBmp& >( rItem ); + + Image aImage; + if ( isFolderEntry( pEntryLoop ) ) + { + aImage = ImageProvider::getFolderImage( DatabaseObject::TABLE ); + } + else + { + OUString sCompleteName( getQualifiedTableName( pEntryLoop ) ); + m_xImageProvider->getImages( sCompleteName, DatabaseObject::TABLE, aImage ); + } + + rContextBitmapItem.SetBitmap1( aImage ); + rContextBitmapItem.SetBitmap2( aImage ); + break; + } + } + pEntryLoop = Next(pEntryLoop); + } +} + +void OTableTreeListBox::implOnNewConnection( const Reference< XConnection >& _rxConnection ) +{ + m_xConnection = _rxConnection; + m_xImageProvider.reset( new ImageProvider( m_xConnection ) ); +} + +void TableTreeListBox::implOnNewConnection( const Reference< XConnection >& _rxConnection ) +{ + m_xConnection = _rxConnection; + m_xImageProvider.reset( new ImageProvider( m_xConnection ) ); +} + +void OTableTreeListBox::UpdateTableList( const Reference< XConnection >& _rxConnection ) +{ + Sequence< OUString > sTables, sViews; + + OUString sCurrentActionError; + try + { + Reference< XTablesSupplier > xTableSupp( _rxConnection, UNO_QUERY_THROW ); + sCurrentActionError = DBA_RES(STR_NOTABLEINFO); + + Reference< XNameAccess > xTables,xViews; + + Reference< XViewsSupplier > xViewSupp( _rxConnection, UNO_QUERY ); + if ( xViewSupp.is() ) + { + xViews = xViewSupp->getViews(); + if (xViews.is()) + sViews = xViews->getElementNames(); + } + + xTables = xTableSupp->getTables(); + if (xTables.is()) + sTables = xTables->getElementNames(); + } + catch(RuntimeException&) + { + OSL_FAIL("OTableTreeListBox::UpdateTableList : caught a RuntimeException!"); + } + catch ( const SQLException& ) + { + throw; + } + catch(Exception&) + { + css::uno::Any anyEx = cppu::getCaughtException(); + // a non-SQLException exception occurred ... simply throw an SQLException + throw SQLException(sCurrentActionError, nullptr, "", 0, anyEx); + } + + UpdateTableList( _rxConnection, sTables, sViews ); +} + +void TableTreeListBox::UpdateTableList( const Reference< XConnection >& _rxConnection ) +{ + Sequence< OUString > sTables, sViews; + + OUString sCurrentActionError; + try + { + Reference< XTablesSupplier > xTableSupp( _rxConnection, UNO_QUERY_THROW ); + sCurrentActionError = DBA_RES(STR_NOTABLEINFO); + + Reference< XNameAccess > xTables,xViews; + + Reference< XViewsSupplier > xViewSupp( _rxConnection, UNO_QUERY ); + if ( xViewSupp.is() ) + { + xViews = xViewSupp->getViews(); + if (xViews.is()) + sViews = xViews->getElementNames(); + } + + xTables = xTableSupp->getTables(); + if (xTables.is()) + sTables = xTables->getElementNames(); + } + catch(RuntimeException&) + { + OSL_FAIL("OTableTreeListBox::UpdateTableList : caught a RuntimeException!"); + } + catch ( const SQLException& ) + { + throw; + } + catch(Exception&) + { + css::uno::Any anyEx = cppu::getCaughtException(); + // a non-SQLException exception occurred ... simply throw an SQLException + throw SQLException(sCurrentActionError, nullptr, "", 0, anyEx); + } + + UpdateTableList( _rxConnection, sTables, sViews ); +} + +namespace +{ + struct OViewSetter + { + const Sequence< OUString> m_aViews; + ::comphelper::UStringMixEqual m_aEqualFunctor; + + OViewSetter(const Sequence< OUString>& _rViews,bool _bCase) : m_aViews(_rViews),m_aEqualFunctor(_bCase){} + OTableTreeListBox::TNames::value_type operator() (const OUString& name) + { + OTableTreeListBox::TNames::value_type aRet; + aRet.first = name; + aRet.second = std::any_of(m_aViews.begin(), m_aViews.end(), + [this, &name](const OUString& lhs) + { return m_aEqualFunctor(lhs, name); } ); + + return aRet; + } + }; + +} + +void OTableTreeListBox::UpdateTableList( + const Reference< XConnection >& _rxConnection, + const Sequence< OUString>& _rTables, + const Sequence< OUString>& _rViews + ) +{ + TNames aTables; + aTables.resize(_rTables.getLength()); + try + { + Reference< XDatabaseMetaData > xMeta( _rxConnection->getMetaData(), UNO_SET_THROW ); + std::transform( _rTables.begin(), _rTables.end(), + aTables.begin(), OViewSetter( _rViews, xMeta->supportsMixedCaseQuotedIdentifiers() ) ); + } + catch(Exception&) + { + DBG_UNHANDLED_EXCEPTION("dbaccess"); + } + UpdateTableList( _rxConnection, aTables ); +} + +void TableTreeListBox::UpdateTableList( + const Reference< XConnection >& _rxConnection, + const Sequence< OUString>& _rTables, + const Sequence< OUString>& _rViews + ) +{ + TNames aTables; + aTables.resize(_rTables.getLength()); + try + { + Reference< XDatabaseMetaData > xMeta( _rxConnection->getMetaData(), UNO_SET_THROW ); + std::transform( _rTables.begin(), _rTables.end(), + aTables.begin(), OViewSetter( _rViews, xMeta->supportsMixedCaseQuotedIdentifiers() ) ); + } + catch(Exception&) + { + DBG_UNHANDLED_EXCEPTION("dbaccess"); + } + UpdateTableList( _rxConnection, aTables ); +} + +namespace +{ + std::vector< OUString > lcl_getMetaDataStrings_throw( const Reference< XResultSet >& _rxMetaDataResult, sal_Int32 _nColumnIndex ) + { + std::vector< OUString > aStrings; + Reference< XRow > xRow( _rxMetaDataResult, UNO_QUERY_THROW ); + while ( _rxMetaDataResult->next() ) + aStrings.push_back( xRow->getString( _nColumnIndex ) ); + return aStrings; + } + + bool lcl_shouldDisplayEmptySchemasAndCatalogs( const Reference< XConnection >& _rxConnection ) + { + ::dbtools::DatabaseMetaData aMetaData( _rxConnection ); + return aMetaData.displayEmptyTableFolders(); + } +} + +void OTableTreeListBox::UpdateTableList( const Reference< XConnection >& _rxConnection, const TNames& _rTables ) +{ + implOnNewConnection( _rxConnection ); + + // throw away all the old stuff + Clear(); + + try + { + if ( _rTables.empty() ) + // nothing to do (besides inserting the root entry) + return; + + // get the table/view names + Reference< XDatabaseMetaData > xMeta( _rxConnection->getMetaData(), UNO_SET_THROW ); + for (auto const& table : _rTables) + { + // add the entry + implAddEntry( + xMeta, + table.first, + false + ); + } + + if ( lcl_shouldDisplayEmptySchemasAndCatalogs( _rxConnection ) ) + { + bool bSupportsCatalogs = xMeta->supportsCatalogsInDataManipulation(); + bool bSupportsSchemas = xMeta->supportsSchemasInDataManipulation(); + + if ( bSupportsCatalogs || bSupportsSchemas ) + { + // we display empty catalogs if the DB supports catalogs, and they're noted at the beginning of a + // composed name. Otherwise, we display empty schematas. (also see the tree structure explained in + // implAddEntry) + bool bCatalogs = bSupportsCatalogs && xMeta->isCatalogAtStart(); + + std::vector< OUString > aFolderNames( lcl_getMetaDataStrings_throw( + bCatalogs ? xMeta->getCatalogs() : xMeta->getSchemas(), 1 ) ); + sal_Int32 nFolderType = bCatalogs ? DatabaseObjectContainer::CATALOG : DatabaseObjectContainer::SCHEMA; + + for (auto const& folderName : aFolderNames) + { + SvTreeListEntry* pFolder = GetEntryPosByName( folderName, nullptr ); + if ( !pFolder ) + InsertEntry( folderName, nullptr, false, TREELIST_APPEND, reinterpret_cast< void* >( nFolderType ) ); + } + } + } + } + catch ( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("dbaccess"); + } +} + +void TableTreeListBox::DisableCheckButtons() +{ + m_bShowToggles = false; + m_nTextColumn = 0; +} + +void TableTreeListBox::UpdateTableList( const Reference< XConnection >& _rxConnection, const TNames& _rTables ) +{ + implOnNewConnection( _rxConnection ); + + // throw away all the old stuff + m_xTreeView->clear(); + m_xTreeView->make_unsorted(); + + try + { + if (haveVirtualRoot()) + { + OUString sRootEntryText; + if ( std::none_of(_rTables.begin(),_rTables.end(), + [] (const TNames::value_type& name) { return !name.second; }) ) + sRootEntryText = DBA_RES(STR_ALL_TABLES); + else if ( std::none_of(_rTables.begin(),_rTables.end(), + [] (const TNames::value_type& name) { return name.second; }) ) + sRootEntryText = DBA_RES(STR_ALL_VIEWS); + else + sRootEntryText = DBA_RES(STR_ALL_TABLES_AND_VIEWS); + OUString sId(OUString::number(DatabaseObjectContainer::TABLES)); + OUString sImageId = ImageProvider::getFolderImageId(DatabaseObject::TABLE); + std::unique_ptr<weld::TreeIter> xRet(m_xTreeView->make_iterator()); + m_xTreeView->insert(nullptr, -1, nullptr, &sId, nullptr, nullptr, nullptr, false, xRet.get()); + m_xTreeView->set_image(*xRet, sImageId, -1); + if (m_bShowToggles) + m_xTreeView->set_toggle(*xRet, TRISTATE_FALSE, 0); + m_xTreeView->set_text(*xRet, sRootEntryText, m_nTextColumn); + } + + if ( _rTables.empty() ) + // nothing to do (besides inserting the root entry) + return; + + // get the table/view names + Reference< XDatabaseMetaData > xMeta( _rxConnection->getMetaData(), UNO_SET_THROW ); + for (auto const& table : _rTables) + { + // add the entry + implAddEntry(xMeta, table.first); + } + + if ( !m_bNoEmptyFolders && lcl_shouldDisplayEmptySchemasAndCatalogs( _rxConnection ) ) + { + bool bSupportsCatalogs = xMeta->supportsCatalogsInDataManipulation(); + bool bSupportsSchemas = xMeta->supportsSchemasInDataManipulation(); + + if ( bSupportsCatalogs || bSupportsSchemas ) + { + // we display empty catalogs if the DB supports catalogs, and they're noted at the beginning of a + // composed name. Otherwise, we display empty schematas. (also see the tree structure explained in + // implAddEntry) + bool bCatalogs = bSupportsCatalogs && xMeta->isCatalogAtStart(); + + std::vector< OUString > aFolderNames( lcl_getMetaDataStrings_throw( + bCatalogs ? xMeta->getCatalogs() : xMeta->getSchemas(), 1 ) ); + sal_Int32 nFolderType = bCatalogs ? DatabaseObjectContainer::CATALOG : DatabaseObjectContainer::SCHEMA; + + OUString sImageId = ImageProvider::getFolderImageId(DatabaseObject::TABLE); + + std::unique_ptr<weld::TreeIter> xRootEntry(getAllObjectsEntry()); + std::unique_ptr<weld::TreeIter> xRet(m_xTreeView->make_iterator()); + for (auto const& folderName : aFolderNames) + { + std::unique_ptr<weld::TreeIter> xFolder(GetEntryPosByName(folderName, xRootEntry.get())); + if (!xFolder) + { + OUString sId(OUString::number(nFolderType)); + m_xTreeView->insert(xRootEntry.get(), -1, nullptr, &sId, nullptr, nullptr, nullptr, false, xRet.get()); + m_xTreeView->set_image(*xRet, sImageId, -1); + if (m_bShowToggles) + m_xTreeView->set_toggle(*xRet, TRISTATE_FALSE, 0); + m_xTreeView->set_text(*xRet, folderName, m_nTextColumn); + } + } + } + } + } + catch ( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("dbaccess"); + } + + m_xTreeView->make_sorted(); +} + +bool TableTreeListBox::isWildcardChecked(const weld::TreeIter& rEntry) +{ + return m_xTreeView->get_text_emphasis(rEntry, m_nTextColumn); +} + +void TableTreeListBox::checkWildcard(weld::TreeIter& rEntry) +{ + if (!m_bShowToggles) + return; + m_xTreeView->set_toggle(rEntry, TRISTATE_TRUE, 0); + checkedButton_noBroadcast(rEntry); +} + +std::unique_ptr<weld::TreeIter> TableTreeListBox::getAllObjectsEntry() const +{ + if (!haveVirtualRoot()) + return nullptr; + auto xRet = m_xTreeView->make_iterator(); + if (!m_xTreeView->get_iter_first(*xRet)) + return nullptr; + return xRet; +} + +void OTableTreeListBox::checkedButton_noBroadcast(SvTreeListEntry* _pEntry) +{ + OMarkableTreeListBox::checkedButton_noBroadcast(_pEntry); + + // if an entry has children, it makes a difference if the entry is checked + // because all children are checked or if the user checked it explicitly. + // So we track explicit (un)checking + + SvButtonState eState = GetCheckButtonState(_pEntry); + OSL_ENSURE(SvButtonState::Tristate != eState, "OTableTreeListBox::CheckButtonHdl: user action which lead to TRISTATE?"); + implEmphasize(_pEntry, SvButtonState::Checked == eState); +} + +void TableTreeListBox::checkedButton_noBroadcast(weld::TreeIter& rEntry) +{ + if (!m_bShowToggles) + return; + TriState eState = m_xTreeView->get_toggle(rEntry, 0); + OSL_ENSURE(TRISTATE_INDET != eState, "OTableTreeListBox::CheckButtonHdl: user action which lead to TRISTATE?"); + + if (m_xTreeView->iter_has_child(rEntry)) // if it has children, check those too + { + std::unique_ptr<weld::TreeIter> xChildEntry(m_xTreeView->make_iterator(&rEntry)); + std::unique_ptr<weld::TreeIter> xSiblingEntry(m_xTreeView->make_iterator(&rEntry)); + bool bChildEntry = m_xTreeView->iter_next(*xChildEntry); + bool bSiblingEntry = m_xTreeView->iter_next_sibling(*xSiblingEntry); + while (bChildEntry && (!bSiblingEntry || !xChildEntry->equal(*xSiblingEntry))) + { + m_xTreeView->set_toggle(*xChildEntry, eState, 0); + bChildEntry = m_xTreeView->iter_next(*xChildEntry); + } + } + + if (m_xTreeView->is_selected(rEntry)) + { + m_xTreeView->selected_foreach([this, eState](weld::TreeIter& rSelected){ + m_xTreeView->set_toggle(rSelected, eState, 0); + if (m_xTreeView->iter_has_child(rSelected)) // if it has children, check those too + { + std::unique_ptr<weld::TreeIter> xChildEntry(m_xTreeView->make_iterator(&rSelected)); + std::unique_ptr<weld::TreeIter> xSiblingEntry(m_xTreeView->make_iterator(&rSelected)); + bool bChildEntry = m_xTreeView->iter_next(*xChildEntry); + bool bSiblingEntry = m_xTreeView->iter_next_sibling(*xSiblingEntry); + while (bChildEntry && (!bSiblingEntry || !xChildEntry->equal(*xSiblingEntry))) + { + m_xTreeView->set_toggle(*xChildEntry, eState, 0); + bChildEntry = m_xTreeView->iter_next(*xChildEntry); + } + } + return false; + }); + } + + CheckButtons(); + + // if an entry has children, it makes a difference if the entry is checked + // because all children are checked or if the user checked it explicitly. + // So we track explicit (un)checking + implEmphasize(rEntry, eState == TRISTATE_TRUE); +} + +void OTableTreeListBox::implEmphasize(SvTreeListEntry* _pEntry, bool _bChecked, bool _bUpdateDescendants, bool _bUpdateAncestors) +{ + OSL_ENSURE(_pEntry, "OTableTreeListBox::implEmphasize: invalid entry (NULL)!"); + + if ( GetModel()->HasChildren(_pEntry) ) // the entry has children + { + OBoldListboxString* pTextItem = static_cast<OBoldListboxString*>(_pEntry->GetFirstItem(SvLBoxItemType::String)); + if (pTextItem) + pTextItem->emphasize(_bChecked); + } + + if (_bUpdateDescendants) + { + // remove the mark for all children of the checked entry + SvTreeListEntry* pChildLoop = FirstChild(_pEntry); + while (pChildLoop) + { + if (GetModel()->HasChildren(pChildLoop)) + implEmphasize(pChildLoop, false, true, false); + pChildLoop = pChildLoop->NextSibling(); + } + } + + if (_bUpdateAncestors) + { + // remove the mark for all ancestors of the entry + if (GetModel()->HasParent(_pEntry)) + implEmphasize(GetParent(_pEntry), false, false); + } +} + +void TableTreeListBox::implEmphasize(weld::TreeIter& rEntry, bool _bChecked, bool _bUpdateDescendants, bool _bUpdateAncestors) +{ + // special emphasizing handling for the "all objects" entry + bool bAllObjectsEntryAffected = haveVirtualRoot() && (getAllObjectsEntry()->equal(rEntry)); + if ( m_xTreeView->iter_has_child(rEntry) // the entry has children + || bAllObjectsEntryAffected // or it is the "all objects" entry + ) + { + m_xTreeView->set_text_emphasis(rEntry, _bChecked, m_nTextColumn); + } + + if (_bUpdateDescendants) + { + std::unique_ptr<weld::TreeIter> xChild(m_xTreeView->make_iterator(&rEntry)); + // remove the mark for all children of the checked entry + bool bChildLoop = m_xTreeView->iter_children(*xChild); + while (bChildLoop) + { + if (m_xTreeView->iter_has_child(*xChild)) + implEmphasize(*xChild, false, true, false); + bChildLoop = m_xTreeView->iter_next_sibling(*xChild); + } + } + + if (_bUpdateAncestors) + { + std::unique_ptr<weld::TreeIter> xParent(m_xTreeView->make_iterator(&rEntry)); + // remove the mark for all ancestors of the entry + if (m_xTreeView->iter_parent(*xParent)) + implEmphasize(*xParent, false, false); + } +} + +void OTableTreeListBox::InitEntry(SvTreeListEntry* _pEntry, const OUString& _rString, const Image& _rCollapsedBitmap, const Image& _rExpandedBitmap) +{ + OMarkableTreeListBox::InitEntry(_pEntry, _rString, _rCollapsedBitmap, _rExpandedBitmap); + + // replace the text item with our own one + SvLBoxItem* pTextItem = _pEntry->GetFirstItem(SvLBoxItemType::String); + OSL_ENSURE(pTextItem, "OTableTreeListBox::InitEntry: no text item!?"); + size_t nTextPos = _pEntry->GetPos(pTextItem); + OSL_ENSURE(SvTreeListEntry::ITEM_NOT_FOUND != nTextPos, "OTableTreeListBox::InitEntry: no text item pos!"); + + _pEntry->ReplaceItem(std::make_unique<OBoldListboxString>(_rString), nTextPos); +} + +SvTreeListEntry* OTableTreeListBox::implAddEntry( + const Reference< XDatabaseMetaData >& _rxMeta, + const OUString& _rTableName, + bool _bCheckName + ) +{ + OSL_PRECOND( _rxMeta.is(), "OTableTreeListBox::implAddEntry: invalid meta data!" ); + if ( !_rxMeta.is() ) + return nullptr; + + // split the complete name into its components + OUString sCatalog, sSchema, sName; + qualifiedNameComponents( _rxMeta, _rTableName, sCatalog, sSchema, sName, ::dbtools::EComposeRule::InDataManipulation ); + + SvTreeListEntry* pParentEntry = nullptr; + + // if the DB uses catalog at the start of identifiers, then our hierarchy is + // catalog + // +- schema + // +- table + // else it is + // schema + // +- catalog + // +- table + bool bCatalogAtStart = _rxMeta->isCatalogAtStart(); + const OUString& rFirstName = bCatalogAtStart ? sCatalog : sSchema; + const sal_Int32 nFirstFolderType = bCatalogAtStart ? DatabaseObjectContainer::CATALOG : DatabaseObjectContainer::SCHEMA; + const OUString& rSecondName = bCatalogAtStart ? sSchema : sCatalog; + const sal_Int32 nSecondFolderType = bCatalogAtStart ? DatabaseObjectContainer::SCHEMA : DatabaseObjectContainer::CATALOG; + + if ( !rFirstName.isEmpty() ) + { + SvTreeListEntry* pFolder = GetEntryPosByName( rFirstName, pParentEntry ); + if ( !pFolder ) + pFolder = InsertEntry( rFirstName, pParentEntry, false, TREELIST_APPEND, reinterpret_cast< void* >( nFirstFolderType ) ); + pParentEntry = pFolder; + } + + if ( !rSecondName.isEmpty() ) + { + SvTreeListEntry* pFolder = GetEntryPosByName( rSecondName, pParentEntry ); + if ( !pFolder ) + pFolder = InsertEntry( rSecondName, pParentEntry, false, TREELIST_APPEND, reinterpret_cast< void* >( nSecondFolderType ) ); + pParentEntry = pFolder; + } + + SvTreeListEntry* pRet = nullptr; + if ( !_bCheckName || !GetEntryPosByName( sName, pParentEntry ) ) + { + pRet = InsertEntry( sName, pParentEntry ); + + Image aImage; + m_xImageProvider->getImages( _rTableName, DatabaseObject::TABLE, aImage ); + + SetExpandedEntryBmp( pRet, aImage ); + SetCollapsedEntryBmp( pRet, aImage ); + } + return pRet; +} + +void TableTreeListBox::implAddEntry( + const Reference< XDatabaseMetaData >& _rxMeta, + const OUString& _rTableName + ) +{ + OSL_PRECOND( _rxMeta.is(), "OTableTreeListBox::implAddEntry: invalid meta data!" ); + if ( !_rxMeta.is() ) + return; + + // split the complete name into its components + OUString sCatalog, sSchema, sName; + qualifiedNameComponents( _rxMeta, _rTableName, sCatalog, sSchema, sName, ::dbtools::EComposeRule::InDataManipulation ); + + std::unique_ptr<weld::TreeIter> xParentEntry(getAllObjectsEntry()); + + // if the DB uses catalog at the start of identifiers, then our hierarchy is + // catalog + // +- schema + // +- table + // else it is + // schema + // +- catalog + // +- table + bool bCatalogAtStart = _rxMeta->isCatalogAtStart(); + const OUString& rFirstName = bCatalogAtStart ? sCatalog : sSchema; + const sal_Int32 nFirstFolderType = bCatalogAtStart ? DatabaseObjectContainer::CATALOG : DatabaseObjectContainer::SCHEMA; + const OUString& rSecondName = bCatalogAtStart ? sSchema : sCatalog; + const sal_Int32 nSecondFolderType = bCatalogAtStart ? DatabaseObjectContainer::SCHEMA : DatabaseObjectContainer::CATALOG; + + if ( !rFirstName.isEmpty() ) + { + std::unique_ptr<weld::TreeIter> xFolder(GetEntryPosByName(rFirstName, xParentEntry.get())); + if (!xFolder) + { + xFolder = m_xTreeView->make_iterator(); + OUString sId(OUString::number(nFirstFolderType)); + OUString sImageId = ImageProvider::getFolderImageId(DatabaseObject::TABLE); + m_xTreeView->insert(xParentEntry.get(), -1, nullptr, &sId, nullptr, nullptr, nullptr, false, xFolder.get()); + m_xTreeView->set_image(*xFolder, sImageId, -1); + if (m_bShowToggles) + m_xTreeView->set_toggle(*xFolder, TRISTATE_FALSE, 0); + m_xTreeView->set_text(*xFolder, rFirstName, m_nTextColumn); + } + xParentEntry = std::move(xFolder); + } + + if ( !rSecondName.isEmpty() ) + { + std::unique_ptr<weld::TreeIter> xFolder(GetEntryPosByName(rSecondName, xParentEntry.get())); + if (!xFolder) + { + xFolder = m_xTreeView->make_iterator(); + OUString sId(OUString::number(nSecondFolderType)); + OUString sImageId = ImageProvider::getFolderImageId(DatabaseObject::TABLE); + m_xTreeView->insert(xParentEntry.get(), -1, nullptr, &sId, nullptr, nullptr, nullptr, false, xFolder.get()); + m_xTreeView->set_image(*xFolder, sImageId, -1); + if (m_bShowToggles) + m_xTreeView->set_toggle(*xFolder, TRISTATE_FALSE, 0); + m_xTreeView->set_text(*xFolder, rSecondName, m_nTextColumn); + } + xParentEntry = std::move(xFolder); + } + + std::unique_ptr<weld::TreeIter> xEntry = m_xTreeView->make_iterator(); + m_xTreeView->insert(xParentEntry.get(), -1, nullptr, nullptr, nullptr, nullptr, nullptr, false, xEntry.get()); + + auto xGraphic = m_xImageProvider->getXGraphic(_rTableName, DatabaseObject::TABLE); + if (xGraphic.is()) + m_xTreeView->set_image(*xEntry, xGraphic, -1); + else + { + OUString sImageId(m_xImageProvider->getImageId(_rTableName, DatabaseObject::TABLE)); + m_xTreeView->set_image(*xEntry, sImageId, -1); + } + if (m_bShowToggles) + m_xTreeView->set_toggle(*xEntry, TRISTATE_FALSE, 0); + m_xTreeView->set_text(*xEntry, sName, m_nTextColumn); +} + +NamedDatabaseObject OTableTreeListBox::describeObject( SvTreeListEntry* _pEntry ) +{ + NamedDatabaseObject aObject; + + sal_Int32 nEntryType = reinterpret_cast< sal_IntPtr >( _pEntry->GetUserData() ); + + if ( nEntryType == DatabaseObjectContainer::TABLES ) + { + aObject.Type = DatabaseObjectContainer::TABLES; + } + else if ( ( nEntryType == DatabaseObjectContainer::CATALOG ) + || ( nEntryType == DatabaseObjectContainer::SCHEMA ) + ) + { + // nothing useful to be done + } + else + { + aObject.Type = DatabaseObject::TABLE; + aObject.Name = getQualifiedTableName( _pEntry ); + } + + return aObject; +} + +SvTreeListEntry* OTableTreeListBox::addedTable( const OUString& _rName ) +{ + try + { + Reference< XDatabaseMetaData > xMeta; + if ( impl_getAndAssertMetaData( xMeta ) ) + return implAddEntry( xMeta, _rName ); + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("dbaccess"); + } + return nullptr; +} + +bool OTableTreeListBox::impl_getAndAssertMetaData( Reference< XDatabaseMetaData >& _out_rMetaData ) const +{ + if ( m_xConnection.is() ) + _out_rMetaData = m_xConnection->getMetaData(); + OSL_PRECOND( _out_rMetaData.is(), "OTableTreeListBox::impl_getAndAssertMetaData: invalid current connection!" ); + return _out_rMetaData.is(); +} + +OUString OTableTreeListBox::getQualifiedTableName( SvTreeListEntry* _pEntry ) const +{ + OSL_PRECOND( !isFolderEntry( _pEntry ), "OTableTreeListBox::getQualifiedTableName: folder entries not allowed here!" ); + + try + { + Reference< XDatabaseMetaData > xMeta; + if ( !impl_getAndAssertMetaData( xMeta ) ) + return OUString(); + + OUString sCatalog; + OUString sSchema; + OUString sTable; + + SvTreeListEntry* pSchema = GetParent( _pEntry ); + if ( pSchema ) + { + SvTreeListEntry* pCatalog = GetParent( pSchema ); + if ( pCatalog + || ( xMeta->supportsCatalogsInDataManipulation() + && !xMeta->supportsSchemasInDataManipulation() + ) // here we support catalog but no schema + ) + { + if ( pCatalog == nullptr ) + { + pCatalog = pSchema; + pSchema = nullptr; + } + sCatalog = GetEntryText( pCatalog ); + } + if ( pSchema ) + sSchema = GetEntryText(pSchema); + } + sTable = GetEntryText( _pEntry ); + + return ::dbtools::composeTableName( xMeta, sCatalog, sSchema, sTable, false, ::dbtools::EComposeRule::InDataManipulation ); + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("dbaccess"); + } + return OUString(); +} + +SvTreeListEntry* OTableTreeListBox::getEntryByQualifiedName( const OUString& _rName ) +{ + try + { + Reference< XDatabaseMetaData > xMeta; + if ( !impl_getAndAssertMetaData( xMeta ) ) + return nullptr; + + // split the complete name into its components + OUString sCatalog, sSchema, sName; + qualifiedNameComponents(xMeta, _rName, sCatalog, sSchema, sName,::dbtools::EComposeRule::InDataManipulation); + + SvTreeListEntry* pParent = nullptr; + SvTreeListEntry* pCat = nullptr; + SvTreeListEntry* pSchema = nullptr; + if ( !sCatalog.isEmpty() ) + { + pCat = GetEntryPosByName(sCatalog, pParent); + if ( pCat ) + pParent = pCat; + } + + if ( !sSchema.isEmpty() ) + { + pSchema = GetEntryPosByName(sSchema, pParent); + if ( pSchema ) + pParent = pSchema; + } + + return GetEntryPosByName(sName, pParent); + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("dbaccess"); + } + return nullptr; +} + +void OTableTreeListBox::removedTable( const OUString& _rName ) +{ + try + { + SvTreeListEntry* pEntry = getEntryByQualifiedName( _rName ); + if ( pEntry ) + GetModel()->Remove( pEntry ); + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("dbaccess"); + } +} + +std::unique_ptr<weld::TreeIter> TableTreeListBox::GetEntryPosByName(const OUString& aName, const weld::TreeIter* pStart, const IEntryFilter* _pFilter) const +{ + auto xEntry(m_xTreeView->make_iterator(pStart)); + if (!pStart && !m_xTreeView->get_iter_first(*xEntry)) + return nullptr; + + do + { + if (m_xTreeView->get_text(*xEntry) == aName) + { + if (!_pFilter || _pFilter->includeEntry(reinterpret_cast<void*>(m_xTreeView->get_id(*xEntry).toUInt64()))) + { + // found + return xEntry; + } + } + } while (m_xTreeView->iter_next(*xEntry)); + + return nullptr; +} + +void TableTreeListBox::CheckButtons() +{ + if (!m_bShowToggles) + return; + + auto xEntry(m_xTreeView->make_iterator()); + if (!m_xTreeView->get_iter_first(*xEntry)) + return; + + do + { + implDetermineState(*xEntry); + } while (m_xTreeView->iter_next_sibling(*xEntry)); +} + +TriState TableTreeListBox::implDetermineState(weld::TreeIter& rEntry) +{ + if (!m_bShowToggles) + return TRISTATE_FALSE; + + TriState eState = m_xTreeView->get_toggle(rEntry, 0); + if (!m_xTreeView->iter_has_child(rEntry)) + // nothing to do in this bottom-up routine if there are no children ... + return eState; + + // loop through the children and check their states + sal_uInt16 nCheckedChildren = 0; + sal_uInt16 nChildrenOverall = 0; + + std::unique_ptr<weld::TreeIter> xChild(m_xTreeView->make_iterator(&rEntry)); + bool bChildLoop = m_xTreeView->iter_children(*xChild); + while (bChildLoop) + { + TriState eChildState = implDetermineState(*xChild); + if (eChildState == TRISTATE_INDET) + break; + if (eChildState == TRISTATE_TRUE) + ++nCheckedChildren; + ++nChildrenOverall; + bChildLoop = m_xTreeView->iter_next_sibling(*xChild); + } + + if (bChildLoop) + { + // we did not finish the loop because at least one of the children is in tristate + eState = TRISTATE_INDET; + + // but this means that we did not finish all the siblings of pChildLoop, + // so their checking may be incorrect at the moment + // -> correct this + while (bChildLoop) + { + implDetermineState(*xChild); + bChildLoop = m_xTreeView->iter_next_sibling(*xChild); + } + } + else + { + // none if the children are in tristate + if (nCheckedChildren) + { + // we have at least one child checked + if (nCheckedChildren != nChildrenOverall) + { + // not all children are checked + eState = TRISTATE_INDET; + } + else + { + // all children are checked + eState = TRISTATE_TRUE; + } + } + else + { + // no children are checked + eState = TRISTATE_FALSE; + } + } + + // finally set the entry to the state we just determined + m_xTreeView->set_toggle(rEntry, eState, 0); + + return eState; +} + +} // namespace dbaui + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/control/undosqledit.cxx b/dbaccess/source/ui/control/undosqledit.cxx new file mode 100644 index 000000000..d32774292 --- /dev/null +++ b/dbaccess/source/ui/control/undosqledit.cxx @@ -0,0 +1,34 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <undosqledit.hxx> +#include <sqledit.hxx> + +namespace dbaui +{ +void OSqlEditUndoAct::ToggleText() +{ + OUString strNext = m_pOwner->GetText(); + m_pOwner->SetText(m_strNextText); + m_strNextText = strNext; +} + +} // namespace + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |