diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-15 05:54:39 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-15 05:54:39 +0000 |
commit | 267c6f2ac71f92999e969232431ba04678e7437e (patch) | |
tree | 358c9467650e1d0a1d7227a21dac2e3d08b622b2 /dbaccess/source/ui/control | |
parent | Initial commit. (diff) | |
download | libreoffice-267c6f2ac71f92999e969232431ba04678e7437e.tar.xz libreoffice-267c6f2ac71f92999e969232431ba04678e7437e.zip |
Adding upstream version 4:24.2.0.upstream/4%24.2.0
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'dbaccess/source/ui/control')
-rw-r--r-- | dbaccess/source/ui/control/ColumnControlWindow.cxx | 182 | ||||
-rw-r--r-- | dbaccess/source/ui/control/FieldControls.cxx | 60 | ||||
-rw-r--r-- | dbaccess/source/ui/control/FieldDescControl.cxx | 1385 | ||||
-rw-r--r-- | dbaccess/source/ui/control/RelationControl.cxx | 695 | ||||
-rw-r--r-- | dbaccess/source/ui/control/SqlNameEdit.cxx | 85 | ||||
-rw-r--r-- | dbaccess/source/ui/control/TableGrantCtrl.cxx | 476 | ||||
-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 | 513 | ||||
-rw-r--r-- | dbaccess/source/ui/control/opendoccontrols.cxx | 194 | ||||
-rw-r--r-- | dbaccess/source/ui/control/sqledit.cxx | 515 | ||||
-rw-r--r-- | dbaccess/source/ui/control/tabletree.cxx | 707 | ||||
-rw-r--r-- | dbaccess/source/ui/control/undosqledit.cxx | 34 |
13 files changed, 5004 insertions, 0 deletions
diff --git a/dbaccess/source/ui/control/ColumnControlWindow.cxx b/dbaccess/source/ui/control/ColumnControlWindow.cxx new file mode 100644 index 0000000000..f9f786f22e --- /dev/null +++ b/dbaccess/source/ui/control/ColumnControlWindow.cxx @@ -0,0 +1,182 @@ +/* -*- 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 <o3tl/safeint.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; + +OColumnControlTopLevel::OColumnControlTopLevel(vcl::Window* pParent, + const Reference<XComponentContext>& _rxContext) + : InterimItemWindow(pParent, "dbaccess/ui/colcontrolbox.ui", "ColControlBox") + , m_xControl(new OColumnControlWindow(m_xContainer.get(), _rxContext)) +{ +} + +void OColumnControlTopLevel::dispose() +{ + m_xControl.reset(); + InterimItemWindow::dispose(); +} + +void OColumnControlTopLevel::GetFocus() +{ + m_xControl->GrabFocus(); +} + +// OColumnControlWindow +OColumnControlWindow::OColumnControlWindow(weld::Container* pParent, + const Reference<XComponentContext>& _rxContext) + : OFieldDescControl(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(sal_Int32 /*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 && o3tl::make_unsigned(_nPos) < 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 0000000000..3f3553d56e --- /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, + TranslateId pHelpId, + short nPosition) + : OSQLNameEntry(std::move(xEntry), _rAllowedChars) + , m_nPos(nPosition) +{ + m_strHelpText = DBA_RES(pHelpId); +} + +OPropEditCtrl::OPropEditCtrl(std::unique_ptr<weld::Entry> xEntry, TranslateId 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, TranslateId 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, TranslateId 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 0000000000..f341482ea9 --- /dev/null +++ b/dbaccess/source/ui/control/FieldDescControl.cxx @@ -0,0 +1,1385 @@ +/* -*- 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 <comphelper/diagnose_ex.hxx> +#include <TableDesignHelpBar.hxx> +#include <vcl/svapp.hxx> +#include <FieldDescriptions.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, OTableDesignHelpBar* pHelpBar) + : m_xBuilder(Application::CreateBuilder(pPage, "dbaccess/ui/fielddescpage.ui")) + , m_xContainer(m_xBuilder->weld_container("FieldDescPage")) + , m_pHelp( pHelpBar ) + , m_pLastFocusWindow(nullptr) + , m_pActFocusWindow(nullptr) + , m_nPos(-1) + , aYes(DBA_RES(STR_VALUE_YES)) + , aNo(DBA_RES(STR_VALUE_NO)) + , m_nEditWidth(50) + , pActFieldDescr(nullptr) +{ + if (m_pHelp) + m_pHelp->connect_focus_out(LINK(this, OFieldDescControl, HelpFocusOut)); +} + +OFieldDescControl::~OFieldDescControl() +{ + dispose(); +} + +void OFieldDescControl::dispose() +{ + // 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 ); + m_pHelp = nullptr; + 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(); +} + +OUString OFieldDescControl::BoolStringPersistent(std::u16string_view 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 + struct final + { + OWidgetBase * aggregate; + weld::Widget * text; + } const aggregates[] = { + {m_xRequired.get(), m_xRequiredText.get()} + , {m_xNumType.get(), m_xNumTypeText.get()} + , {m_xAutoIncrement.get(), m_xAutoIncrementText.get()} + , {m_xDefault.get(), m_xDefaultText.get()} + , {m_xTextLen.get(), m_xTextLenText.get()} + , {m_xLength.get(), m_xLengthText.get()} + , {m_xScale.get(), m_xScaleText.get()} + , {m_xColumnName.get(), m_xColumnNameText.get()} + , {m_xType.get(), m_xTypeText.get()} + , {m_xAutoIncrementValue.get(), m_xAutoIncrementValueText.get()}}; + + for (auto const & aggregate: aggregates) + { + if (aggregate.text) + aggregate.text->set_sensitive(!bReadOnly); + if (aggregate.aggregate) + aggregate.aggregate->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::getFromUnoTunnel<SvNumberFormatsSupplierObj>( xSupplier ); + if (!pSupplierImpl) + return; + + SvNumberFormatter* pFormatter = pSupplierImpl->GetNumberFormatter(); + if(!::dbaui::callColumnFormatDialog(m_xContainer.get(),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; + } +} + +void OFieldDescControl::InitializeControl(OPropListBoxCtrl* _pControl,const OUString& _sHelpId,bool _bAddChangeHandler) +{ + if ( _bAddChangeHandler ) + _pControl->GetComboBox().connect_changed(LINK(this,OFieldDescControl,ChangeHdl)); + + InitializeControl(_pControl->GetWidget(), _sHelpId); +} + +void OFieldDescControl::InitializeControl(weld::Widget* pControl,const OUString& _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 = Application::GetDefaultDevice()->LogicToPixel(Size(m_nEditWidth, 0), MapMode(MapUnit::MapAppFont)).Width(); + pControl->set_size_request(nWidthRequest, -1); + } +} + +std::unique_ptr<OPropNumericEditCtrl> OFieldDescControl::CreateNumericControl(const OUString& rId, TranslateId pHelpId, short _nProperty, const OUString& _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; + } +} + +void OFieldDescControl::DisplayData(OFieldDescription* pFieldDescr ) +{ + pActFieldDescr = pFieldDescr; + if(!pFieldDescr) + { + if (m_pHelp) + m_pHelp->SetHelpText( OUString() ); + 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; + return; + } + + TOTypeInfoSP pFieldType(pFieldDescr->getTypeInfo()); + + ActivateAggregate( tpColumnName ); + ActivateAggregate( tpType ); + + OSL_ENSURE(pFieldType,"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(Any(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() && m_pHelp) + m_pHelp->SetHelpText(strHelpText); + + m_pActFocusWindow = &rControl; + + m_aControlFocusIn.Call(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) + { + // tdf#138409 take the control default in the UI Locale format, e.g. 12,34 and return a string + // suitable as the database default, e.g. 12.34 + sDefault = CanonicalizeToControlDefault(pFieldDescr, m_xDefault->get_text()); + } + else if (m_xBoolDefault) + { + sDefault = BoolStringPersistent(m_xBoolDefault->get_active_text()); + } + + if ( !sDefault.isEmpty() ) + pFieldDescr->SetControlDefault(Any(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::GrabFocus() +{ + m_xContainer->grab_focus(); + + // Set the Focus to the Control that has been active last + 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 (m_pHelp && !m_pHelp->HasFocus()) + m_pHelp->SetHelpText( OUString() ); +} + +IMPL_LINK_NOARG(OFieldDescControl, HelpFocusOut, weld::Widget&, void) +{ + m_pHelp->SetHelpText(OUString()); +} + +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::HasChildPathFocus() const +{ + return m_xContainer && m_xContainer->has_child_focus(); +} + +bool OFieldDescControl::isCopyAllowed() +{ + 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() +{ + 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() +{ + bool bAllowed = (m_pActFocusWindow != nullptr) && IsFocusInEditableWidget(); + if ( bAllowed ) + { + TransferableDataHelper aTransferData(TransferableDataHelper::CreateFromClipboard(m_pActFocusWindow->get_clipboard())); + 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 ) + { + try + { + double nValue = 0.0; + sal_uInt32 nFormatKey; + 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; +} + +// tdf#138409 intended to be effectively the reverse of getControlDefault to +// turn a user's possibly 12,34 format into 12.34 format for numerical types +OUString OFieldDescControl::CanonicalizeToControlDefault(const OFieldDescription* pFieldDescr, const OUString& rDefault) const +{ + if (rDefault.isEmpty()) + return rDefault; + + bool bIsNumericalType = false; + switch (pFieldDescr->GetType()) + { + case DataType::TINYINT: + case DataType::SMALLINT: + case DataType::INTEGER: + case DataType::BIGINT: + case DataType::FLOAT: + case DataType::REAL: + case DataType::DOUBLE: + case DataType::NUMERIC: + case DataType::DECIMAL: + bIsNumericalType = true; + break; + } + + if (!bIsNumericalType) + return rDefault; + + try + { + sal_uInt32 nFormatKey; + bool bTextFormat = isTextFormat(pFieldDescr, nFormatKey); + if (bTextFormat) + return rDefault; + double nValue = GetFormatter()->convertStringToNumber(nFormatKey, rDefault); + return OUString::number(nValue); + } + catch(const Exception&) + { + } + + return rDefault; +} + + +/* 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 0000000000..d6e3b3d87f --- /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 <comphelper/diagnose_ex.hxx> +#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; + tools::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, sal_Int32 nRow, sal_uInt16 nCol ) override; + virtual ::svt::CellController* GetController( sal_Int32 nRow, sal_uInt16 nCol ) override; + virtual void PaintCell( OutputDevice& rDev, const tools::Rectangle& rRect, sal_uInt16 nColId ) const override; + virtual bool SeekRow( sal_Int32 nRow ) override; + virtual bool SaveModified() override; + virtual OUString GetCellText( sal_Int32 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(); + tools::Long nOutputWidth = GetOutputSizePixel().Width() - 1; + SetColumnWidth(1, (nOutputWidth / 2)); + SetColumnWidth(2, (nOutputWidth / 2)); + } + + bool ORelationControl::PreNotify(NotifyEvent& rNEvt) + { + if (rNEvt.GetType() == NotifyEventType::LOSEFOCUS && !HasChildPathFocus() && !ControlHasFocus()) + PostUserEvent(LINK(this, ORelationControl, AsynchDeactivate), nullptr, true); + else if (rNEvt.GetType() == NotifyEventType::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 + { + sal_Int32 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() + { + sal_Int32 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( sal_Int32 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*/, sal_Int32 nRow, sal_uInt16 nColumnId ) + { + + OUString 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( sal_Int32 /*nRow*/, sal_uInt16 /*nColumnId*/ ) + { + return new ListBoxCellController( m_pListCell.get() ); + } + + bool ORelationControl::SeekRow( sal_Int32 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/SqlNameEdit.cxx b/dbaccess/source/ui/control/SqlNameEdit.cxx new file mode 100644 index 0000000000..9ac58cfda8 --- /dev/null +++ b/dbaccess/source/ui/control/SqlNameEdit.cxx @@ -0,0 +1,85 @@ +/* -*- 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, std::u16string_view _sAllowedChars) + { + return ( + (_cChar >= 'A' && _cChar <= 'Z') || + _cChar == '_' || + _sAllowedChars.find(_cChar) != std::u16string_view::npos || + (!_bFirstChar && (_cChar >= '0' && _cChar <= '9')) || + (_cChar >= 'a' && _cChar <= 'z') + ); + } + bool OSQLNameChecker::checkString(std::u16string_view _sToCheck, + OUString& _rsCorrected) + { + bool bCorrected = false; + if ( m_bCheck ) + { + sal_Int32 nMatch = 0; + for (size_t i = nMatch; i < _sToCheck.size(); ++i) + { + if ( !isCharOk( _sToCheck[i], i == 0, m_sAllowedChars ) ) + { + _rsCorrected += _sToCheck.substr(nMatch, i - nMatch); + bCorrected = true; + nMatch = i + 1; + } + } + _rsCorrected += _sToCheck.substr( nMatch ); + } + return bCorrected; + } + + namespace + { + void checkName(OSQLNameChecker& rChecker, weld::Entry& rEntry) + { + OUString sCorrected; + if (rChecker.checkString(rEntry.get_text(), sCorrected)) + { + int nStartPos, nEndPos; + rEntry.get_selection_bounds(nStartPos, nEndPos); + int nMin = std::min(nStartPos, nEndPos); + rEntry.set_text(sCorrected); + rEntry.select_region(nMin, nMin); + + rEntry.save_value(); + } + } + } + + IMPL_LINK(OSQLNameEditControl, ModifyHdl, weld::Entry&, rEntry, void) + { + checkName(*this, rEntry); + m_ChainChangedHdl.Call(rEntry); + } + + IMPL_LINK(OSQLNameEntry, ModifyHdl, weld::Entry&, rEntry, void) + { + checkName(*this, rEntry); + } +} + +/* 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 0000000000..607c019972 --- /dev/null +++ b/dbaccess/source/ui/control/TableGrantCtrl.cxx @@ -0,0 +1,476 @@ +/* -*- 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/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->EnableTriState(false); + + m_pEdit = VclPtr<EditControl>::Create(&GetDataWindow()); + weld::Entry& rEntry = m_pEdit->get_widget(); + rEntry.set_editable(false); + rEntry.set_sensitive(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() == NotifyEventType::LOSEFOCUS) + if (!HasChildPathFocus()) + { + if (m_nDeactivateEvent) + Application::RemoveUserEvent(m_nDeactivateEvent); + m_nDeactivateEvent = Application::PostUserEvent(LINK(this, OTableGrantControl, AsynchDeactivate), nullptr, true); + } + if (rNEvt.GetType() == NotifyEventType::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 +{ + sal_Int32 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); +} + +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: + if (m_pCheckCell->GetBox().get_active()) + xAuth->grantPrivileges(sTableName,PrivilegeObject::TABLE,Privilege::INSERT); + else + xAuth->revokePrivileges(sTableName,PrivilegeObject::TABLE,Privilege::INSERT); + break; + case COL_DELETE: + if (m_pCheckCell->GetBox().get_active()) + xAuth->grantPrivileges(sTableName,PrivilegeObject::TABLE,Privilege::DELETE); + else + xAuth->revokePrivileges(sTableName,PrivilegeObject::TABLE,Privilege::DELETE); + break; + case COL_UPDATE: + if (m_pCheckCell->GetBox().get_active()) + xAuth->grantPrivileges(sTableName,PrivilegeObject::TABLE,Privilege::UPDATE); + else + xAuth->revokePrivileges(sTableName,PrivilegeObject::TABLE,Privilege::UPDATE); + break; + case COL_ALTER: + if (m_pCheckCell->GetBox().get_active()) + xAuth->grantPrivileges(sTableName,PrivilegeObject::TABLE,Privilege::ALTER); + else + xAuth->revokePrivileges(sTableName,PrivilegeObject::TABLE,Privilege::ALTER); + break; + case COL_SELECT: + if (m_pCheckCell->GetBox().get_active()) + xAuth->grantPrivileges(sTableName,PrivilegeObject::TABLE,Privilege::SELECT); + else + xAuth->revokePrivileges(sTableName,PrivilegeObject::TABLE,Privilege::SELECT); + break; + case COL_REF: + if (m_pCheckCell->GetBox().get_active()) + xAuth->grantPrivileges(sTableName,PrivilegeObject::TABLE,Privilege::REFERENCE); + else + xAuth->revokePrivileges(sTableName,PrivilegeObject::TABLE,Privilege::REFERENCE); + break; + case COL_DROP: + if (m_pCheckCell->GetBox().get_active()) + xAuth->grantPrivileges(sTableName,PrivilegeObject::TABLE,Privilege::DROP); + else + xAuth->revokePrivileges(sTableName,PrivilegeObject::TABLE,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()->SaveValue(); + if(!bErg) + UpdateTables(); + + return bErg; +} + +OUString OTableGrantControl::GetCellText( sal_Int32 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*/, sal_Int32 nRow, sal_uInt16 nColumnId ) +{ + OUString sTablename = m_aTableNames[nRow]; + // special case for tablename + if (nColumnId == COL_TABLE_NAME) + m_pEdit->get_widget().set_text(sTablename); + else + { + // get the privileges from the user + TTablePrivilegeMap::const_iterator aFind = findPrivilege(nRow); + m_pCheckCell->GetBox().set_active(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( sal_Int32 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( sal_Int32 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/charsetlistbox.cxx b/dbaccess/source/ui/control/charsetlistbox.cxx new file mode 100644 index 0000000000..f9866905c3 --- /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( std::u16string_view _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, TypedWhichId<SfxStringItem> _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 0000000000..9cccde370f --- /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 0000000000..be900d650f --- /dev/null +++ b/dbaccess/source/ui/control/dbtreelistbox.cxx @@ -0,0 +1,513 @@ +/* -*- 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 <dbexchange.hxx> +#include <callbacks.hxx> + +#include <com/sun/star/awt/PopupMenuDirection.hpp> +#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/frame/XPopupMenuController.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 <dbaccess/IController.hxx> +#include <framework/actiontriggerhelper.hxx> +#include <toolkit/awt/vclxmenu.hxx> +#include <toolkit/helper/vclunohelper.hxx> +#include <svx/dbaobjectex.hxx> +#include <utility> +#include <vcl/commandevent.hxx> +#include <vcl/event.hxx> +#include <vcl/svapp.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; + +InterimDBTreeListBox::InterimDBTreeListBox(vcl::Window* pParent) + : InterimItemWindow(pParent, "dbaccess/ui/dbtreelist.ui", "DBTreeList") + , TreeListBox(m_xBuilder->weld_tree_view("treeview"), true) + , m_xStatusBar(m_xBuilder->weld_label("statusbar")) +{ + InitControlBase(&GetWidget()); +} + +InterimDBTreeListBox::~InterimDBTreeListBox() +{ + disposeOnce(); +} + +void InterimDBTreeListBox::dispose() +{ + implStopSelectionTimer(); + m_xStatusBar.reset(); + m_xTreeView.reset(); + InterimItemWindow::dispose(); +} + +bool InterimDBTreeListBox::DoChildKeyInput(const KeyEvent& rKEvt) +{ + return ChildKeyInput(rKEvt); +} + +TreeListBoxDropTarget::TreeListBoxDropTarget(TreeListBox& rTreeView) + : DropTargetHelper(rTreeView.GetWidget().get_drop_target()) + , m_rTreeView(rTreeView) +{ +} + +sal_Int8 TreeListBoxDropTarget::AcceptDrop(const AcceptDropEvent& rEvt) +{ + sal_Int8 nAccept = m_rTreeView.AcceptDrop(rEvt); + + if (nAccept != DND_ACTION_NONE) + { + // to enable the autoscroll when we're close to the edges + weld::TreeView& rWidget = m_rTreeView.GetWidget(); + rWidget.get_dest_row_at_pos(rEvt.maPosPixel, nullptr, true); + } + + return nAccept; +} + +sal_Int8 TreeListBoxDropTarget::ExecuteDrop(const ExecuteDropEvent& rEvt) +{ + return m_rTreeView.ExecuteDrop(rEvt); +} + +TreeListBox::TreeListBox(std::unique_ptr<weld::TreeView> xTreeView, bool bSQLType) + : m_xTreeView(std::move(xTreeView)) + , m_aDropTargetHelper(*this) + , m_pActionListener(nullptr) + , m_pContextMenuProvider(nullptr) + , m_aTimer("dbaccess TreeListBox m_aTimer") +{ + m_xTreeView->connect_key_press(LINK(this, TreeListBox, KeyInputHdl)); + m_xTreeView->connect_changed(LINK(this, TreeListBox, SelectHdl)); + m_xTreeView->connect_query_tooltip(LINK(this, TreeListBox, QueryTooltipHdl)); + m_xTreeView->connect_popup_menu(LINK(this, TreeListBox, CommandHdl)); + + if (bSQLType) + m_xHelper.set(new ODataClipboard); + else + m_xHelper.set(new svx::OComponentTransferable); + m_xTreeView->enable_drag_source(m_xHelper, DND_ACTION_COPY); + m_xTreeView->connect_drag_begin(LINK(this, TreeListBox, DragBeginHdl)); + + m_aTimer.SetTimeout(900); + m_aTimer.SetInvokeHandler(LINK(this, TreeListBox, OnTimeOut)); +} + +bool TreeListBox::DoChildKeyInput(const KeyEvent& /*rKEvt*/) +{ + // nothing by default + return false; +} + +IMPL_LINK(TreeListBox, KeyInputHdl, const KeyEvent&, rKEvt, bool) +{ + KeyFuncType eFunc = rKEvt.GetKeyCode().GetFunction(); + bool bHandled = false; + + switch (eFunc) + { + case KeyFuncType::COPY: + bHandled = m_aCopyHandler.IsSet() && !m_xTreeView->get_selected(nullptr); + if (bHandled) + m_aCopyHandler.Call(nullptr); + break; + case KeyFuncType::PASTE: + bHandled = m_aPasteHandler.IsSet() && !m_xTreeView->get_selected(nullptr); + if (bHandled) + m_aPasteHandler.Call(nullptr); + break; + case KeyFuncType::DELETE: + bHandled = m_aDeleteHandler.IsSet() && !m_xTreeView->get_selected(nullptr); + if (bHandled) + m_aDeleteHandler.Call(nullptr); + break; + default: + break; + } + + return bHandled || DoChildKeyInput(rKEvt); +} + +void TreeListBox::implStopSelectionTimer() +{ + if ( m_aTimer.IsActive() ) + m_aTimer.Stop(); +} + +void TreeListBox::implStartSelectionTimer() +{ + implStopSelectionTimer(); + m_aTimer.Start(); +} + +IMPL_LINK_NOARG(TreeListBox, SelectHdl, weld::TreeView&, void) +{ + implStartSelectionTimer(); +} + +TreeListBox::~TreeListBox() +{ +} + +std::unique_ptr<weld::TreeIter> TreeListBox::GetEntryPosByName(std::u16string_view aName, const weld::TreeIter* pStart, const IEntryFilter* _pFilter) const +{ + auto xEntry(m_xTreeView->make_iterator(pStart)); + if (pStart) + { + if (!m_xTreeView->iter_children(*xEntry)) + return nullptr; + } + else + { + if (!m_xTreeView->get_iter_first(*xEntry)) + return nullptr; + } + + do + { + if (m_xTreeView->get_text(*xEntry) == aName) + { + if (!_pFilter || _pFilter->includeEntry(weld::fromId<void*>(m_xTreeView->get_id(*xEntry)))) + { + // found + return xEntry; + } + } + } while (m_xTreeView->iter_next_sibling(*xEntry)); + + return nullptr; +} + +IMPL_LINK(TreeListBox, DragBeginHdl, bool&, rUnsetDragIcon, bool) +{ + rUnsetDragIcon = false; + + if (m_pActionListener) + { + m_xDragedEntry = m_xTreeView->make_iterator(); + if (!m_xTreeView->get_selected(m_xDragedEntry.get())) + m_xDragedEntry.reset(); + if (m_xDragedEntry && m_pActionListener->requestDrag(*m_xDragedEntry)) + { + // if the (asynchronous) drag started, stop the selection timer + implStopSelectionTimer(); + return false; + } + } + + return true; +} + +sal_Int8 TreeListBox::AcceptDrop(const AcceptDropEvent& rEvt) +{ + sal_Int8 nDropOption = DND_ACTION_NONE; + if ( m_pActionListener ) + { + ::Point aDropPos = rEvt.maPosPixel; + std::unique_ptr<weld::TreeIter> xDropTarget(m_xTreeView->make_iterator()); + if (!m_xTreeView->get_dest_row_at_pos(aDropPos, xDropTarget.get(), true)) + xDropTarget.reset(); + + // check if drag is on child entry, which is not allowed + std::unique_ptr<weld::TreeIter> xParent; + if (rEvt.mnAction & DND_ACTION_MOVE) + { + if (!m_xDragedEntry) // no entry to move + return m_pActionListener->queryDrop(rEvt, m_aDropTargetHelper.GetDataFlavorExVector()); + + if (xDropTarget) + { + xParent = m_xTreeView->make_iterator(xDropTarget.get()); + if (!m_xTreeView->iter_parent(*xParent)) + xParent.reset(); + } + while (xParent && m_xTreeView->iter_compare(*xParent, *m_xDragedEntry) != 0) + { + if (!m_xTreeView->iter_parent(*xParent)) + xParent.reset(); + } + } + + if (!xParent) + { + nDropOption = m_pActionListener->queryDrop(rEvt, m_aDropTargetHelper.GetDataFlavorExVector()); + // check if move is allowed + if ( nDropOption & DND_ACTION_MOVE ) + { + if (!m_xDragedEntry || !xDropTarget || + m_xTreeView->iter_compare(*m_xDragedEntry, *xDropTarget) == 0 || + GetEntryPosByName(m_xTreeView->get_text(*m_xDragedEntry), xDropTarget.get())) + { + nDropOption = nDropOption & ~DND_ACTION_MOVE;//DND_ACTION_NONE; + } + } + } + } + + return nDropOption; +} + +sal_Int8 TreeListBox::ExecuteDrop(const ExecuteDropEvent& rEvt) +{ + if (m_pActionListener) + m_pActionListener->executeDrop(rEvt); + m_xTreeView->unset_drag_dest_row(); + return DND_ACTION_NONE; +} + +IMPL_LINK(TreeListBox, QueryTooltipHdl, const weld::TreeIter&, rIter, OUString) +{ + OUString sQuickHelpText; + if (m_pActionListener && + m_pActionListener->requestQuickHelp(weld::fromId<void*>(m_xTreeView->get_id(rIter)), sQuickHelpText)) + { + return sQuickHelpText; + } + return m_xTreeView->get_tooltip_text(); +} + +namespace +{ + // SelectionSupplier + typedef ::cppu::WeakImplHelper< XSelectionSupplier + > SelectionSupplier_Base; + class SelectionSupplier : public SelectionSupplier_Base + { + public: + explicit SelectionSupplier( Any _aSelection ) + :m_aSelection(std::move( _aSelection )) + { + } + + 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 + } +} + +IMPL_LINK(TreeListBox, CommandHdl, const CommandEvent&, rCEvt, bool) +{ + if (rCEvt.GetCommand() != CommandEventId::ContextMenu) + return false; + + ::Point aPos = rCEvt.GetMousePosPixel(); + + std::unique_ptr<weld::TreeIter> xIter(m_xTreeView->make_iterator()); + if (m_xTreeView->get_dest_row_at_pos(aPos, xIter.get(), false) && !m_xTreeView->is_selected(*xIter)) + { + m_xTreeView->unselect_all(); + m_xTreeView->set_cursor(*xIter); + m_xTreeView->select(*xIter); + SelectHdl(*m_xTreeView); + } + + if (!m_pContextMenuProvider) + return false; + + OUString aResourceName(m_pContextMenuProvider->getContextMenuResourceName()); + if (aResourceName.isEmpty()) + return false; + + css::uno::Sequence< css::uno::Any > aArgs{ + css::uno::Any(comphelper::makePropertyValue( "Value", aResourceName )), + css::uno::Any(comphelper::makePropertyValue( "Frame", m_pContextMenuProvider->getCommandController().getXController()->getFrame() )), + css::uno::Any(comphelper::makePropertyValue( "IsContextMenu", true )) + }; + + css::uno::Reference< css::uno::XComponentContext > xContext = comphelper::getProcessComponentContext(); + css::uno::Reference<css::frame::XPopupMenuController> xMenuController + (xContext->getServiceManager()->createInstanceWithArgumentsAndContext( + "com.sun.star.comp.framework.ResourceMenuController", aArgs, xContext), css::uno::UNO_QUERY); + + if (!xMenuController.is()) + return false; + + VclPtr<vcl::Window> xMenuParent = m_pContextMenuProvider->getMenuParent(); + + css::uno::Reference< css::awt::XWindow> xSourceWindow = VCLUnoHelper::GetInterface(xMenuParent); + + rtl::Reference xPopupMenu( new VCLXPopupMenu ); + xMenuController->setPopupMenu( xPopupMenu ); + + // allow context menu interception + ::comphelper::OInterfaceContainerHelper2* pInterceptors = m_pContextMenuProvider->getContextMenuInterceptors(); + if (pInterceptors && pInterceptors->getLength()) + { + OUString aMenuIdentifier( "private:resource/popupmenu/" + aResourceName ); + + ContextMenuExecuteEvent aEvent; + aEvent.SourceWindow = xSourceWindow; + aEvent.ExecutePosition.X = -1; + aEvent.ExecutePosition.Y = -1; + aEvent.ActionTriggerContainer = ::framework::ActionTriggerHelper::CreateActionTriggerContainerFromMenu( + xPopupMenu, &aMenuIdentifier ); + aEvent.Selection = new SelectionSupplier(m_pContextMenuProvider->getCurrentSelection(*m_xTreeView)); + + ::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 false; + + 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 ) + { + xPopupMenu->clear(); + ::framework::ActionTriggerHelper::CreateMenuFromActionTriggerContainer( + xPopupMenu, aEvent.ActionTriggerContainer ); + aEvent.ActionTriggerContainer.clear(); + } + } + + // adjust pos relative to m_xTreeView to relative to xMenuParent + m_pContextMenuProvider->adjustMenuPosition(*m_xTreeView, aPos); + + // do action for selected entry in popup menu + css::uno::Reference<css::awt::XWindowPeer> xParent(xSourceWindow, css::uno::UNO_QUERY); + xPopupMenu->execute(xParent, css::awt::Rectangle(aPos.X(), aPos.Y(), 1, 1), css::awt::PopupMenuDirection::EXECUTE_DOWN); + + css::uno::Reference<css::lang::XComponent> xComponent(xMenuController, css::uno::UNO_QUERY); + if (xComponent.is()) + xComponent->dispose(); + xMenuController.clear(); + + return true; +} + +IMPL_LINK_NOARG(TreeListBox, OnTimeOut, Timer*, void) +{ + implStopSelectionTimer(); + + m_aSelChangeHdl.Call( nullptr ); +} + +std::unique_ptr<weld::TreeIter> TreeListBox::GetRootLevelParent(const weld::TreeIter* pEntry) const +{ + if (!pEntry) + return nullptr; + std::unique_ptr<weld::TreeIter> xEntry(m_xTreeView->make_iterator(pEntry)); + while (m_xTreeView->get_iter_depth(*xEntry)) + m_xTreeView->iter_parent(*xEntry); + return xEntry; +} + +DBTreeViewBase::DBTreeViewBase(weld::Container* pContainer) + : m_xBuilder(Application::CreateBuilder(pContainer, "dbaccess/ui/dbtreelist.ui")) + , m_xContainer(m_xBuilder->weld_container("DBTreeList")) +{ +} + +DBTreeViewBase::~DBTreeViewBase() +{ +} + +DBTreeView::DBTreeView(weld::Container* pContainer, bool bSQLType) + : DBTreeViewBase(pContainer) +{ + m_xTreeListBox.reset(new TreeListBox(m_xBuilder->weld_tree_view("treeview"), bSQLType)); +} + +} // namespace dbaui + +/* 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 0000000000..2fb86bdca6 --- /dev/null +++ b/dbaccess/source/ui/control/opendoccontrols.cxx @@ -0,0 +1,194 @@ +/* -*- 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!" ); + + std::vector< SvtHistoryOptions::HistoryItem > aHistory = SvtHistoryOptions::GetList( EHistoryType::PickList ); + Reference< XNameAccess > xFilterFactory; + xFilterFactory.set(::comphelper::getProcessServiceFactory()->createInstance( + "com.sun.star.document.FilterFactory" ), css::uno::UNO_QUERY); + + for ( const SvtHistoryOptions::HistoryItem& rHistoryItem : aHistory ) + { + try + { + // Get the current history item's properties. + OUString sURL = rHistoryItem.sURL; + OUString sFilter = rHistoryItem.sFilter; + OUString sTitle = rHistoryItem.sTitle; + OUString sPassword = rHistoryItem.sPassword; + + // If the entry is a Base 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(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; + } + + const 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 0000000000..5997e5b80e --- /dev/null +++ b/dbaccess/source/ui/control/sqledit.cxx @@ -0,0 +1,515 @@ +/* -*- 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 <editeng/eeitem.hxx> +#include <editeng/colritem.hxx> +#include <editeng/fhgtitem.hxx> +#include <editeng/fontitem.hxx> +#include <editeng/wghtitem.hxx> +#include <sqledit.hxx> +#include <cppuhelper/implbase.hxx> +#include <i18nlangtag/languagetag.hxx> +#include <svl/itempool.hxx> +#include <svl/itemset.hxx> +#include <vcl/commandevent.hxx> +#include <vcl/event.hxx> +#include <vcl/settings.hxx> +#include <vcl/specialchars.hxx> +#include <vcl/svapp.hxx> + +using namespace dbaui; + +class SQLEditView::ChangesListener: + public cppu::WeakImplHelper< css::beans::XPropertiesChangeListener > +{ +public: + explicit ChangesListener(SQLEditView& editor): editor_(editor) {} + +private: + virtual ~ChangesListener() override {} + + virtual void SAL_CALL disposing(css::lang::EventObject const &) override + { + std::unique_lock 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(); + } + + SQLEditView& editor_; +}; + +SQLEditView::SQLEditView(std::unique_ptr<weld::ScrolledWindow> xScrolledWindow) + : m_xScrolledWindow(std::move(xScrolledWindow)) + , m_aUpdateDataTimer("dbaccess SQLEditView m_aUpdateDataTimer") + , m_aHighlighter(HighlighterLanguage::SQL) + , m_bInUpdate(false) + , m_bDisableInternalUndo(false) +{ + m_xScrolledWindow->connect_vadjustment_changed(LINK(this, SQLEditView, ScrollHdl)); +} + +void SQLEditView::DisableInternalUndo() +{ + GetEditEngine()->EnableUndo(false); + m_bDisableInternalUndo = true; +} + +void SQLEditView::SetItemPoolFont(SfxItemPool* pItemPool) +{ + 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::OnlyOne)); + sFontName = aTmpFont.GetFamilyName(); + } + + Size aFontSize(0, officecfg::Office::Common::Font::SourceViewFont::FontHeight::get()); + vcl::Font aAppFont(sFontName, aFontSize); + + pItemPool->SetPoolDefaultItem(SvxFontItem(aAppFont.GetFamilyType(), aAppFont.GetFamilyName(), + "", PITCH_DONTKNOW, RTL_TEXTENCODING_DONTKNOW, + EE_CHAR_FONTINFO)); + pItemPool->SetPoolDefaultItem(SvxFontItem(aAppFont.GetFamilyType(), aAppFont.GetFamilyName(), + "", PITCH_DONTKNOW, RTL_TEXTENCODING_DONTKNOW, + EE_CHAR_FONTINFO_CJK)); + pItemPool->SetPoolDefaultItem(SvxFontItem(aAppFont.GetFamilyType(), aAppFont.GetFamilyName(), + "", PITCH_DONTKNOW, RTL_TEXTENCODING_DONTKNOW, + EE_CHAR_FONTINFO_CTL)); + + pItemPool->SetPoolDefaultItem( + SvxFontHeightItem(aAppFont.GetFontHeight() * 20, 100, EE_CHAR_FONTHEIGHT)); + pItemPool->SetPoolDefaultItem( + SvxFontHeightItem(aAppFont.GetFontHeight() * 20, 100, EE_CHAR_FONTHEIGHT_CJK)); + pItemPool->SetPoolDefaultItem( + SvxFontHeightItem(aAppFont.GetFontHeight() * 20, 100, EE_CHAR_FONTHEIGHT_CTL)); +} + +void SQLEditView::makeEditEngine() +{ + assert(!m_pItemPool); + m_pItemPool = EditEngine::CreatePool(); + SetItemPoolFont(m_pItemPool.get()); + m_xEditEngine.reset(new EditEngine(m_pItemPool.get())); +} + +void SQLEditView::SetDrawingArea(weld::DrawingArea* pDrawingArea) +{ + WeldEditView::SetDrawingArea(pDrawingArea); + + EditEngine& rEditEngine = *GetEditEngine(); + + rEditEngine.SetDefaultHorizontalTextDirection(EEHorizontalTextDirection::L2R); + rEditEngine.SetModifyHdl(LINK(this, SQLEditView, ModifyHdl)); + rEditEngine.SetStatusEventHdl(LINK(this, SQLEditView, EditStatusHdl)); + + m_aUpdateDataTimer.SetTimeout(150); + m_aUpdateDataTimer.SetInvokeHandler(LINK(this, SQLEditView, ImplUpdateDataHdl)); + + 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); + { + std::unique_lock g(m_mutex); + m_notifier = n; + } + css::uno::Sequence< OUString > s { "FontHeight", "FontName" }; + n->addPropertiesChangeListener(s, m_listener); + m_ColorConfig.AddListener(this); +} + +SQLEditView::~SQLEditView() +{ + css::uno::Reference< css::beans::XMultiPropertySet > n; + { + std::unique_lock g(m_mutex); + n = m_notifier; + } + if (n.is()) { + n->removePropertiesChangeListener(m_listener); + } + m_ColorConfig.RemoveListener(this); +} + +void SQLEditView::SetTextAndUpdate(const OUString& rNewText) +{ + SetText(rNewText); + UpdateData(); +} + +IMPL_LINK_NOARG(SQLEditView, ModifyHdl, LinkParamNone*, void) +{ + if (m_bInUpdate) + return; + m_aUpdateDataTimer.Start(); +} + +IMPL_LINK_NOARG(SQLEditView, ImplUpdateDataHdl, Timer*, void) +{ + UpdateData(); +} + +Color SQLEditView::GetColorValue(TokenType aToken) +{ + return GetSyntaxHighlightColor(m_aColorConfig, m_aHighlighter.GetLanguage(), aToken); +} + +void SQLEditView::UpdateData() +{ + m_bInUpdate = true; + EditEngine& rEditEngine = *GetEditEngine(); + + bool bModified = rEditEngine.IsModified(); + bool bUndoEnabled = rEditEngine.IsUndoEnabled(); + rEditEngine.EnableUndo(false); + + // syntax highlighting + for (sal_Int32 nLine=0; nLine < rEditEngine.GetParagraphCount(); ++nLine) + { + OUString aLine( rEditEngine.GetText( nLine ) ); + + ESelection aAllLine(nLine, 0, nLine, EE_TEXTPOS_ALL); + rEditEngine.RemoveAttribs(aAllLine, false, EE_CHAR_COLOR); + rEditEngine.RemoveAttribs(aAllLine, false, EE_CHAR_WEIGHT); + rEditEngine.RemoveAttribs(aAllLine, false, EE_CHAR_WEIGHT_CJK); + rEditEngine.RemoveAttribs(aAllLine, false, EE_CHAR_WEIGHT_CTL); + + std::vector<HighlightPortion> aPortions; + m_aHighlighter.getHighlightPortions( aLine, aPortions ); + for (auto const& portion : aPortions) + { + SfxItemSet aSet(rEditEngine.GetEmptyItemSet()); + aSet.Put(SvxColorItem(GetColorValue(portion.tokenType), EE_CHAR_COLOR)); + rEditEngine.QuickSetAttribs(aSet, ESelection(nLine, portion.nBegin, nLine, portion.nEnd)); + } + } + + rEditEngine.ClearModifyFlag(); + + m_bInUpdate = false; + + rEditEngine.EnableUndo(bUndoEnabled); + + if (bModified) + m_aModifyLink.Call(nullptr); + + Invalidate(); +} + +void SQLEditView::DoBracketHilight(sal_uInt16 nKey) +{ + ESelection aCurrentPos = m_xEditView->GetSelection(); + sal_Int32 nStartPos = aCurrentPos.nStartPos; + const sal_uInt32 nStartPara = aCurrentPos.nStartPara; + sal_uInt16 nCount = 0; + int nChar = -1; + + switch (nKey) + { + case '\'': // no break + case '"': + { + nChar = nKey; + break; + } + case '}' : + { + nChar = '{'; + break; + } + case ')': + { + nChar = '('; + break; + } + case ']': + { + nChar = '['; + break; + } + } + + if (nChar == -1) + return; + + bool bUndoEnabled = m_xEditEngine->IsUndoEnabled(); + m_xEditEngine->EnableUndo(false); + + sal_uInt32 nPara = nStartPara; + do + { + if (nPara == nStartPara && nStartPos == 0) + continue; + + OUString aLine( m_xEditEngine->GetText( nPara ) ); + + if (aLine.isEmpty()) + continue; + + for (sal_Int32 i = (nPara==nStartPara) ? nStartPos-1 : aLine.getLength()-1; i>0; --i) + { + if (aLine[i] == nChar) + { + if (!nCount) + { + SfxItemSet aSet(m_xEditEngine->GetEmptyItemSet()); + aSet.Put(SvxColorItem(Color(0,0,0), EE_CHAR_COLOR)); + aSet.Put(SvxWeightItem(WEIGHT_ULTRABOLD, EE_CHAR_WEIGHT)); + aSet.Put(SvxWeightItem(WEIGHT_ULTRABOLD, EE_CHAR_WEIGHT_CJK)); + aSet.Put(SvxWeightItem(WEIGHT_ULTRABOLD, EE_CHAR_WEIGHT_CTL)); + + m_xEditEngine->QuickSetAttribs(aSet, ESelection(nPara, i, nPara, i + 1)); + m_xEditEngine->QuickSetAttribs(aSet, ESelection(nStartPara, nStartPos, nStartPara, nStartPos)); + return; + } + else + --nCount; + } + if (aLine[i] == nKey) + ++nCount; + } + } while (nPara--); + + m_xEditEngine->EnableUndo(bUndoEnabled); +} + +Color SQLEditView::GetSyntaxHighlightColor(const svtools::ColorConfig& rColorConfig, HighlighterLanguage eLanguage, TokenType aToken) +{ + Color aColor; + switch (eLanguage) + { + case HighlighterLanguage::SQL: + { + switch (aToken) + { + case TokenType::Identifier: aColor = rColorConfig.GetColorValue(svtools::SQLIDENTIFIER).nColor; break; + case TokenType::Number: aColor = rColorConfig.GetColorValue(svtools::SQLNUMBER).nColor; break; + case TokenType::String: aColor = rColorConfig.GetColorValue(svtools::SQLSTRING).nColor; break; + case TokenType::Operator: aColor = rColorConfig.GetColorValue(svtools::SQLOPERATOR).nColor; break; + case TokenType::Keywords: aColor = rColorConfig.GetColorValue(svtools::SQLKEYWORD).nColor; break; + case TokenType::Parameter: aColor = rColorConfig.GetColorValue(svtools::SQLPARAMETER).nColor; break; + case TokenType::Comment: aColor = rColorConfig.GetColorValue(svtools::SQLCOMMENT).nColor; break; + default: aColor = Color(0,0,0); + } + break; + } + case HighlighterLanguage::Basic: + { + switch (aToken) + { + case TokenType::Identifier: aColor = Color(255,0,0); break; + case TokenType::Comment: aColor = Color(0,0,45); break; + case TokenType::Number: aColor = Color(204,102,204); break; + case TokenType::String: aColor = Color(0,255,45); break; + case TokenType::Operator: aColor = Color(0,0,100); break; + case TokenType::Keywords: aColor = Color(0,0,255); break; + case TokenType::Error : aColor = Color(0,255,255); break; + default: aColor = Color(0,0,0); + } + break; + } + default: aColor = Color(0,0,0); + + } + return aColor; +} + +bool SQLEditView::KeyInput(const KeyEvent& rKEvt) +{ + DoBracketHilight(rKEvt.GetCharCode()); + + if (m_bDisableInternalUndo) + { + KeyFuncType eFunc = rKEvt.GetKeyCode().GetFunction(); + if (eFunc == KeyFuncType::UNDO || eFunc == KeyFuncType::REDO) + return false; + } + + return WeldEditView::KeyInput(rKEvt); +} + +bool SQLEditView::Command(const CommandEvent& rCEvt) +{ + if (rCEvt.GetCommand() == CommandEventId::ContextMenu) + { + ::tools::Rectangle aRect(rCEvt.GetMousePosPixel(), Size(1, 1)); + weld::Widget* pPopupParent = GetDrawingArea(); + std::unique_ptr<weld::Builder> xBuilder(Application::CreateBuilder(pPopupParent, "vcl/ui/editmenu.ui")); + std::unique_ptr<weld::Menu> xContextMenu(xBuilder->weld_menu("menu")); + + bool bEnableCut = true; + bool bEnableCopy = true; + bool bEnableDelete = true; + bool bEnablePaste = true; + bool bEnableSpecialChar = true; + + EditView* pEditView = GetEditView(); + + if (!pEditView->HasSelection()) + { + bEnableCut = false; + bEnableCopy = false; + bEnableDelete = false; + } + + if (pEditView->IsReadOnly()) + { + bEnableCut = false; + bEnablePaste = false; + bEnableDelete = false; + bEnableSpecialChar = false; + } + + xContextMenu->set_sensitive("cut", bEnableCut); + xContextMenu->set_sensitive("copy", bEnableCopy); + xContextMenu->set_sensitive("delete", bEnableDelete); + xContextMenu->set_sensitive("paste", bEnablePaste); + xContextMenu->set_sensitive("specialchar", bEnableSpecialChar); + xContextMenu->set_visible("undo", false); + xContextMenu->set_visible("specialchar", vcl::GetGetSpecialCharsFunction() != nullptr); + + OUString sCommand = xContextMenu->popup_at_rect(pPopupParent, aRect); + + if (sCommand == "cut") + pEditView->Cut(); + else if (sCommand == "copy") + pEditView->Copy(); + else if (sCommand == "paste") + pEditView->Paste(); + else if (sCommand == "delete") + pEditView->DeleteSelected(); + else if (sCommand == "selectall") + { + sal_Int32 nPar = m_xEditEngine->GetParagraphCount(); + if (nPar) + { + sal_Int32 nLen = m_xEditEngine->GetTextLen(nPar - 1); + pEditView->SetSelection(ESelection(0, 0, nPar - 1, nLen)); + } + } + else if (sCommand == "specialchar") + { + OUString aChars = vcl::GetGetSpecialCharsFunction()(pPopupParent, m_xEditEngine->GetStandardFont(0)); + if (!aChars.isEmpty()) + { + pEditView->InsertText(aChars); + } + } + + return true; + } + return WeldEditView::Command(rCEvt); +} + +void SQLEditView::EditViewScrollStateChange() +{ + // editengine height has changed or editview scroll pos has changed + SetScrollBarRange(); +} + +void SQLEditView::SetScrollBarRange() +{ + EditEngine *pEditEngine = GetEditEngine(); + if (!pEditEngine) + return; + if (!m_xScrolledWindow) + return; + EditView* pEditView = GetEditView(); + if (!pEditView) + return; + + int nVUpper = pEditEngine->GetTextHeight(); + int nVCurrentDocPos = pEditView->GetVisArea().Top(); + const Size aOut(pEditView->GetOutputArea().GetSize()); + int nVStepIncrement = aOut.Height() * 2 / 10; + int nVPageIncrement = aOut.Height() * 8 / 10; + int nVPageSize = aOut.Height(); + + /* limit the page size to below nUpper because gtk's gtk_scrolled_window_start_deceleration has + effectively... + + lower = gtk_adjustment_get_lower + upper = gtk_adjustment_get_upper - gtk_adjustment_get_page_size + + and requires that upper > lower or the deceleration animation never ends + */ + nVPageSize = std::min(nVPageSize, nVUpper); + + m_xScrolledWindow->vadjustment_configure(nVCurrentDocPos, 0, nVUpper, + nVStepIncrement, nVPageIncrement, nVPageSize); +} + +IMPL_LINK_NOARG(SQLEditView, ScrollHdl, weld::ScrolledWindow&, void) +{ + DoScroll(); +} + +IMPL_LINK_NOARG(SQLEditView, EditStatusHdl, EditStatus&, void) +{ + Resize(); +} + +void SQLEditView::DoScroll() +{ + if (m_xEditView) + { + auto currentDocPos = m_xEditView->GetVisArea().Top(); + auto nDiff = currentDocPos - m_xScrolledWindow->vadjustment_get_value(); + // we expect SetScrollBarRange callback to be triggered by Scroll + // to set where we ended up + m_xEditView->Scroll(0, nDiff); + } +} + +void SQLEditView::ConfigurationChanged(utl::ConfigurationBroadcaster*, ConfigurationHints) +{ + UpdateData(); +} + +void SQLEditView::ImplSetFont() +{ + // see SmEditWindow::DataChanged for a similar case + SetItemPoolFont(m_pItemPool.get()); // change default font + // re-create with the new font + EditEngine& rEditEngine = *GetEditEngine(); + OUString aTxt(rEditEngine.GetText()); + rEditEngine.Clear(); + SetTextAndUpdate(aTxt); +} + +/* 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 0000000000..45050a1967 --- /dev/null +++ b/dbaccess/source/ui/control/tabletree.cxx @@ -0,0 +1,707 @@ +/* -*- 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 <comphelper/diagnose_ex.hxx> +#include <osl/diagnose.h> +#include <connectivity/dbmetadata.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::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(std::unique_ptr<weld::TreeView> xTreeView, bool bShowToggles) + : TreeListBox(std::move(xTreeView), true) + , m_xImageProvider(new ImageProvider) + , m_bVirtualRoot(false) + , m_bNoEmptyFolders(false) + , m_bShowToggles(bShowToggles) +{ + if (m_bShowToggles) + m_xTreeView->enable_toggle_buttons(weld::ColumnToggleType::Check); +} + +bool OTableTreeListBox::isFolderEntry(const weld::TreeIter& rEntry) const +{ + sal_Int32 nEntryType = m_xTreeView->get_id(rEntry).toInt32(); + return ( nEntryType == DatabaseObjectContainer::TABLES ) + || ( nEntryType == DatabaseObjectContainer::CATALOG ) + || ( nEntryType == DatabaseObjectContainer::SCHEMA ); +} + +void OTableTreeListBox::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&) + { + TOOLS_WARN_EXCEPTION( "dbaccess", "OTableTreeListBox::UpdateTableList"); + } + 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 ); +} + +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 + 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, false, xRet.get()); + m_xTreeView->set_image(*xRet, sImageId, -1); + if (m_bShowToggles) + m_xTreeView->set_toggle(*xRet, TRISTATE_FALSE); + m_xTreeView->set_text(*xRet, sRootEntryText, 0); + m_xTreeView->set_text_emphasis(*xRet, false, 0); + } + + 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 ( !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, false, xRet.get()); + m_xTreeView->set_image(*xRet, sImageId, -1); + if (m_bShowToggles) + m_xTreeView->set_toggle(*xRet, TRISTATE_FALSE); + m_xTreeView->set_text(*xRet, folderName, 0); + m_xTreeView->set_text_emphasis(*xRet, false, 0); + } + } + } + } + } + catch ( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("dbaccess"); + } + + m_xTreeView->make_sorted(); +} + +bool OTableTreeListBox::isWildcardChecked(const weld::TreeIter& rEntry) +{ + return m_xTreeView->get_text_emphasis(rEntry, 0); +} + +void OTableTreeListBox::checkWildcard(const weld::TreeIter& rEntry) +{ + if (!m_bShowToggles) + return; + m_xTreeView->set_toggle(rEntry, TRISTATE_TRUE); + checkedButton_noBroadcast(rEntry); +} + +std::unique_ptr<weld::TreeIter> OTableTreeListBox::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(const weld::TreeIter& rEntry) +{ + if (!m_bShowToggles) + return; + TriState eState = m_xTreeView->get_toggle(rEntry); + 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); + 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); + 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); + 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(const 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, 0); + } + + 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); + } +} + +std::unique_ptr<weld::TreeIter> 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 ); + + 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, false, xFolder.get()); + m_xTreeView->set_image(*xFolder, sImageId, -1); + if (m_bShowToggles) + m_xTreeView->set_toggle(*xFolder, TRISTATE_FALSE); + m_xTreeView->set_text(*xFolder, rFirstName, 0); + m_xTreeView->set_text_emphasis(*xFolder, false, 0); + } + 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, false, xFolder.get()); + m_xTreeView->set_image(*xFolder, sImageId, -1); + if (m_bShowToggles) + m_xTreeView->set_toggle(*xFolder, TRISTATE_FALSE); + m_xTreeView->set_text(*xFolder, rSecondName, 0); + m_xTreeView->set_text_emphasis(*xFolder, false, 0); + } + xParentEntry = std::move(xFolder); + } + + if (!_bCheckName || !GetEntryPosByName(sName, xParentEntry.get())) + { + std::unique_ptr<weld::TreeIter> xEntry = m_xTreeView->make_iterator(); + m_xTreeView->insert(xParentEntry.get(), -1, 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); + m_xTreeView->set_text(*xEntry, sName, 0); + m_xTreeView->set_text_emphasis(*xEntry, false, 0); + + return xEntry; + } + + return nullptr; +} + +NamedDatabaseObject OTableTreeListBox::describeObject(const weld::TreeIter& rEntry) +{ + NamedDatabaseObject aObject; + + sal_Int32 nEntryType = m_xTreeView->get_id(rEntry).toInt32(); + + 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(rEntry); + } + + return aObject; +} + +std::unique_ptr<weld::TreeIter> 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(const weld::TreeIter& rEntry) const +{ + OSL_PRECOND( !isFolderEntry(rEntry), "OTableTreeListBox::getQualifiedTableName: folder entries not allowed here!" ); + + try + { + Reference< XDatabaseMetaData > xMeta; + if ( !impl_getAndAssertMetaData( xMeta ) ) + return OUString(); + + OUString sCatalog; + OUString sSchema; + OUString sTable; + + std::unique_ptr<weld::TreeIter> xSchema(m_xTreeView->make_iterator(&rEntry)); + bool bSchema = m_xTreeView->iter_parent(*xSchema); + if (bSchema) + { + std::unique_ptr<weld::TreeIter> xCatalog(m_xTreeView->make_iterator(xSchema.get())); + bool bCatalog = m_xTreeView->iter_parent(*xCatalog); + if ( bCatalog + || ( xMeta->supportsCatalogsInDataManipulation() + && !xMeta->supportsSchemasInDataManipulation() + ) // here we support catalog but no schema + ) + { + if (!bCatalog) + { + xCatalog = std::move(xSchema); + bSchema = false; + } + sCatalog = m_xTreeView->get_text(*xCatalog); + } + if (bSchema) + sSchema = m_xTreeView->get_text(*xSchema); + } + sTable = m_xTreeView->get_text(rEntry); + + return ::dbtools::composeTableName( xMeta, sCatalog, sSchema, sTable, false, ::dbtools::EComposeRule::InDataManipulation ); + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("dbaccess"); + } + return OUString(); +} + +std::unique_ptr<weld::TreeIter> 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); + + std::unique_ptr<weld::TreeIter> xParent(getAllObjectsEntry()); + std::unique_ptr<weld::TreeIter> xCat; + std::unique_ptr<weld::TreeIter> xSchema; + if (!sCatalog.isEmpty()) + { + xCat = GetEntryPosByName(sCatalog); + if (xCat) + xParent = std::move(xCat); + } + + if (!sSchema.isEmpty()) + { + xSchema = GetEntryPosByName(sSchema, xParent.get()); + if (xSchema) + xParent = std::move(xSchema); + } + + return GetEntryPosByName(sName, xParent.get()); + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("dbaccess"); + } + return nullptr; +} + +void OTableTreeListBox::removedTable(const OUString& rName) +{ + try + { + std::unique_ptr<weld::TreeIter> xEntry = getEntryByQualifiedName(rName); + if (xEntry) + m_xTreeView->remove(*xEntry); + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("dbaccess"); + } +} + +void OTableTreeListBox::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 OTableTreeListBox::implDetermineState(const weld::TreeIter& rEntry) +{ + if (!m_bShowToggles) + return TRISTATE_FALSE; + + TriState eState = m_xTreeView->get_toggle(rEntry); + 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); + + return eState; +} + +DBTableTreeView::DBTableTreeView(weld::Container* pContainer) + : DBTreeViewBase(pContainer) +{ + m_xTreeListBox.reset(new OTableTreeListBox(m_xBuilder->weld_tree_view("treeview"), /*bShowToggles*/false)); +} + +} // 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 0000000000..00a5fd4079 --- /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 <QueryTextView.hxx> + +namespace dbaui +{ +void OSqlEditUndoAct::ToggleText() +{ + OUString strNext = m_rOwner.GetSQLText(); + m_rOwner.SetSQLText(m_strNextText); + m_strNextText = strNext; +} + +} // namespace + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |