/* -*- 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 .
*/
void OTableController::Execute(sal_uInt16 _nId, const Sequence< PropertyValue >& aArgs)
{ switch(_nId)
{ case ID_BROWSER_EDITDOC:
setEditable(!isEditable()); static_cast<OTableDesignView*>(getView())->setReadOnly(!isEditable());
InvalidateFeature(ID_BROWSER_SAVEDOC);
InvalidateFeature(ID_BROWSER_PASTE);
InvalidateFeature(SID_BROWSER_CLEAR_QUERY); break; case ID_BROWSER_SAVEASDOC:
doSaveDoc(true); break; case ID_BROWSER_SAVEDOC: static_cast<OTableDesignView*>(getView())->GetEditorCtrl()->SaveCurRow();
doSaveDoc(false); break; case ID_BROWSER_CUT: static_cast<OTableDesignView*>(getView())->cut(); break; case ID_BROWSER_COPY: static_cast<OTableDesignView*>(getView())->copy(); break; case ID_BROWSER_PASTE: static_cast<OTableDesignView*>(getView())->paste(); break; case SID_INDEXDESIGN:
doEditIndexes(); break; default:
OTableController_BASE::Execute(_nId,aArgs);
}
InvalidateFeature(_nId);
}
bool OTableController::doSaveDoc(bool _bSaveAs)
{ if (!isConnected())
reconnect(true); // ask the user for a new connection
Reference<XTablesSupplier> xTablesSup(getConnection(),UNO_QUERY);
// first we need a name for our query so ask the user if(bNew)
{
OUString aName = DBA_RES(STR_TBL_TITLE);
OUString aDefaultName = aName.getToken(0,' ');
aDefaultName = ::dbtools::createUniqueName(xTables,aDefaultName);
// did we get a name if(m_sName.isEmpty()) returnfalse;
} catch(Exception&)
{
OSL_FAIL("OTableController::doSaveDoc: nothing is expected to happen here!");
}
Reference<XPropertySet> xTable; if(bNew || !xTables->hasByName(m_sName)) // just to make sure the table already exists
{
dropTable(xTables,m_sName);
Reference<XDataDescriptorFactory> xFact(xTables,UNO_QUERY);
OSL_ENSURE(xFact.is(),"OTableController::doSaveDoc: No XDataDescriptorFactory available!");
xTable = xFact->createDataDescriptor();
OSL_ENSURE(xTable.is(),"OTableController::doSaveDoc: Create query failed!"); // to set the name is only allowed when the query is new
xTable->setPropertyValue(PROPERTY_CATALOGNAME,Any(sCatalog));
xTable->setPropertyValue(PROPERTY_SCHEMANAME,Any(sSchema));
xTable->setPropertyValue(PROPERTY_NAME,Any(m_sName));
// now append the columns
Reference<XColumnsSupplier> xColSup(xTable,UNO_QUERY);
appendColumns(xColSup,bNew); // now append the primary key
Reference<XKeysSupplier> xKeySup(xTable,UNO_QUERY);
appendPrimaryKey(xKeySup,bNew);
} // now set the properties if(bNew)
{
Reference<XAppend> xAppend(xTables,UNO_QUERY);
OSL_ENSURE(xAppend.is(),"OTableController::doSaveDoc: No XAppend Interface!");
xAppend->appendByDescriptor(xTable);
assignTable(); if(!m_xTable.is()) // correct name and try again
{ // it can be that someone inserted new data for us
m_sName = ::dbtools::composeTableName( getConnection()->getMetaData(), xTable, ::dbtools::EComposeRule::InDataManipulation, false );
assignTable();
} // now check if our datasource has set a tablefilter and if append the new table name to it
::dbaui::appendToFilter(getConnection(), m_sName, getORB(), getFrameWeld()); // we are not interested in the return value
Reference< frame::XTitleChangeListener> xEventListener(impl_getTitleHelper_throw(),UNO_QUERY); if ( xEventListener.is() )
{
frame::TitleChangedEvent aEvent;
xEventListener->titleChanged(aEvent);
}
releaseNumberForComponent();
} elseif(m_xTable.is())
{
bAlter = true;
alterColumns();
}
reSyncRows();
} catch(const SQLContext& e)
{
aInfo = SQLExceptionInfo(e);
} catch(const SQLWarning& e)
{
aInfo = SQLExceptionInfo(e);
} catch(const SQLException& e)
{
aInfo = SQLExceptionInfo(e);
} catch(const ElementExistException& )
{
OUString sText( DBA_RES( STR_NAME_ALREADY_EXISTS ) );
sText = sText.replaceFirst( "#" , m_sName);
OSQLMessageBox aDlg(getFrameWeld(), DBA_RES( STR_ERROR_DURING_CREATION ), sText, MessBoxStyle::Ok, MessageType::Error);
aDlg.run();
bError = true;
} catch( const Exception& )
{
DBG_UNHANDLED_EXCEPTION("dbaccess");
bError = true;
}
if ( aInfo.isValid() )
aInfo.prepend( DBA_RES( STR_TABLEDESIGN_SAVE_ERROR ) );
showError(aInfo);
void OTableController::doEditIndexes()
{ // table needs to be saved before editing indexes if (m_bNew || isModified())
{
std::unique_ptr<weld::MessageDialog> xAsk(Application::CreateMessageDialog(getFrameWeld(),
VclMessageType::Question, VclButtonsType::YesNo,
DBA_RES(STR_QUERY_SAVE_TABLE_EDIT_INDEXES))); if (RET_YES != xAsk->run()) return;
if (!doSaveDoc(false)) return;
OSL_ENSURE(!m_bNew && !isModified(), "OTableController::doEditIndexes: what the hell did doSaveDoc do?");
}
Reference< XNameAccess > xIndexes; // will be the keys of the table
Sequence< OUString > aFieldNames; // will be the column names of the table try
{ // get the keys
Reference< XIndexesSupplier > xIndexesSupp(m_xTable, UNO_QUERY); if (xIndexesSupp.is())
{
xIndexes = xIndexesSupp->getIndexes();
OSL_ENSURE(xIndexes.is(), "OTableController::doEditIndexes: no keys got from the indexes supplier!");
} else
OSL_FAIL("OTableController::doEditIndexes: should never have reached this (no indexes supplier)!");
// get the field names
Reference< XColumnsSupplier > xColSupp(m_xTable, UNO_QUERY);
OSL_ENSURE(xColSupp.is(), "OTableController::doEditIndexes: no columns supplier!"); if (xColSupp.is())
{
Reference< XNameAccess > xCols = xColSupp->getColumns();
OSL_ENSURE(xCols.is(), "OTableController::doEditIndexes: no columns!"); if (xCols.is())
aFieldNames = xCols->getElementNames();
}
} catch( const Exception& )
{
DBG_UNHANDLED_EXCEPTION("dbaccess");
}
try
{
::dbaui::fillTypeInfo(getConnection(),m_sTypeNames,m_aTypeInfo,m_aTypeInfoIndex); // fill the needed type information
} catch(const SQLException&)
{
OSQLWarningBox aWarning(getFrameWeld(), DBA_RES( STR_NO_TYPE_INFO_AVAILABLE));
aWarning.run(); throw;
} try
{
loadData(); // fill the column information from the table
getView()->initialize(); // show the windows and fill with our information
ClearUndoManager();
setModified(false); // and we are not modified yet
} catch( const Exception& )
{
DBG_UNHANDLED_EXCEPTION("dbaccess");
}
}
void SAL_CALL OTableController::disposing( const EventObject& _rSource )
{ if ( _rSource.Source == m_xTable )
{ // some deleted our table so we have a new one
stopTableListening();
m_xTable = nullptr;
m_bNew = true;
setModified(true);
} else
OTableController_BASE::disposing( _rSource );
}
void OTableController::losingConnection( )
{ // let the base class do its reconnect
OTableController_BASE::losingConnection( );
void OTableController::loadData()
{ // if the data structure already exists, empty it
m_vRowList.clear();
std::shared_ptr<OTableRow> pTabEdRow;
Reference< XDatabaseMetaData> xMetaData = getMetaData( ); // fill data structure with data from DataDefinitionObject if(m_xTable.is() && xMetaData.is())
{
Reference<XColumnsSupplier> xColSup(m_xTable,UNO_QUERY);
OSL_ENSURE(xColSup.is(),"No XColumnsSupplier!");
Reference<XNameAccess> xColumns = xColSup->getColumns(); // ReadOnly-Flag // For Drop no row may be editable // For Add only the empty rows may be editable // For Add and Drop all rows can be edited // sal_Bool bReadOldRow = xMetaData->supportsAlterTableWithAddColumn() && xMetaData->supportsAlterTableWithDropColumn(); bool bIsAlterAllowed = isAlterAllowed();
Reference<XNameAccess> xColumns = xColSup->getColumns();
Reference<XIndexAccess> xIdxColumns(xColumns,UNO_QUERY_THROW);
OSL_ENSURE(xColumns.is(),"No columns"); if ( !xColumns.is() ) return;
Reference<XAlterTable> xAlter(m_xTable,UNO_QUERY); // can be null
sal_Int32 nColumnCount = xIdxColumns->getCount();
Reference<XDrop> xDrop(xColumns,UNO_QUERY); // can be null
Reference<XAppend> xAppend(xColumns,UNO_QUERY); // can be null
Reference<XDataDescriptorFactory> xColumnFactory(xColumns,UNO_QUERY); // can be null
bool bReload = false; // refresh the data
// contains all columns names which are already handled those which are not in the list will be deleted
Reference< XDatabaseMetaData> xMetaData = getMetaData( );
std::set<OUString, comphelper::UStringMixLess> aColumns(
comphelper::UStringMixLess(
!xMetaData.is()
|| xMetaData->supportsMixedCaseQuotedIdentifiers()));
std::vector< std::shared_ptr<OTableRow> >::const_iterator aIter = m_vRowList.begin();
std::vector< std::shared_ptr<OTableRow> >::const_iterator aEnd = m_vRowList.end(); // first look for columns where something other than the name changed for(sal_Int32 nPos = 0;aIter != aEnd;++aIter,++nPos)
{
OSL_ENSURE(*aIter,"OTableRow is null!");
OFieldDescription* pField = (*aIter)->GetActFieldDescr(); if ( !pField ) continue; if ( (*aIter)->IsReadOnly() )
{
aColumns.insert(pField->GetName()); continue;
}
Reference<XPropertySet> xColumn; if ( xColumns->hasByName(pField->GetName()) )
{
aColumns.insert(pField->GetName());
xColumns->getByName(pField->GetName()) >>= xColumn;
OSL_ENSURE(xColumn.is(),"Column is null!");
try { xColumn->getPropertyValue(PROPERTY_TYPENAME) >>= sTypeName; } catch( const Exception& )
{
OSL_FAIL( "no TypeName property?!" ); // since this is a last minute fix for #i41785#, I want to be on the safe side, // and catch errors here as early as possible (instead of the whole process of altering // the columns failing) // Normally, sdbcx::Column objects are expected to have a TypeName property
}
// check if something changed if((nType != pField->GetType() ||
sTypeName != pField->GetTypeName() ||
(nPrecision != pField->GetPrecision() && nPrecision ) ||
nScale != pField->GetScale() ||
nNullable != pField->GetIsNullable() ||
sDescription != pField->GetDescription() ||
bAutoIncrement != pField->IsAutoIncrement())&&
xColumnFactory.is())
{
Reference<XPropertySet> xNewColumn = xColumnFactory->createDataDescriptor();
::dbaui::setColumnProperties(xNewColumn,pField); // first try to alter the column bool bNotOk = false; try
{ // first try if we can alter the column if(xAlter.is())
xAlter->alterColumnByName(pField->GetName(),xNewColumn);
} catch(const SQLException&)
{ if(xDrop.is() && xAppend.is())
{
OUString aMessage( DBA_RES( STR_TABLEDESIGN_ALTER_ERROR ) );
aMessage = aMessage.replaceFirst( "$column$", pField->GetName() );
SQLExceptionInfo aError( ::cppu::getCaughtException() );
OSQLWarningBox aMsg(getFrameWeld(), aMessage, MessBoxStyle::YesNo | MessBoxStyle::DefaultYes , &aError);
bNotOk = aMsg.run() == RET_YES;
} else throw;
} // if something went wrong or we can't alter columns // drop and append a new one if((!xAlter.is() || bNotOk) && xDrop.is() && xAppend.is())
{
xDrop->dropByName(pField->GetName()); try
{
xAppend->appendByDescriptor(xNewColumn);
} catch(const SQLException&)
{ // an error occurred so we try to reactivate the old one
xAppend->appendByDescriptor(xColumn); throw;
}
} // exceptions are caught outside
xNewColumn = nullptr; if(xColumns->hasByName(pField->GetName()))
xColumns->getByName(pField->GetName()) >>= xColumn;
bReload = true;
}
} elseif(xColumnFactory.is() && xAlter.is() && nPos < nColumnCount)
{ // we can't find the column so we could try it with the index before we drop and append a new column try
{
Reference<XPropertySet> xNewColumn = xColumnFactory->createDataDescriptor();
::dbaui::setColumnProperties(xNewColumn,pField);
xAlter->alterColumnByIndex(nPos,xNewColumn); if(xColumns->hasByName(pField->GetName()))
{ // ask for the append by name
aColumns.insert(pField->GetName());
xColumns->getByName(pField->GetName()) >>= xColumn; if(xColumn.is())
pField->copyColumnSettingsTo(xColumn);
} else
{
OSL_FAIL("OTableController::alterColumns: invalid column (2)!");
}
} catch(const SQLException&)
{ // we couldn't alter the column so we have to add new columns
SQLExceptionInfo aError( ::cppu::getCaughtException() );
bReload = true; if(xDrop.is() && xAppend.is())
{
OUString aMessage(DBA_RES(STR_TABLEDESIGN_ALTER_ERROR));
aMessage = aMessage.replaceFirst("$column$",pField->GetName());
OSQLWarningBox aMsg(getFrameWeld(), aMessage, MessBoxStyle::YesNo | MessBoxStyle::DefaultYes, &aError); if (aMsg.run() != RET_YES)
{
Reference<XPropertySet> xNewColumn(xIdxColumns->getByIndex(nPos),UNO_QUERY_THROW);
OUString sName;
xNewColumn->getPropertyValue(PROPERTY_NAME) >>= sName;
aColumns.insert(sName);
aColumns.insert(pField->GetName()); continue;
}
} else throw;
}
} else
bReload = true;
} // alter column settings
// first look for columns where something other than the name changed for (autoconst& row : m_vRowList)
{
OSL_ENSURE(row,"OTableRow is null!");
OFieldDescription* pField = row->GetActFieldDescr(); if ( !pField ) continue; if ( row->IsReadOnly() )
{
aColumns.insert(pField->GetName()); continue;
}
Reference<XPropertySet> xColumn; if ( xColumns->hasByName(pField->GetName()) )
{
xColumns->getByName(pField->GetName()) >>= xColumn;
Reference<XPropertySetInfo> xInfo = xColumn->getPropertySetInfo(); if ( xInfo->hasPropertyByName(PROPERTY_HELPTEXT) )
xColumn->setPropertyValue(PROPERTY_HELPTEXT,Any(pField->GetHelpText()));
if(xInfo->hasPropertyByName(PROPERTY_CONTROLDEFAULT))
xColumn->setPropertyValue(PROPERTY_CONTROLDEFAULT,pField->GetControlDefault()); if(xInfo->hasPropertyByName(PROPERTY_FORMATKEY))
xColumn->setPropertyValue(PROPERTY_FORMATKEY,Any(pField->GetFormatKey())); if(xInfo->hasPropertyByName(PROPERTY_ALIGN))
xColumn->setPropertyValue(PROPERTY_ALIGN,Any(dbaui::mapTextAlign(pField->GetHorJustify())));
}
} // second drop all columns which could be found by name
Reference<XNameAccess> xKeyColumns = getKeyColumns(); // now we have to look for the columns who could be deleted if ( xDrop.is() )
{ const Sequence<OUString> aColNames = xColumns->getElementNames(); for(const OUString& rColumnName : aColNames)
{ if(aColumns.find(rColumnName) == aColumns.end()) // found a column to delete
{ if(xKeyColumns.is() && xKeyColumns->hasByName(rColumnName)) // check if this column is a member of the primary key
{
OUString aMsgT(DBA_RES(STR_TBL_COLUMN_IS_KEYCOLUMN));
aMsgT = aMsgT.replaceFirst("$column$",rColumnName);
OUString aTitle(DBA_RES(STR_TBL_COLUMN_IS_KEYCOLUMN_TITLE));
OSQLMessageBox aMsg(getFrameWeld(), aTitle, aMsgT, MessBoxStyle::YesNo| MessBoxStyle::DefaultYes); if (aMsg.run() == RET_YES)
{
xKeyColumns = nullptr;
dropPrimaryKey();
} else
{
bReload = true; continue;
}
} try
{
xDrop->dropByName(rColumnName);
} catch (const SQLException&)
{ constauto caughtException = ::cppu::getCaughtException();
OUString sError( DBA_RES( STR_TABLEDESIGN_COULD_NOT_DROP_COL ) );
sError = sError.replaceFirst( "$column$", rColumnName );
// third append the new columns for(constauto& rxRow : m_vRowList)
{
OSL_ENSURE(rxRow,"OTableRow is null!");
OFieldDescription* pField = rxRow->GetActFieldDescr(); if ( !pField || rxRow->IsReadOnly() || aColumns.find(pField->GetName()) != aColumns.end() ) continue;
Reference<XPropertySet> xColumn; if(!xColumns->hasByName(pField->GetName()))
{ if(xColumnFactory.is() && xAppend.is())
{// column not found by its name so we assume it is new // Column is new
xColumn = xColumnFactory->createDataDescriptor();
::dbaui::setColumnProperties(xColumn,pField);
xAppend->appendByDescriptor(xColumn); if(xColumns->hasByName(pField->GetName()))
{ // ask for the append by name
aColumns.insert(pField->GetName());
xColumns->getByName(pField->GetName()) >>= xColumn; if(xColumn.is())
pField->copyColumnSettingsTo(xColumn);
} else
{
OSL_FAIL("OTableController::alterColumns: invalid column!");
}
}
}
}
// check if we have to do something with the primary key bool bNeedDropKey = false; bool bNeedAppendKey = false; if ( xKeyColumns.is() )
{ for(constauto& rxRow : m_vRowList)
{
OSL_ENSURE(rxRow,"OTableRow is null!");
OFieldDescription* pField = rxRow->GetActFieldDescr(); if ( !pField ) continue;
if ( pField->IsPrimaryKey()
&& !xKeyColumns->hasByName( pField->GetName() )
)
{ // new primary key column inserted which isn't already in the columns selection
bNeedDropKey = bNeedAppendKey = true; break;
} elseif ( !pField->IsPrimaryKey()
&& xKeyColumns->hasByName( pField->GetName() )
)
{ // found a column which currently is in the primary key, but is marked not to be anymore
bNeedDropKey = bNeedAppendKey = true; break;
}
}
} else
{ // no primary key available so we check if we should create one
bNeedAppendKey = true;
}
if ( bNeedDropKey && xKeyColumns.is() && xKeyColumns->getElementNames().hasElements() )
dropPrimaryKey();
sal_Int32 i = 0; while(std::any_of(m_vRowList.begin(), m_vRowList.end(), lHasName))
{ // found a second name of _rName so we need another
sName = _rName + OUString::number(++i);
} return sName;
}
void OTableController::reload()
{
loadData(); // fill the column information from the table static_cast<OTableDesignView*>(getView())->reSync(); // show the windows and fill with our information
ClearUndoManager();
setModified(false); // and we are not modified yet static_cast<OTableDesignView*>(getView())->Invalidate();
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.