calc: on editing invalidation of view with different zoom is wrong
[LibreOffice.git] / dbaccess / source / ui / tabledesign / TableController.cxx
blobdb2fcf48fbbfa8631b099bec49c0e329eb933a34
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <FieldDescriptions.hxx>
21 #include "TEditControl.hxx"
22 #include <TableController.hxx>
23 #include <TableDesignView.hxx>
24 #include <TableRow.hxx>
25 #include <TypeInfo.hxx>
26 #include <UITools.hxx>
27 #include <browserids.hxx>
28 #include <core_resource.hxx>
29 #include <strings.hrc>
30 #include <strings.hxx>
31 #include <defaultobjectnamecheck.hxx>
32 #include <dlgsave.hxx>
33 #include <indexdialog.hxx>
34 #include <sqlmessage.hxx>
36 #include <com/sun/star/frame/XTitleChangeListener.hpp>
37 #include <com/sun/star/sdb/CommandType.hpp>
38 #include <com/sun/star/sdb/SQLContext.hpp>
39 #include <com/sun/star/sdbc/ColumnValue.hpp>
40 #include <com/sun/star/sdbc/SQLWarning.hpp>
41 #include <com/sun/star/sdbcx/KeyType.hpp>
42 #include <com/sun/star/sdbcx/XAlterTable.hpp>
43 #include <com/sun/star/sdbcx/XAppend.hpp>
44 #include <com/sun/star/sdbcx/XDataDescriptorFactory.hpp>
45 #include <com/sun/star/sdbcx/XDrop.hpp>
46 #include <com/sun/star/sdbcx/XIndexesSupplier.hpp>
47 #include <com/sun/star/sdbcx/XTablesSupplier.hpp>
49 #include <connectivity/dbexception.hxx>
50 #include <connectivity/dbtools.hxx>
51 #include <connectivity/dbmetadata.hxx>
52 #include <cppuhelper/exc_hlp.hxx>
53 #include <comphelper/diagnose_ex.hxx>
54 #include <vcl/svapp.hxx>
55 #include <vcl/weld.hxx>
56 #include <o3tl/string_view.hxx>
58 #include <algorithm>
59 #include <functional>
60 #include <set>
62 extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface*
63 org_openoffice_comp_dbu_OTableDesign_get_implementation(
64 css::uno::XComponentContext* context, css::uno::Sequence<css::uno::Any> const& )
66 return cppu::acquire(new ::dbaui::OTableController(context));
69 using namespace ::com::sun::star;
70 using namespace ::com::sun::star::uno;
71 using namespace ::com::sun::star::io;
72 using namespace ::com::sun::star::beans;
73 using namespace ::com::sun::star::frame;
74 using namespace ::com::sun::star::lang;
75 using namespace ::com::sun::star::container;
76 using namespace ::com::sun::star::sdbcx;
77 using namespace ::com::sun::star::sdbc;
78 using namespace ::com::sun::star::sdb;
79 using namespace ::com::sun::star::ui;
80 using namespace ::com::sun::star::util;
81 using namespace ::dbtools;
82 using namespace ::dbaui;
83 using namespace ::comphelper;
85 // number of columns when creating it from scratch
86 #define NEWCOLS 128
88 namespace
90 void dropTable(const Reference<XNameAccess>& _rxTable,const OUString& _sTableName)
92 if ( _rxTable->hasByName(_sTableName) )
94 Reference<XDrop> xNameCont(_rxTable,UNO_QUERY);
95 OSL_ENSURE(xNameCont.is(),"No drop interface for tables!");
96 if ( xNameCont.is() )
97 xNameCont->dropByName(_sTableName);
102 OUString SAL_CALL OTableController::getImplementationName()
104 return "org.openoffice.comp.dbu.OTableDesign";
107 Sequence< OUString> OTableController::getSupportedServiceNames()
109 return { "com.sun.star.sdb.TableDesign" };
112 OTableController::OTableController(const Reference< XComponentContext >& _rM) : OTableController_BASE(_rM)
113 ,m_sTypeNames(DBA_RES(STR_TABLEDESIGN_DBFIELDTYPES))
114 ,m_bAllowAutoIncrementValue(false)
115 ,m_bNew(true)
118 InvalidateAll();
119 m_pTypeInfo = std::make_shared<OTypeInfo>();
120 m_pTypeInfo->aUIName = m_sTypeNames.getToken(TYPE_OTHER, ';');
123 OTableController::~OTableController()
125 m_aTypeInfoIndex.clear();
126 m_aTypeInfo.clear();
130 void OTableController::startTableListening()
132 Reference< XComponent > xComponent(m_xTable, UNO_QUERY);
133 if (xComponent.is())
134 xComponent->addEventListener(static_cast<XModifyListener*>(this));
137 void OTableController::stopTableListening()
139 Reference< XComponent > xComponent(m_xTable, UNO_QUERY);
140 if (xComponent.is())
141 xComponent->removeEventListener(static_cast<XModifyListener*>(this));
144 void OTableController::disposing()
146 OTableController_BASE::disposing();
147 clearView();
149 m_vRowList.clear();
152 FeatureState OTableController::GetState(sal_uInt16 _nId) const
154 FeatureState aReturn;
155 // disabled automatically
157 switch (_nId)
159 case ID_BROWSER_CLOSE:
160 aReturn.bEnabled = true;
161 break;
162 case ID_BROWSER_EDITDOC:
163 aReturn.bChecked = isEditable();
164 aReturn.bEnabled = true;
165 break;
166 case ID_BROWSER_SAVEDOC:
167 aReturn.bEnabled = isEditable() && std::any_of(m_vRowList.begin(),m_vRowList.end(),std::mem_fn(&OTableRow::isValid));
168 break;
169 case ID_BROWSER_SAVEASDOC:
170 aReturn.bEnabled = isConnected() && isEditable();
171 if ( aReturn.bEnabled )
173 aReturn.bEnabled = std::any_of(m_vRowList.begin(),m_vRowList.end(),
174 std::mem_fn(&OTableRow::isValid));
176 break;
178 case ID_BROWSER_CUT:
179 aReturn.bEnabled = isEditable() && getView() && static_cast<OTableDesignView*>(getView())->isCutAllowed();
180 break;
181 case ID_BROWSER_COPY:
182 aReturn.bEnabled = getView() && static_cast<OTableDesignView*>(getView())->isCopyAllowed();
183 break;
184 case ID_BROWSER_PASTE:
185 aReturn.bEnabled = isEditable() && getView() && static_cast<OTableDesignView*>(getView())->isPasteAllowed();
186 break;
187 case SID_INDEXDESIGN:
188 aReturn.bEnabled =
189 ( ( ((!m_bNew && impl_isModified()) || impl_isModified())
190 || Reference< XIndexesSupplier >(m_xTable, UNO_QUERY).is()
192 && isConnected()
194 if ( aReturn.bEnabled )
196 aReturn.bEnabled = std::any_of(m_vRowList.begin(),m_vRowList.end(),
197 std::mem_fn(&OTableRow::isValid));
199 break;
200 default:
201 aReturn = OTableController_BASE::GetState(_nId);
203 return aReturn;
206 void OTableController::Execute(sal_uInt16 _nId, const Sequence< PropertyValue >& aArgs)
208 switch(_nId)
210 case ID_BROWSER_EDITDOC:
211 setEditable(!isEditable());
212 static_cast<OTableDesignView*>(getView())->setReadOnly(!isEditable());
213 InvalidateFeature(ID_BROWSER_SAVEDOC);
214 InvalidateFeature(ID_BROWSER_PASTE);
215 InvalidateFeature(SID_BROWSER_CLEAR_QUERY);
216 break;
217 case ID_BROWSER_SAVEASDOC:
218 doSaveDoc(true);
219 break;
220 case ID_BROWSER_SAVEDOC:
221 static_cast<OTableDesignView*>(getView())->GetEditorCtrl()->SaveCurRow();
222 doSaveDoc(false);
223 break;
224 case ID_BROWSER_CUT:
225 static_cast<OTableDesignView*>(getView())->cut();
226 break;
227 case ID_BROWSER_COPY:
228 static_cast<OTableDesignView*>(getView())->copy();
229 break;
230 case ID_BROWSER_PASTE:
231 static_cast<OTableDesignView*>(getView())->paste();
232 break;
233 case SID_INDEXDESIGN:
234 doEditIndexes();
235 break;
236 default:
237 OTableController_BASE::Execute(_nId,aArgs);
239 InvalidateFeature(_nId);
242 bool OTableController::doSaveDoc(bool _bSaveAs)
244 if (!isConnected())
245 reconnect(true); // ask the user for a new connection
246 Reference<XTablesSupplier> xTablesSup(getConnection(),UNO_QUERY);
248 if (!xTablesSup.is())
250 OUString aMessage(DBA_RES(STR_TABLEDESIGN_CONNECTION_MISSING));
251 OSQLWarningBox aWarning(getFrameWeld(), aMessage);
252 aWarning.run();
253 return false;
256 // check if a column exists
257 // TODO
259 Reference<XNameAccess> xTables;
260 OUString sCatalog, sSchema;
262 bool bNew = m_sName.isEmpty();
263 bNew = bNew || m_bNew || _bSaveAs;
267 xTables = xTablesSup->getTables();
268 OSL_ENSURE(xTables.is(),"The tables can't be null!");
269 bNew = bNew || (xTables.is() && !xTables->hasByName(m_sName));
271 // first we need a name for our query so ask the user
272 if(bNew)
274 OUString aName = DBA_RES(STR_TBL_TITLE);
275 OUString aDefaultName = aName.getToken(0,' ');
276 aDefaultName = ::dbtools::createUniqueName(xTables,aDefaultName);
278 DynamicTableOrQueryNameCheck aNameChecker( getConnection(), CommandType::TABLE );
279 OSaveAsDlg aDlg(getFrameWeld(), CommandType::TABLE, getORB(), getConnection(), aDefaultName, aNameChecker, SADFlags::NONE);
280 if (aDlg.run() != RET_OK)
281 return false;
283 m_sName = aDlg.getName();
284 sCatalog = aDlg.getCatalog();
285 sSchema = aDlg.getSchema();
288 // did we get a name
289 if(m_sName.isEmpty())
290 return false;
292 catch(Exception&)
294 OSL_FAIL("OTableController::doSaveDoc: nothing is expected to happen here!");
297 bool bAlter = false;
298 bool bError = false;
299 SQLExceptionInfo aInfo;
302 // check the columns for double names
303 if(!checkColumns(bNew || !xTables->hasByName(m_sName)))
305 return false;
308 Reference<XPropertySet> xTable;
309 if(bNew || !xTables->hasByName(m_sName)) // just to make sure the table already exists
311 dropTable(xTables,m_sName);
313 Reference<XDataDescriptorFactory> xFact(xTables,UNO_QUERY);
314 OSL_ENSURE(xFact.is(),"OTableController::doSaveDoc: No XDataDescriptorFactory available!");
315 xTable = xFact->createDataDescriptor();
316 OSL_ENSURE(xTable.is(),"OTableController::doSaveDoc: Create query failed!");
317 // to set the name is only allowed when the query is new
318 xTable->setPropertyValue(PROPERTY_CATALOGNAME,Any(sCatalog));
319 xTable->setPropertyValue(PROPERTY_SCHEMANAME,Any(sSchema));
320 xTable->setPropertyValue(PROPERTY_NAME,Any(m_sName));
322 // now append the columns
323 Reference<XColumnsSupplier> xColSup(xTable,UNO_QUERY);
324 appendColumns(xColSup,bNew);
325 // now append the primary key
326 Reference<XKeysSupplier> xKeySup(xTable,UNO_QUERY);
327 appendPrimaryKey(xKeySup,bNew);
329 // now set the properties
330 if(bNew)
332 Reference<XAppend> xAppend(xTables,UNO_QUERY);
333 OSL_ENSURE(xAppend.is(),"OTableController::doSaveDoc: No XAppend Interface!");
334 xAppend->appendByDescriptor(xTable);
336 assignTable();
337 if(!m_xTable.is()) // correct name and try again
339 // it can be that someone inserted new data for us
340 m_sName = ::dbtools::composeTableName( getConnection()->getMetaData(), xTable, ::dbtools::EComposeRule::InDataManipulation, false );
341 assignTable();
343 // now check if our datasource has set a tablefilter and if append the new table name to it
344 ::dbaui::appendToFilter(getConnection(), m_sName, getORB(), getFrameWeld()); // we are not interested in the return value
345 Reference< frame::XTitleChangeListener> xEventListener(impl_getTitleHelper_throw(),UNO_QUERY);
346 if ( xEventListener.is() )
348 frame::TitleChangedEvent aEvent;
349 xEventListener->titleChanged(aEvent);
351 releaseNumberForComponent();
353 else if(m_xTable.is())
355 bAlter = true;
356 alterColumns();
358 reSyncRows();
360 catch(const SQLContext& e)
362 aInfo = SQLExceptionInfo(e);
364 catch(const SQLWarning& e)
366 aInfo = SQLExceptionInfo(e);
368 catch(const SQLException& e)
370 aInfo = SQLExceptionInfo(e);
372 catch(const ElementExistException& )
374 OUString sText( DBA_RES( STR_NAME_ALREADY_EXISTS ) );
375 sText = sText.replaceFirst( "#" , m_sName);
376 OSQLMessageBox aDlg(getFrameWeld(), DBA_RES( STR_ERROR_DURING_CREATION ), sText, MessBoxStyle::Ok, MessageType::Error);
377 aDlg.run();
378 bError = true;
380 catch( const Exception& )
382 DBG_UNHANDLED_EXCEPTION("dbaccess");
383 bError = true;
386 if ( aInfo.isValid() )
387 aInfo.prepend( DBA_RES( STR_TABLEDESIGN_SAVE_ERROR ) );
388 showError(aInfo);
390 if (aInfo.isValid() || bError)
392 if(!bAlter || bNew)
394 m_sName.clear();
395 stopTableListening();
396 m_xTable = nullptr;
399 return ! (aInfo.isValid() || bError);
402 void OTableController::doEditIndexes()
404 // table needs to be saved before editing indexes
405 if (m_bNew || isModified())
407 std::unique_ptr<weld::MessageDialog> xAsk(Application::CreateMessageDialog(getFrameWeld(),
408 VclMessageType::Question, VclButtonsType::YesNo,
409 DBA_RES(STR_QUERY_SAVE_TABLE_EDIT_INDEXES)));
410 if (RET_YES != xAsk->run())
411 return;
413 if (!doSaveDoc(false))
414 return;
416 OSL_ENSURE(!m_bNew && !isModified(), "OTableController::doEditIndexes: what the hell did doSaveDoc do?");
419 Reference< XNameAccess > xIndexes; // will be the keys of the table
420 Sequence< OUString > aFieldNames; // will be the column names of the table
423 // get the keys
424 Reference< XIndexesSupplier > xIndexesSupp(m_xTable, UNO_QUERY);
425 if (xIndexesSupp.is())
427 xIndexes = xIndexesSupp->getIndexes();
428 OSL_ENSURE(xIndexes.is(), "OTableController::doEditIndexes: no keys got from the indexes supplier!");
430 else
431 OSL_FAIL("OTableController::doEditIndexes: should never have reached this (no indexes supplier)!");
433 // get the field names
434 Reference< XColumnsSupplier > xColSupp(m_xTable, UNO_QUERY);
435 OSL_ENSURE(xColSupp.is(), "OTableController::doEditIndexes: no columns supplier!");
436 if (xColSupp.is())
438 Reference< XNameAccess > xCols = xColSupp->getColumns();
439 OSL_ENSURE(xCols.is(), "OTableController::doEditIndexes: no columns!");
440 if (xCols.is())
441 aFieldNames = xCols->getElementNames();
444 catch( const Exception& )
446 DBG_UNHANDLED_EXCEPTION("dbaccess");
449 if (!xIndexes.is())
450 return;
452 DbaIndexDialog aDialog(getFrameWeld(), aFieldNames, xIndexes, getConnection(), getORB());
453 if (RET_OK != aDialog.run())
454 return;
458 void OTableController::impl_initialize()
462 OTableController_BASE::impl_initialize();
464 const NamedValueCollection& rArguments( getInitParams() );
466 rArguments.get_ensureType( PROPERTY_CURRENTTABLE, m_sName );
468 // read autoincrement value set in the datasource
469 ::dbaui::fillAutoIncrementValue(getDataSource(),m_bAllowAutoIncrementValue,m_sAutoIncrementValue);
471 assignTable();
473 catch( const Exception& )
475 DBG_UNHANDLED_EXCEPTION("dbaccess");
480 ::dbaui::fillTypeInfo(getConnection(),m_sTypeNames,m_aTypeInfo,m_aTypeInfoIndex); // fill the needed type information
482 catch(const SQLException&)
484 OSQLWarningBox aWarning(getFrameWeld(), DBA_RES( STR_NO_TYPE_INFO_AVAILABLE));
485 aWarning.run();
486 throw;
490 loadData(); // fill the column information from the table
491 getView()->initialize(); // show the windows and fill with our information
492 ClearUndoManager();
493 setModified(false); // and we are not modified yet
495 catch( const Exception& )
497 DBG_UNHANDLED_EXCEPTION("dbaccess");
501 bool OTableController::Construct(vcl::Window* pParent)
503 setView( VclPtr<OTableDesignView>::Create( pParent, getORB(), *this ) );
504 OTableController_BASE::Construct(pParent);
505 return true;
508 sal_Bool SAL_CALL OTableController::suspend(sal_Bool /*_bSuspend*/)
510 if ( getBroadcastHelper().bInDispose || getBroadcastHelper().bDisposed )
511 return true;
513 SolarMutexGuard aSolarGuard;
514 ::osl::MutexGuard aGuard( getMutex() );
515 if ( getView() && getView()->IsInModalMode() )
516 return false;
517 if ( getView() )
518 static_cast<OTableDesignView*>(getView())->GrabFocus();
519 bool bCheck = true;
520 if ( isModified() )
522 if ( std::any_of(m_vRowList.begin(),m_vRowList.end(),
523 std::mem_fn(&OTableRow::isValid)) )
525 std::unique_ptr<weld::Builder> xBuilder(Application::CreateBuilder(getFrameWeld(), "dbaccess/ui/tabledesignsavemodifieddialog.ui"));
526 std::unique_ptr<weld::MessageDialog> xQuery(xBuilder->weld_message_dialog("TableDesignSaveModifiedDialog"));
527 switch (xQuery->run())
529 case RET_YES:
530 Execute(ID_BROWSER_SAVEDOC,Sequence<PropertyValue>());
531 if ( isModified() )
532 bCheck = false; // when we save the table this must be false else some press cancel
533 break;
534 case RET_CANCEL:
535 bCheck = false;
536 break;
537 default:
538 break;
541 else if ( !m_bNew )
543 std::unique_ptr<weld::Builder> xBuilder(Application::CreateBuilder(getFrameWeld(), "dbaccess/ui/deleteallrowsdialog.ui"));
544 std::unique_ptr<weld::MessageDialog> xQuery(xBuilder->weld_message_dialog("DeleteAllRowsDialog"));
545 switch (xQuery->run())
547 case RET_YES:
551 Reference<XTablesSupplier> xTablesSup(getConnection(),UNO_QUERY);
552 Reference<XNameAccess> xTables = xTablesSup->getTables();
553 dropTable(xTables,m_sName);
555 catch(const Exception&)
557 OSL_FAIL("OTableController::suspend: nothing is expected to happen here!");
561 break;
562 case RET_CANCEL:
563 bCheck = false;
564 break;
565 default:
566 break;
571 return bCheck;
574 void OTableController::describeSupportedFeatures()
576 OSingleDocumentController::describeSupportedFeatures();
578 implDescribeSupportedFeature( ".uno:Redo", ID_BROWSER_REDO, CommandGroup::EDIT );
579 implDescribeSupportedFeature( ".uno:Save", ID_BROWSER_SAVEDOC, CommandGroup::EDIT );
580 implDescribeSupportedFeature( ".uno:Undo", ID_BROWSER_UNDO, CommandGroup::EDIT );
581 implDescribeSupportedFeature( ".uno:NewDoc", SID_NEWDOC, CommandGroup::DOCUMENT );
582 implDescribeSupportedFeature( ".uno:SaveAs", ID_BROWSER_SAVEASDOC, CommandGroup::DOCUMENT );
583 implDescribeSupportedFeature( ".uno:DBIndexDesign", SID_INDEXDESIGN, CommandGroup::APPLICATION );
584 implDescribeSupportedFeature( ".uno:EditDoc", ID_BROWSER_EDITDOC, CommandGroup::EDIT );
585 implDescribeSupportedFeature( ".uno:GetUndoStrings", SID_GETUNDOSTRINGS );
586 implDescribeSupportedFeature( ".uno:GetRedoStrings", SID_GETREDOSTRINGS );
589 void OTableController::impl_onModifyChanged()
591 OSingleDocumentController::impl_onModifyChanged();
592 InvalidateFeature( SID_INDEXDESIGN );
595 void SAL_CALL OTableController::disposing( const EventObject& _rSource )
597 if ( _rSource.Source == m_xTable )
598 { // some deleted our table so we have a new one
599 stopTableListening();
600 m_xTable = nullptr;
601 m_bNew = true;
602 setModified(true);
604 else
605 OTableController_BASE::disposing( _rSource );
608 void OTableController::losingConnection( )
610 // let the base class do its reconnect
611 OTableController_BASE::losingConnection( );
613 // remove from the table
614 Reference< XComponent > xComponent(m_xTable, UNO_QUERY);
615 if (xComponent.is())
617 Reference<XEventListener> xEvtL( static_cast< ::cppu::OWeakObject*>(this), UNO_QUERY);
618 xComponent->removeEventListener(xEvtL);
620 stopTableListening();
621 m_xTable = nullptr;
622 assignTable();
623 if(!m_xTable.is())
625 m_bNew = true;
626 setModified(true);
628 InvalidateAll();
631 TOTypeInfoSP OTableController::getTypeInfoByType(sal_Int32 _nDataType) const
633 return queryTypeInfoByType(_nDataType,m_aTypeInfo);
636 void OTableController::appendColumns(Reference<XColumnsSupplier> const & _rxColSup, bool _bNew, bool _bKeyColumns)
640 // now append the columns
641 OSL_ENSURE(_rxColSup.is(),"No columns supplier");
642 if(!_rxColSup.is())
643 return;
644 Reference<XNameAccess> xColumns = _rxColSup->getColumns();
645 OSL_ENSURE(xColumns.is(),"No columns");
646 Reference<XDataDescriptorFactory> xColumnFactory(xColumns,UNO_QUERY);
648 Reference<XAppend> xAppend(xColumns,UNO_QUERY);
649 OSL_ENSURE(xAppend.is(),"No XAppend Interface!");
651 for (auto const& row : m_vRowList)
653 OSL_ENSURE(row,"OTableRow is null!");
654 OFieldDescription* pField = row->GetActFieldDescr();
655 if ( !pField || (!_bNew && row->IsReadOnly() && !_bKeyColumns) )
656 continue;
658 Reference<XPropertySet> xColumn;
659 if(pField->IsPrimaryKey() || !_bKeyColumns)
660 xColumn = xColumnFactory->createDataDescriptor();
661 if(xColumn.is())
663 if(!_bKeyColumns)
664 ::dbaui::setColumnProperties(xColumn,pField);
665 else
666 xColumn->setPropertyValue(PROPERTY_NAME,Any(pField->GetName()));
668 xAppend->appendByDescriptor(xColumn);
669 xColumn = nullptr;
670 // now only the settings are missing
671 if(xColumns->hasByName(pField->GetName()))
673 xColumns->getByName(pField->GetName()) >>= xColumn;
674 if(xColumn.is())
675 pField->copyColumnSettingsTo(xColumn);
677 else
679 OSL_FAIL("OTableController::appendColumns: invalid field name!");
685 catch(const SQLException& )
687 showError( SQLExceptionInfo( ::cppu::getCaughtException() ) );
689 catch( const Exception& )
691 DBG_UNHANDLED_EXCEPTION("dbaccess");
695 void OTableController::appendPrimaryKey(Reference<XKeysSupplier> const & _rxSup, bool _bNew)
697 if(!_rxSup.is())
698 return; // the database doesn't support keys
700 OSL_ENSURE(_rxSup.is(),"No XKeysSupplier!");
701 Reference<XIndexAccess> xKeys = _rxSup->getKeys();
702 Reference<XPropertySet> xProp;
703 if (!xKeys.is())
704 return;
705 const sal_Int32 nCount = xKeys->getCount();
706 for(sal_Int32 i=0;i< nCount ;++i)
708 xKeys->getByIndex(i) >>= xProp;
709 sal_Int32 nKeyType = 0;
710 xProp->getPropertyValue(PROPERTY_TYPE) >>= nKeyType;
711 if(KeyType::PRIMARY == nKeyType)
713 return; // primary key already exists after appending a column
716 Reference<XDataDescriptorFactory> xKeyFactory(xKeys,UNO_QUERY);
717 OSL_ENSURE(xKeyFactory.is(),"No XDataDescriptorFactory Interface!");
718 if ( !xKeyFactory.is() )
719 return;
720 Reference<XAppend> xAppend(xKeyFactory,UNO_QUERY);
721 OSL_ENSURE(xAppend.is(),"No XAppend Interface!");
723 Reference<XPropertySet> xKey = xKeyFactory->createDataDescriptor();
724 OSL_ENSURE(xKey.is(),"Key is null!");
725 xKey->setPropertyValue(PROPERTY_TYPE,Any(KeyType::PRIMARY));
727 Reference<XColumnsSupplier> xColSup(xKey,UNO_QUERY);
728 if(xColSup.is())
730 appendColumns(xColSup,_bNew,true);
731 Reference<XNameAccess> xColumns = xColSup->getColumns();
732 if(xColumns->hasElements())
733 xAppend->appendByDescriptor(xKey);
737 void OTableController::loadData()
739 // if the data structure already exists, empty it
740 m_vRowList.clear();
742 std::shared_ptr<OTableRow> pTabEdRow;
743 Reference< XDatabaseMetaData> xMetaData = getMetaData( );
744 // fill data structure with data from DataDefinitionObject
745 if(m_xTable.is() && xMetaData.is())
747 Reference<XColumnsSupplier> xColSup(m_xTable,UNO_QUERY);
748 OSL_ENSURE(xColSup.is(),"No XColumnsSupplier!");
749 Reference<XNameAccess> xColumns = xColSup->getColumns();
750 // ReadOnly-Flag
751 // For Drop no row may be editable
752 // For Add only the empty rows may be editable
753 // For Add and Drop all rows can be edited
754 // sal_Bool bReadOldRow = xMetaData->supportsAlterTableWithAddColumn() && xMetaData->supportsAlterTableWithDropColumn();
755 bool bIsAlterAllowed = isAlterAllowed();
757 const Sequence<OUString> aColNames = xColumns->getElementNames();
758 for(const OUString& rColumn : aColNames)
760 Reference<XPropertySet> xColumn;
761 xColumns->getByName(rColumn) >>= xColumn;
762 sal_Int32 nType = 0;
763 sal_Int32 nScale = 0;
764 sal_Int32 nPrecision = 0;
765 sal_Int32 nNullable = 0;
766 sal_Int32 nFormatKey = 0;
767 sal_Int32 nAlign = 0;
769 bool bIsAutoIncrement = false, bIsCurrency = false;
770 OUString sName,sDescription,sTypeName,sHelpText;
771 Any aControlDefault;
773 // get the properties from the column
774 xColumn->getPropertyValue(PROPERTY_NAME) >>= sName;
775 xColumn->getPropertyValue(PROPERTY_TYPENAME) >>= sTypeName;
776 xColumn->getPropertyValue(PROPERTY_ISNULLABLE) >>= nNullable;
777 xColumn->getPropertyValue(PROPERTY_ISAUTOINCREMENT) >>= bIsAutoIncrement;
778 xColumn->getPropertyValue(PROPERTY_ISCURRENCY) >>= bIsCurrency;
779 xColumn->getPropertyValue(PROPERTY_TYPE) >>= nType;
780 xColumn->getPropertyValue(PROPERTY_SCALE) >>= nScale;
781 xColumn->getPropertyValue(PROPERTY_PRECISION) >>= nPrecision;
782 xColumn->getPropertyValue(PROPERTY_DESCRIPTION) >>= sDescription;
784 if(xColumn->getPropertySetInfo()->hasPropertyByName(PROPERTY_HELPTEXT))
785 xColumn->getPropertyValue(PROPERTY_HELPTEXT) >>= sHelpText;
787 if(xColumn->getPropertySetInfo()->hasPropertyByName(PROPERTY_CONTROLDEFAULT))
788 aControlDefault = xColumn->getPropertyValue(PROPERTY_CONTROLDEFAULT);
789 if(xColumn->getPropertySetInfo()->hasPropertyByName(PROPERTY_FORMATKEY))
790 xColumn->getPropertyValue(PROPERTY_FORMATKEY) >>= nFormatKey;
791 if(xColumn->getPropertySetInfo()->hasPropertyByName(PROPERTY_ALIGN))
792 xColumn->getPropertyValue(PROPERTY_ALIGN) >>= nAlign;
794 pTabEdRow = std::make_shared<OTableRow>();
795 pTabEdRow->SetReadOnly(!bIsAlterAllowed);
796 // search for type
797 bool bForce;
798 TOTypeInfoSP pTypeInfo = ::dbaui::getTypeInfoFromType(m_aTypeInfo,nType,sTypeName,"x",nPrecision,nScale,bIsAutoIncrement,bForce);
799 if ( !pTypeInfo )
800 pTypeInfo = m_pTypeInfo;
801 pTabEdRow->SetFieldType( pTypeInfo, bForce );
803 OFieldDescription* pActFieldDescr = pTabEdRow->GetActFieldDescr();
804 OSL_ENSURE(pActFieldDescr, "OTableController::loadData: invalid field description generated by the table row!");
805 if ( pActFieldDescr )
807 pActFieldDescr->SetName(sName);
808 pActFieldDescr->SetFormatKey(nFormatKey);
809 pActFieldDescr->SetDescription(sDescription);
810 pActFieldDescr->SetHelpText(sHelpText);
811 pActFieldDescr->SetAutoIncrement(bIsAutoIncrement);
812 pActFieldDescr->SetHorJustify(dbaui::mapTextJustify(nAlign));
813 pActFieldDescr->SetCurrency(bIsCurrency);
815 // special data
816 pActFieldDescr->SetIsNullable(nNullable);
817 pActFieldDescr->SetControlDefault(aControlDefault);
818 pActFieldDescr->SetPrecision(nPrecision);
819 pActFieldDescr->SetScale(nScale);
821 m_vRowList.push_back( pTabEdRow);
823 // fill the primary key information
824 Reference<XNameAccess> xKeyColumns = getKeyColumns();
825 if(xKeyColumns.is())
827 const Sequence<OUString> aKeyColumnNames = xKeyColumns->getElementNames();
828 for(const OUString& rKeyColumn : aKeyColumnNames)
830 for(std::shared_ptr<OTableRow> const& pRow : m_vRowList)
832 if(pRow->GetActFieldDescr()->GetName() == rKeyColumn)
834 pRow->SetPrimaryKey(true);
835 break;
842 // fill empty rows
844 OTypeInfoMap::const_iterator aTypeIter = m_aTypeInfo.find(DataType::VARCHAR);
845 if(aTypeIter == m_aTypeInfo.end())
846 aTypeIter = m_aTypeInfo.begin();
848 OSL_ENSURE(aTypeIter != m_aTypeInfo.end(),"We have no type information!");
850 bool bReadRow = !isAddAllowed();
851 for(sal_Int32 i=m_vRowList.size(); i < NEWCOLS; i++ )
853 pTabEdRow = std::make_shared<OTableRow>();
854 pTabEdRow->SetReadOnly(bReadRow);
855 m_vRowList.push_back( pTabEdRow);
859 Reference<XNameAccess> OTableController::getKeyColumns() const
861 return getPrimaryKeyColumns_throw(m_xTable);
864 bool OTableController::checkColumns(bool _bNew)
866 bool bOk = true;
867 bool bFoundPKey = false;
868 Reference< XDatabaseMetaData > xMetaData = getMetaData( );
869 DatabaseMetaData aMetaData( getConnection() );
871 ::comphelper::UStringMixEqual bCase(!xMetaData.is() || xMetaData->supportsMixedCaseQuotedIdentifiers());
872 std::vector< std::shared_ptr<OTableRow> >::const_iterator aIter = m_vRowList.begin();
873 std::vector< std::shared_ptr<OTableRow> >::const_iterator aEnd = m_vRowList.end();
874 for(;aIter != aEnd;++aIter)
876 OFieldDescription* pFieldDesc = (*aIter)->GetActFieldDescr();
877 if (pFieldDesc && !pFieldDesc->GetName().isEmpty())
879 bFoundPKey |= (*aIter)->IsPrimaryKey();
880 // first check for duplicate names
881 bool bDuplicateNameFound = std::any_of(aIter+1, aEnd,
882 [&bCase, &pFieldDesc](const std::shared_ptr<OTableRow>& rxRow) {
883 OFieldDescription* pCompareDesc = rxRow->GetActFieldDescr();
884 return pCompareDesc && bCase(pCompareDesc->GetName(),pFieldDesc->GetName());
886 if (bDuplicateNameFound)
888 OUString strMessage = DBA_RES(STR_TABLEDESIGN_DUPLICATE_NAME);
889 strMessage = strMessage.replaceFirst("$column$", pFieldDesc->GetName());
890 OSQLWarningBox aWarning(getFrameWeld(), strMessage);
891 aWarning.run();
892 return false;
896 if ( _bNew && !bFoundPKey && aMetaData.supportsPrimaryKeys() )
898 OUString sTitle(DBA_RES(STR_TABLEDESIGN_NO_PRIM_KEY_HEAD));
899 OUString sMsg(DBA_RES(STR_TABLEDESIGN_NO_PRIM_KEY));
900 OSQLMessageBox aBox(getFrameWeld(), sTitle,sMsg, MessBoxStyle::YesNoCancel | MessBoxStyle::DefaultYes);
902 switch (aBox.run())
904 case RET_YES:
906 auto pNewRow = std::make_shared<OTableRow>();
907 TOTypeInfoSP pTypeInfo = ::dbaui::queryPrimaryKeyType(m_aTypeInfo);
908 if ( !pTypeInfo )
909 break;
911 pNewRow->SetFieldType( pTypeInfo );
912 OFieldDescription* pActFieldDescr = pNewRow->GetActFieldDescr();
914 pActFieldDescr->SetAutoIncrement(false);
915 pActFieldDescr->SetIsNullable(ColumnValue::NO_NULLS);
917 pActFieldDescr->SetName( createUniqueName("ID" ));
918 pActFieldDescr->SetPrimaryKey( true );
919 m_vRowList.insert(m_vRowList.begin(),pNewRow);
921 static_cast<OTableDesignView*>(getView())->GetEditorCtrl()->Invalidate();
922 static_cast<OTableDesignView*>(getView())->GetEditorCtrl()->RowInserted(0);
924 break;
925 case RET_CANCEL:
926 bOk = false;
927 break;
930 return bOk;
933 void OTableController::alterColumns()
935 Reference<XColumnsSupplier> xColSup(m_xTable,UNO_QUERY_THROW);
937 Reference<XNameAccess> xColumns = xColSup->getColumns();
938 Reference<XIndexAccess> xIdxColumns(xColumns,UNO_QUERY_THROW);
939 OSL_ENSURE(xColumns.is(),"No columns");
940 if ( !xColumns.is() )
941 return;
942 Reference<XAlterTable> xAlter(m_xTable,UNO_QUERY); // can be null
944 sal_Int32 nColumnCount = xIdxColumns->getCount();
945 Reference<XDrop> xDrop(xColumns,UNO_QUERY); // can be null
946 Reference<XAppend> xAppend(xColumns,UNO_QUERY); // can be null
947 Reference<XDataDescriptorFactory> xColumnFactory(xColumns,UNO_QUERY); // can be null
949 bool bReload = false; // refresh the data
951 // contains all columns names which are already handled those which are not in the list will be deleted
952 Reference< XDatabaseMetaData> xMetaData = getMetaData( );
954 std::set<OUString, comphelper::UStringMixLess> aColumns(
955 comphelper::UStringMixLess(
956 !xMetaData.is()
957 || xMetaData->supportsMixedCaseQuotedIdentifiers()));
958 std::vector< std::shared_ptr<OTableRow> >::const_iterator aIter = m_vRowList.begin();
959 std::vector< std::shared_ptr<OTableRow> >::const_iterator aEnd = m_vRowList.end();
960 // first look for columns where something other than the name changed
961 for(sal_Int32 nPos = 0;aIter != aEnd;++aIter,++nPos)
963 OSL_ENSURE(*aIter,"OTableRow is null!");
964 OFieldDescription* pField = (*aIter)->GetActFieldDescr();
965 if ( !pField )
966 continue;
967 if ( (*aIter)->IsReadOnly() )
969 aColumns.insert(pField->GetName());
970 continue;
973 Reference<XPropertySet> xColumn;
974 if ( xColumns->hasByName(pField->GetName()) )
976 aColumns.insert(pField->GetName());
977 xColumns->getByName(pField->GetName()) >>= xColumn;
978 OSL_ENSURE(xColumn.is(),"Column is null!");
980 sal_Int32 nType=0,nPrecision=0,nScale=0,nNullable=0;
981 bool bAutoIncrement = false;
982 OUString sTypeName,sDescription;
984 xColumn->getPropertyValue(PROPERTY_TYPE) >>= nType;
985 xColumn->getPropertyValue(PROPERTY_PRECISION) >>= nPrecision;
986 xColumn->getPropertyValue(PROPERTY_SCALE) >>= nScale;
987 xColumn->getPropertyValue(PROPERTY_ISNULLABLE) >>= nNullable;
988 xColumn->getPropertyValue(PROPERTY_ISAUTOINCREMENT) >>= bAutoIncrement;
989 xColumn->getPropertyValue(PROPERTY_DESCRIPTION) >>= sDescription;
991 try { xColumn->getPropertyValue(PROPERTY_TYPENAME) >>= sTypeName; }
992 catch( const Exception& )
994 OSL_FAIL( "no TypeName property?!" );
995 // since this is a last minute fix for #i41785#, I want to be on the safe side,
996 // and catch errors here as early as possible (instead of the whole process of altering
997 // the columns failing)
998 // Normally, sdbcx::Column objects are expected to have a TypeName property
1001 // check if something changed
1002 if((nType != pField->GetType() ||
1003 sTypeName != pField->GetTypeName() ||
1004 (nPrecision != pField->GetPrecision() && nPrecision ) ||
1005 nScale != pField->GetScale() ||
1006 nNullable != pField->GetIsNullable() ||
1007 sDescription != pField->GetDescription() ||
1008 bAutoIncrement != pField->IsAutoIncrement())&&
1009 xColumnFactory.is())
1011 Reference<XPropertySet> xNewColumn = xColumnFactory->createDataDescriptor();
1012 ::dbaui::setColumnProperties(xNewColumn,pField);
1013 // first try to alter the column
1014 bool bNotOk = false;
1017 // first try if we can alter the column
1018 if(xAlter.is())
1019 xAlter->alterColumnByName(pField->GetName(),xNewColumn);
1021 catch(const SQLException&)
1023 if(xDrop.is() && xAppend.is())
1025 OUString aMessage( DBA_RES( STR_TABLEDESIGN_ALTER_ERROR ) );
1026 aMessage = aMessage.replaceFirst( "$column$", pField->GetName() );
1028 SQLExceptionInfo aError( ::cppu::getCaughtException() );
1029 OSQLWarningBox aMsg(getFrameWeld(), aMessage, MessBoxStyle::YesNo | MessBoxStyle::DefaultYes , &aError);
1030 bNotOk = aMsg.run() == RET_YES;
1032 else
1033 throw;
1035 // if something went wrong or we can't alter columns
1036 // drop and append a new one
1037 if((!xAlter.is() || bNotOk) && xDrop.is() && xAppend.is())
1039 xDrop->dropByName(pField->GetName());
1042 xAppend->appendByDescriptor(xNewColumn);
1044 catch(const SQLException&)
1045 { // an error occurred so we try to reactivate the old one
1046 xAppend->appendByDescriptor(xColumn);
1047 throw;
1050 // exceptions are caught outside
1051 xNewColumn = nullptr;
1052 if(xColumns->hasByName(pField->GetName()))
1053 xColumns->getByName(pField->GetName()) >>= xColumn;
1054 bReload = true;
1058 else if(xColumnFactory.is() && xAlter.is() && nPos < nColumnCount)
1059 { // we can't find the column so we could try it with the index before we drop and append a new column
1062 Reference<XPropertySet> xNewColumn = xColumnFactory->createDataDescriptor();
1063 ::dbaui::setColumnProperties(xNewColumn,pField);
1064 xAlter->alterColumnByIndex(nPos,xNewColumn);
1065 if(xColumns->hasByName(pField->GetName()))
1066 { // ask for the append by name
1067 aColumns.insert(pField->GetName());
1068 xColumns->getByName(pField->GetName()) >>= xColumn;
1069 if(xColumn.is())
1070 pField->copyColumnSettingsTo(xColumn);
1072 else
1074 OSL_FAIL("OTableController::alterColumns: invalid column (2)!");
1077 catch(const SQLException&)
1078 { // we couldn't alter the column so we have to add new columns
1079 SQLExceptionInfo aError( ::cppu::getCaughtException() );
1080 bReload = true;
1081 if(xDrop.is() && xAppend.is())
1083 OUString aMessage(DBA_RES(STR_TABLEDESIGN_ALTER_ERROR));
1084 aMessage = aMessage.replaceFirst("$column$",pField->GetName());
1085 OSQLWarningBox aMsg(getFrameWeld(), aMessage, MessBoxStyle::YesNo | MessBoxStyle::DefaultYes, &aError);
1086 if (aMsg.run() != RET_YES)
1088 Reference<XPropertySet> xNewColumn(xIdxColumns->getByIndex(nPos),UNO_QUERY_THROW);
1089 OUString sName;
1090 xNewColumn->getPropertyValue(PROPERTY_NAME) >>= sName;
1091 aColumns.insert(sName);
1092 aColumns.insert(pField->GetName());
1093 continue;
1096 else
1097 throw;
1100 else
1101 bReload = true;
1103 // alter column settings
1105 // first look for columns where something other than the name changed
1106 for (auto const& row : m_vRowList)
1108 OSL_ENSURE(row,"OTableRow is null!");
1109 OFieldDescription* pField = row->GetActFieldDescr();
1110 if ( !pField )
1111 continue;
1112 if ( row->IsReadOnly() )
1114 aColumns.insert(pField->GetName());
1115 continue;
1118 Reference<XPropertySet> xColumn;
1119 if ( xColumns->hasByName(pField->GetName()) )
1121 xColumns->getByName(pField->GetName()) >>= xColumn;
1122 Reference<XPropertySetInfo> xInfo = xColumn->getPropertySetInfo();
1123 if ( xInfo->hasPropertyByName(PROPERTY_HELPTEXT) )
1124 xColumn->setPropertyValue(PROPERTY_HELPTEXT,Any(pField->GetHelpText()));
1126 if(xInfo->hasPropertyByName(PROPERTY_CONTROLDEFAULT))
1127 xColumn->setPropertyValue(PROPERTY_CONTROLDEFAULT,pField->GetControlDefault());
1128 if(xInfo->hasPropertyByName(PROPERTY_FORMATKEY))
1129 xColumn->setPropertyValue(PROPERTY_FORMATKEY,Any(pField->GetFormatKey()));
1130 if(xInfo->hasPropertyByName(PROPERTY_ALIGN))
1131 xColumn->setPropertyValue(PROPERTY_ALIGN,Any(dbaui::mapTextAlign(pField->GetHorJustify())));
1134 // second drop all columns which could be found by name
1135 Reference<XNameAccess> xKeyColumns = getKeyColumns();
1136 // now we have to look for the columns who could be deleted
1137 if ( xDrop.is() )
1139 const Sequence<OUString> aColNames = xColumns->getElementNames();
1140 for(const OUString& rColumnName : aColNames)
1142 if(aColumns.find(rColumnName) == aColumns.end()) // found a column to delete
1144 if(xKeyColumns.is() && xKeyColumns->hasByName(rColumnName)) // check if this column is a member of the primary key
1146 OUString aMsgT(DBA_RES(STR_TBL_COLUMN_IS_KEYCOLUMN));
1147 aMsgT = aMsgT.replaceFirst("$column$",rColumnName);
1148 OUString aTitle(DBA_RES(STR_TBL_COLUMN_IS_KEYCOLUMN_TITLE));
1149 OSQLMessageBox aMsg(getFrameWeld(), aTitle, aMsgT, MessBoxStyle::YesNo| MessBoxStyle::DefaultYes);
1150 if (aMsg.run() == RET_YES)
1152 xKeyColumns = nullptr;
1153 dropPrimaryKey();
1155 else
1157 bReload = true;
1158 continue;
1163 xDrop->dropByName(rColumnName);
1165 catch (const SQLException&)
1167 OUString sError( DBA_RES( STR_TABLEDESIGN_COULD_NOT_DROP_COL ) );
1168 sError = sError.replaceFirst( "$column$", rColumnName );
1170 SQLException aNewException;
1171 aNewException.Message = sError;
1172 aNewException.SQLState = "S1000";
1173 aNewException.NextException = ::cppu::getCaughtException();
1175 throw aNewException;
1181 // third append the new columns
1182 for(const auto& rxRow : m_vRowList)
1184 OSL_ENSURE(rxRow,"OTableRow is null!");
1185 OFieldDescription* pField = rxRow->GetActFieldDescr();
1186 if ( !pField || rxRow->IsReadOnly() || aColumns.find(pField->GetName()) != aColumns.end() )
1187 continue;
1189 Reference<XPropertySet> xColumn;
1190 if(!xColumns->hasByName(pField->GetName()))
1192 if(xColumnFactory.is() && xAppend.is())
1193 {// column not found by its name so we assume it is new
1194 // Column is new
1195 xColumn = xColumnFactory->createDataDescriptor();
1196 ::dbaui::setColumnProperties(xColumn,pField);
1197 xAppend->appendByDescriptor(xColumn);
1198 if(xColumns->hasByName(pField->GetName()))
1199 { // ask for the append by name
1200 aColumns.insert(pField->GetName());
1201 xColumns->getByName(pField->GetName()) >>= xColumn;
1202 if(xColumn.is())
1203 pField->copyColumnSettingsTo(xColumn);
1205 else
1207 OSL_FAIL("OTableController::alterColumns: invalid column!");
1213 // check if we have to do something with the primary key
1214 bool bNeedDropKey = false;
1215 bool bNeedAppendKey = false;
1216 if ( xKeyColumns.is() )
1218 for(const auto& rxRow : m_vRowList)
1220 OSL_ENSURE(rxRow,"OTableRow is null!");
1221 OFieldDescription* pField = rxRow->GetActFieldDescr();
1222 if ( !pField )
1223 continue;
1225 if ( pField->IsPrimaryKey()
1226 && !xKeyColumns->hasByName( pField->GetName() )
1228 { // new primary key column inserted which isn't already in the columns selection
1229 bNeedDropKey = bNeedAppendKey = true;
1230 break;
1232 else if ( !pField->IsPrimaryKey()
1233 && xKeyColumns->hasByName( pField->GetName() )
1235 { // found a column which currently is in the primary key, but is marked not to be anymore
1236 bNeedDropKey = bNeedAppendKey = true;
1237 break;
1241 else
1242 { // no primary key available so we check if we should create one
1243 bNeedAppendKey = true;
1246 if ( bNeedDropKey && xKeyColumns.is() && xKeyColumns->getElementNames().hasElements() )
1247 dropPrimaryKey();
1249 if ( bNeedAppendKey )
1251 Reference< XKeysSupplier > xKeySup( m_xTable, UNO_QUERY );
1252 appendPrimaryKey( xKeySup ,false);
1255 reSyncRows();
1257 if ( bReload )
1258 reload();
1261 void OTableController::dropPrimaryKey()
1263 SQLExceptionInfo aInfo;
1266 Reference<XKeysSupplier> xKeySup(m_xTable,UNO_QUERY);
1267 Reference<XIndexAccess> xKeys;
1268 if(xKeySup.is())
1269 xKeys = xKeySup->getKeys();
1271 if(xKeys.is())
1273 Reference<XPropertySet> xProp;
1274 for(sal_Int32 i=0;i< xKeys->getCount();++i)
1276 xProp.set(xKeys->getByIndex(i),UNO_QUERY);
1277 sal_Int32 nKeyType = 0;
1278 xProp->getPropertyValue(PROPERTY_TYPE) >>= nKeyType;
1279 if(KeyType::PRIMARY == nKeyType)
1281 Reference<XDrop> xDrop(xKeys,UNO_QUERY);
1282 xDrop->dropByIndex(i); // delete the key
1283 break;
1288 catch(const SQLContext& e)
1290 aInfo = SQLExceptionInfo(e);
1292 catch(const SQLWarning& e)
1294 aInfo = SQLExceptionInfo(e);
1296 catch(const SQLException& e)
1298 aInfo = SQLExceptionInfo(e);
1300 catch( const Exception& )
1302 DBG_UNHANDLED_EXCEPTION("dbaccess");
1305 showError(aInfo);
1308 void OTableController::assignTable()
1310 // get the table
1311 if(m_sName.isEmpty())
1312 return;
1314 Reference<XNameAccess> xNameAccess;
1315 Reference<XTablesSupplier> xSup(getConnection(),UNO_QUERY);
1316 if(!xSup.is())
1317 return;
1319 xNameAccess = xSup->getTables();
1320 OSL_ENSURE(xNameAccess.is(),"no nameaccess for the queries!");
1322 if(!xNameAccess->hasByName(m_sName))
1323 return;
1325 Reference<XPropertySet> xProp(xNameAccess->getByName(m_sName), css::uno::UNO_QUERY);
1326 if (!xProp.is())
1327 return;
1329 m_xTable = xProp;
1330 startTableListening();
1332 // check if we set the table editable
1333 Reference<XDatabaseMetaData> xMeta = getConnection()->getMetaData();
1334 setEditable( xMeta.is() && !xMeta->isReadOnly() && (isAlterAllowed() || isDropAllowed() || isAddAllowed()) );
1335 if(!isEditable())
1337 for( const auto& rTableRow : m_vRowList )
1339 rTableRow->SetReadOnly();
1342 m_bNew = false;
1343 // be notified when the table is in disposing
1344 InvalidateAll();
1347 bool OTableController::isAddAllowed() const
1349 Reference<XColumnsSupplier> xColsSup(m_xTable,UNO_QUERY);
1350 bool bAddAllowed = !m_xTable.is();
1351 if(xColsSup.is())
1352 bAddAllowed = Reference<XAppend>(xColsSup->getColumns(),UNO_QUERY).is();
1356 Reference< XDatabaseMetaData > xMetaData = getMetaData( );
1357 bAddAllowed = bAddAllowed || ( xMetaData.is() && xMetaData->supportsAlterTableWithAddColumn());
1359 catch(Exception&)
1361 DBG_UNHANDLED_EXCEPTION("dbaccess");
1362 bAddAllowed = false;
1365 return bAddAllowed;
1368 bool OTableController::isDropAllowed() const
1370 Reference<XColumnsSupplier> xColsSup(m_xTable,UNO_QUERY);
1371 bool bDropAllowed = !m_xTable.is();
1372 if(xColsSup.is())
1374 Reference<XNameAccess> xNameAccess = xColsSup->getColumns();
1375 bDropAllowed = Reference<XDrop>(xNameAccess,UNO_QUERY).is() && xNameAccess->hasElements();
1378 Reference< XDatabaseMetaData> xMetaData = getMetaData( );
1379 bDropAllowed = bDropAllowed || ( xMetaData.is() && xMetaData->supportsAlterTableWithDropColumn());
1381 return bDropAllowed;
1384 bool OTableController::isAlterAllowed() const
1386 bool bAllowed(!m_xTable.is() || Reference<XAlterTable>(m_xTable,UNO_QUERY).is());
1387 return bAllowed;
1390 void OTableController::reSyncRows()
1392 bool bAlterAllowed = isAlterAllowed();
1393 bool bAddAllowed = isAddAllowed();
1394 for (auto const& row : m_vRowList)
1396 OSL_ENSURE(row,"OTableRow is null!");
1397 OFieldDescription* pField = row->GetActFieldDescr();
1398 if ( pField )
1399 row->SetReadOnly(!bAlterAllowed);
1400 else
1401 row->SetReadOnly(!bAddAllowed);
1404 static_cast<OTableDesignView*>(getView())->reSync(); // show the windows and fill with our information
1406 ClearUndoManager();
1407 setModified(false); // and we are not modified yet
1410 OUString OTableController::createUniqueName(const OUString& _rName)
1412 OUString sName = _rName;
1413 Reference< XDatabaseMetaData> xMetaData = getMetaData( );
1415 ::comphelper::UStringMixEqual bCase(!xMetaData.is() || xMetaData->supportsMixedCaseQuotedIdentifiers());
1417 auto lHasName = [&bCase, &sName](const std::shared_ptr<OTableRow>& rxRow) {
1418 OFieldDescription* pFieldDesc = rxRow->GetActFieldDescr();
1419 return pFieldDesc && !pFieldDesc->GetName().isEmpty() && bCase(sName, pFieldDesc->GetName());
1422 sal_Int32 i = 0;
1423 while(std::any_of(m_vRowList.begin(), m_vRowList.end(), lHasName))
1425 // found a second name of _rName so we need another
1426 sName = _rName + OUString::number(++i);
1428 return sName;
1431 OUString OTableController::getPrivateTitle() const
1433 OUString sTitle;
1436 // get the table
1437 if ( !m_sName.isEmpty() && getConnection().is() )
1439 if ( m_xTable.is() )
1440 sTitle = ::dbtools::composeTableName( getConnection()->getMetaData(), m_xTable, ::dbtools::EComposeRule::InDataManipulation, false );
1441 else
1442 sTitle = m_sName;
1444 if ( sTitle.isEmpty() )
1446 OUString aName = DBA_RES(STR_TBL_TITLE);
1447 sTitle = o3tl::getToken(aName,0,' ') + OUString::number(getCurrentStartNumber());
1450 catch( const Exception& )
1452 DBG_UNHANDLED_EXCEPTION("dbaccess");
1454 return sTitle;
1457 void OTableController::reload()
1459 loadData(); // fill the column information from the table
1460 static_cast<OTableDesignView*>(getView())->reSync(); // show the windows and fill with our information
1461 ClearUndoManager();
1462 setModified(false); // and we are not modified yet
1463 static_cast<OTableDesignView*>(getView())->Invalidate();
1466 sal_Int32 OTableController::getFirstEmptyRowPosition()
1468 sal_Int32 nRet = 0;
1469 bool bFoundElem = false;
1470 for (auto const& row : m_vRowList)
1472 if ( !row || !row->GetActFieldDescr() || row->GetActFieldDescr()->GetName().isEmpty() )
1474 bFoundElem = true;
1475 break;
1477 ++nRet;
1479 if (!bFoundElem)
1481 bool bReadRow = !isAddAllowed();
1482 auto pTabEdRow = std::make_shared<OTableRow>();
1483 pTabEdRow->SetReadOnly(bReadRow);
1484 nRet = m_vRowList.size();
1485 m_vRowList.push_back( pTabEdRow);
1487 return nRet;
1490 bool OTableController::isAutoIncrementPrimaryKey() const
1492 return getSdbMetaData().isAutoIncrementPrimaryKey();
1495 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */