bump product version to 4.1.6.2
[LibreOffice.git] / dbaccess / source / ui / tabledesign / TableController.cxx
blob30e737e7947ce14eee3c94bc82eddca4b5f51b31
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 .
21 #include "FieldDescriptions.hxx"
22 #include "TEditControl.hxx"
23 #include "TableController.hxx"
24 #include "TableDesignView.hxx"
25 #include "TableRow.hxx"
26 #include "TypeInfo.hxx"
27 #include "UITools.hxx"
28 #include "browserids.hxx"
29 #include "dbu_reghelper.hxx"
30 #include "dbu_tbl.hrc"
31 #include "dbustrings.hrc"
32 #include "defaultobjectnamecheck.hxx"
33 #include "dlgsave.hxx"
34 #include "dsmeta.hxx"
35 #include "indexdialog.hxx"
36 #include "sqlmessage.hxx"
38 #include <com/sun/star/container/XChild.hpp>
39 #include <com/sun/star/container/XNameContainer.hpp>
40 #include <com/sun/star/frame/FrameSearchFlag.hpp>
41 #include <com/sun/star/frame/XTitleChangeListener.hpp>
42 #include <com/sun/star/frame/XUntitledNumbers.hpp>
43 #include <com/sun/star/io/XActiveDataSink.hpp>
44 #include <com/sun/star/io/XActiveDataSource.hpp>
45 #include <com/sun/star/sdb/CommandType.hpp>
46 #include <com/sun/star/sdb/SQLContext.hpp>
47 #include <com/sun/star/sdbc/ColumnValue.hpp>
48 #include <com/sun/star/sdbc/SQLWarning.hpp>
49 #include <com/sun/star/sdbc/XRow.hpp>
50 #include <com/sun/star/sdbcx/KeyType.hpp>
51 #include <com/sun/star/sdbcx/XAlterTable.hpp>
52 #include <com/sun/star/sdbcx/XAppend.hpp>
53 #include <com/sun/star/sdbcx/XDataDescriptorFactory.hpp>
54 #include <com/sun/star/sdbcx/XDrop.hpp>
55 #include <com/sun/star/sdbcx/XIndexesSupplier.hpp>
56 #include <com/sun/star/sdbcx/XTablesSupplier.hpp>
57 #include <com/sun/star/ui/dialogs/XExecutableDialog.hpp>
59 #include <comphelper/extract.hxx>
60 #include <comphelper/processfactory.hxx>
61 #include <comphelper/streamsection.hxx>
62 #include <comphelper/types.hxx>
63 #include <connectivity/dbexception.hxx>
64 #include <connectivity/dbtools.hxx>
65 #include <connectivity/dbmetadata.hxx>
66 #include <cppuhelper/exc_hlp.hxx>
67 #include <sfx2/sfxsids.hrc>
68 #include <tools/diagnose_ex.h>
69 #include <tools/string.hxx>
70 #include <vcl/msgbox.hxx>
72 #include <boost/mem_fn.hpp>
73 #include <boost/bind.hpp>
75 #include <algorithm>
76 #include <functional>
78 extern "C" void SAL_CALL createRegistryInfo_OTableControl()
80 static ::dbaui::OMultiInstanceAutoRegistration< ::dbaui::OTableController > aAutoRegistration;
83 using namespace ::com::sun::star;
84 using namespace ::com::sun::star::uno;
85 using namespace ::com::sun::star::io;
86 using namespace ::com::sun::star::beans;
87 using namespace ::com::sun::star::frame;
88 using namespace ::com::sun::star::lang;
89 using namespace ::com::sun::star::container;
90 using namespace ::com::sun::star::sdbcx;
91 using namespace ::com::sun::star::sdbc;
92 using namespace ::com::sun::star::sdb;
93 using namespace ::com::sun::star::ui;
94 using namespace ::com::sun::star::util;
95 using namespace ::dbtools;
96 using namespace ::dbaui;
97 using namespace ::comphelper;
99 // Anzahl Spalten beim Neuanlegen
100 #define NEWCOLS 128
102 namespace
104 void dropTable(const Reference<XNameAccess>& _rxTable,const OUString& _sTableName)
106 if ( _rxTable->hasByName(_sTableName) )
108 Reference<XDrop> xNameCont(_rxTable,UNO_QUERY);
109 OSL_ENSURE(xNameCont.is(),"No drop interface for tables!");
110 if ( xNameCont.is() )
111 xNameCont->dropByName(_sTableName);
114 //------------------------------------------------------------------------------
115 struct OTableRowCompare : public ::std::binary_function< ::boost::shared_ptr<OTableRow> , OUString, bool>
117 bool operator() (const ::boost::shared_ptr<OTableRow> lhs, const OUString& rhs) const
119 OFieldDescription* pField = lhs->GetActFieldDescr();
120 return pField && pField->GetName() == rhs;
126 //------------------------------------------------------------------------------
127 OUString SAL_CALL OTableController::getImplementationName() throw( RuntimeException )
129 return getImplementationName_Static();
132 //------------------------------------------------------------------------------
133 OUString OTableController::getImplementationName_Static() throw( RuntimeException )
135 return OUString("org.openoffice.comp.dbu.OTableDesign");
137 //------------------------------------------------------------------------------
138 Sequence< OUString> OTableController::getSupportedServiceNames_Static(void) throw( RuntimeException )
140 Sequence< OUString> aSupported(1);
141 aSupported.getArray()[0] = OUString("com.sun.star.sdb.TableDesign");
142 return aSupported;
144 //-------------------------------------------------------------------------
145 Sequence< OUString> SAL_CALL OTableController::getSupportedServiceNames() throw(RuntimeException)
147 return getSupportedServiceNames_Static();
149 // -------------------------------------------------------------------------
150 Reference< XInterface > SAL_CALL OTableController::Create(const Reference<XMultiServiceFactory >& _rxFactory)
152 return *(new OTableController(comphelper::getComponentContext(_rxFactory)));
155 DBG_NAME(OTableController)
156 // -----------------------------------------------------------------------------
157 OTableController::OTableController(const Reference< XComponentContext >& _rM) : OTableController_BASE(_rM)
158 ,m_sTypeNames(ModuleRes(STR_TABLEDESIGN_DBFIELDTYPES))
159 ,m_pTypeInfo()
160 ,m_bAllowAutoIncrementValue(sal_False)
161 ,m_bNew(sal_True)
163 DBG_CTOR(OTableController,NULL);
165 InvalidateAll();
166 m_pTypeInfo = TOTypeInfoSP(new OTypeInfo());
167 m_pTypeInfo->aUIName = m_sTypeNames.GetToken(TYPE_OTHER);
169 // -----------------------------------------------------------------------------
170 OTableController::~OTableController()
172 m_aTypeInfoIndex.clear();
173 m_aTypeInfo.clear();
175 DBG_DTOR(OTableController,NULL);
178 // -----------------------------------------------------------------------------
179 void OTableController::startTableListening()
181 Reference< XComponent > xComponent(m_xTable, UNO_QUERY);
182 if (xComponent.is())
183 xComponent->addEventListener(static_cast<XModifyListener*>(this));
186 // -----------------------------------------------------------------------------
187 void OTableController::stopTableListening()
189 Reference< XComponent > xComponent(m_xTable, UNO_QUERY);
190 if (xComponent.is())
191 xComponent->removeEventListener(static_cast<XModifyListener*>(this));
194 // -----------------------------------------------------------------------------
195 void OTableController::disposing()
197 OTableController_BASE::disposing();
198 clearView();
200 m_vRowList.clear();
202 // -----------------------------------------------------------------------------
203 FeatureState OTableController::GetState(sal_uInt16 _nId) const
205 FeatureState aReturn;
206 // (disabled automatically)
208 switch (_nId)
210 case ID_BROWSER_CLOSE:
211 aReturn.bEnabled = sal_True;
212 break;
213 case ID_BROWSER_EDITDOC:
214 aReturn.bChecked = isEditable();
215 aReturn.bEnabled = m_bNew || isEditable();// the editable flag is set through this one -> || isAddAllowed() || isDropAllowed() || isAlterAllowed();
216 break;
217 case ID_BROWSER_SAVEDOC:
218 aReturn.bEnabled = impl_isModified();
219 if ( aReturn.bEnabled )
221 ::std::vector< ::boost::shared_ptr<OTableRow> >::const_iterator aIter = ::std::find_if(m_vRowList.begin(),m_vRowList.end(),
222 ::boost::mem_fn(&OTableRow::isValid));
223 aReturn.bEnabled = aIter != m_vRowList.end();
225 break;
226 case ID_BROWSER_SAVEASDOC:
227 aReturn.bEnabled = isConnected() && isEditable();
228 if ( aReturn.bEnabled )
230 ::std::vector< ::boost::shared_ptr<OTableRow> >::const_iterator aIter = ::std::find_if(m_vRowList.begin(),m_vRowList.end(),
231 ::boost::mem_fn(&OTableRow::isValid));
232 aReturn.bEnabled = aIter != m_vRowList.end();
234 break;
236 case ID_BROWSER_CUT:
237 aReturn.bEnabled = isEditable() && m_aCurrentFrame.isActive() && getView() && static_cast<OTableDesignView*>(getView())->isCutAllowed();
238 break;
239 case ID_BROWSER_COPY:
240 aReturn.bEnabled = m_aCurrentFrame.isActive() && getView() && static_cast<OTableDesignView*>(getView())->isCopyAllowed();
241 break;
242 case ID_BROWSER_PASTE:
243 aReturn.bEnabled = isEditable() && m_aCurrentFrame.isActive() && getView() && static_cast<OTableDesignView*>(getView())->isPasteAllowed();
244 break;
245 case SID_INDEXDESIGN:
246 aReturn.bEnabled =
247 ( ( ((!m_bNew && impl_isModified()) || impl_isModified())
248 || Reference< XIndexesSupplier >(m_xTable, UNO_QUERY).is()
250 && isConnected()
252 if ( aReturn.bEnabled )
254 ::std::vector< ::boost::shared_ptr<OTableRow> >::const_iterator aIter = ::std::find_if(m_vRowList.begin(),m_vRowList.end(),
255 ::boost::mem_fn(&OTableRow::isValid));
256 aReturn.bEnabled = aIter != m_vRowList.end();
258 break;
259 default:
260 aReturn = OTableController_BASE::GetState(_nId);
262 return aReturn;
264 // -----------------------------------------------------------------------------
265 void OTableController::Execute(sal_uInt16 _nId, const Sequence< PropertyValue >& aArgs)
267 switch(_nId)
269 case ID_BROWSER_EDITDOC:
270 setEditable(!isEditable());
271 static_cast<OTableDesignView*>(getView())->setReadOnly(!isEditable());
272 InvalidateFeature(ID_BROWSER_PASTE);
273 InvalidateFeature(SID_BROWSER_CLEAR_QUERY);
274 break;
275 case ID_BROWSER_SAVEASDOC:
276 doSaveDoc(sal_True);
277 break;
278 case ID_BROWSER_SAVEDOC:
279 static_cast<OTableDesignView*>(getView())->GetEditorCtrl()->SaveCurRow();
280 doSaveDoc(sal_False);
281 break;
282 case ID_BROWSER_CUT:
283 static_cast<OTableDesignView*>(getView())->cut();
284 break;
285 case ID_BROWSER_COPY:
286 static_cast<OTableDesignView*>(getView())->copy();
287 break;
288 case ID_BROWSER_PASTE:
289 static_cast<OTableDesignView*>(getView())->paste();
290 break;
291 case SID_INDEXDESIGN:
292 doEditIndexes();
293 break;
294 default:
295 OTableController_BASE::Execute(_nId,aArgs);
297 InvalidateFeature(_nId);
300 // -----------------------------------------------------------------------------
301 sal_Bool OTableController::doSaveDoc(sal_Bool _bSaveAs)
303 if (!isConnected())
304 reconnect(sal_True); // ask the user for a new connection
305 Reference<XTablesSupplier> xTablesSup(getConnection(),UNO_QUERY);
307 if (!xTablesSup.is())
309 String aMessage(ModuleRes(STR_TABLEDESIGN_CONNECTION_MISSING));
310 OSQLWarningBox( getView(), aMessage ).Execute();
311 return sal_False;
314 // check if a column exists
315 // TODO
317 Reference<XNameAccess> xTables;
318 OUString sCatalog, sSchema;
320 sal_Bool bNew = m_sName.isEmpty();
321 bNew = bNew || m_bNew || _bSaveAs;
325 xTables = xTablesSup->getTables();
326 OSL_ENSURE(xTables.is(),"The tables can't be null!");
327 bNew = bNew || (xTables.is() && !xTables->hasByName(m_sName));
329 // first we need a name for our query so ask the user
330 if(bNew)
332 String aDefaultName;
333 if (_bSaveAs && !bNew)
334 aDefaultName = String(m_sName);
335 else
337 String aName = String(ModuleRes(STR_TBL_TITLE));
338 aDefaultName = aName.GetToken(0,' ');
339 aDefaultName = ::dbtools::createUniqueName(xTables,aDefaultName);
342 DynamicTableOrQueryNameCheck aNameChecker( getConnection(), CommandType::TABLE );
343 OSaveAsDlg aDlg( getView(), CommandType::TABLE, getORB(), getConnection(), aDefaultName, aNameChecker );
344 if ( aDlg.Execute() != RET_OK )
345 return sal_False;
347 m_sName = aDlg.getName();
348 sCatalog = aDlg.getCatalog();
349 sSchema = aDlg.getSchema();
352 // did we get a name
353 if(m_sName.isEmpty())
354 return sal_False;
356 catch(Exception&)
358 OSL_FAIL("OTableController::doSaveDoc: nothing is expected to happen here!");
361 sal_Bool bAlter = sal_False;
362 sal_Bool bError = sal_False;
363 SQLExceptionInfo aInfo;
366 // check the columns for double names
367 if(!checkColumns(bNew || !xTables->hasByName(m_sName)))
369 return sal_False;
372 Reference<XPropertySet> xTable;
373 if(bNew || !xTables->hasByName(m_sName)) // just to make sure the table already exists
375 dropTable(xTables,m_sName);
377 Reference<XDataDescriptorFactory> xFact(xTables,UNO_QUERY);
378 OSL_ENSURE(xFact.is(),"OTableController::doSaveDoc: No XDataDescriptorFactory available!");
379 xTable = xFact->createDataDescriptor();
380 OSL_ENSURE(xTable.is(),"OTableController::doSaveDoc: Create query failed!");
381 // to set the name is only allowed when the wuery is new
382 xTable->setPropertyValue(PROPERTY_CATALOGNAME,makeAny(sCatalog));
383 xTable->setPropertyValue(PROPERTY_SCHEMANAME,makeAny(sSchema));
384 xTable->setPropertyValue(PROPERTY_NAME,makeAny(m_sName));
386 // now append the columns
387 Reference<XColumnsSupplier> xColSup(xTable,UNO_QUERY);
388 appendColumns(xColSup,bNew);
389 // now append the primary key
390 Reference<XKeysSupplier> xKeySup(xTable,UNO_QUERY);
391 appendPrimaryKey(xKeySup,bNew);
393 // now set the properties
394 if(bNew)
396 Reference<XAppend> xAppend(xTables,UNO_QUERY);
397 OSL_ENSURE(xAppend.is(),"OTableController::doSaveDoc: No XAppend Interface!");
398 xAppend->appendByDescriptor(xTable);
400 assignTable();
401 if(!m_xTable.is()) // correct name and try again
403 // it can be that someone inserted new data for us
404 m_sName = ::dbtools::composeTableName( getConnection()->getMetaData(), xTable, ::dbtools::eInDataManipulation, false, false, false );
405 assignTable();
407 // now check if our datasource has set a tablefilter and if append the new table name to it
408 ::dbaui::appendToFilter(getConnection(),m_sName,getORB(),getView()); // we are not interessted in the return value
409 Reference< frame::XTitleChangeListener> xEventListener(impl_getTitleHelper_throw(),UNO_QUERY);
410 if ( xEventListener.is() )
412 frame::TitleChangedEvent aEvent;
413 xEventListener->titleChanged(aEvent);
415 releaseNumberForComponent();
417 else if(m_xTable.is())
419 bAlter = sal_True;
420 alterColumns();
422 reSyncRows();
424 catch(const SQLContext& e)
426 aInfo = SQLExceptionInfo(e);
428 catch(const SQLWarning& e)
430 aInfo = SQLExceptionInfo(e);
432 catch(const SQLException& e)
434 aInfo = SQLExceptionInfo(e);
436 catch(const ElementExistException& )
438 String sText( ModuleRes( STR_NAME_ALREADY_EXISTS ) );
439 sText.SearchAndReplaceAscii( "#" , m_sName);
440 OSQLMessageBox aDlg( getView(), String( ModuleRes( STR_ERROR_DURING_CREATION ) ), sText, WB_OK, OSQLMessageBox::Error );
442 aDlg.Execute();
443 bError = sal_True;
445 catch( const Exception& )
447 bError = sal_True;
448 DBG_UNHANDLED_EXCEPTION();
451 if ( aInfo.isValid() )
452 aInfo.prepend( String( ModuleRes( STR_TABLEDESIGN_SAVE_ERROR ) ) );
453 showError(aInfo);
455 if (aInfo.isValid() || bError)
457 if(!bAlter || bNew)
459 m_sName = OUString();
460 stopTableListening();
461 m_xTable = NULL;
464 return ! (aInfo.isValid() || bError);
467 // -----------------------------------------------------------------------------
468 void OTableController::doEditIndexes()
470 // table needs to be saved before editing indexes
471 if (m_bNew || isModified())
473 QueryBox aAsk(getView(), ModuleRes(QUERY_SAVE_TABLE_EDIT_INDEXES));
474 if (RET_YES != aAsk.Execute())
475 return;
477 if (!doSaveDoc(sal_False))
478 return;
480 OSL_ENSURE(!m_bNew && !isModified(), "OTableController::doEditIndexes: what the hell did doSaveDoc do?");
483 Reference< XNameAccess > xIndexes; // will be the keys of the table
484 Sequence< OUString > aFieldNames; // will be the column names of the table
487 // get the keys
488 Reference< XIndexesSupplier > xIndexesSupp(m_xTable, UNO_QUERY);
489 if (xIndexesSupp.is())
491 xIndexes = xIndexesSupp->getIndexes();
492 OSL_ENSURE(xIndexes.is(), "OTableController::doEditIndexes: no keys got from the indexes supplier!");
494 else
495 OSL_FAIL("OTableController::doEditIndexes: should never have reached this (no indexes supplier)!");
497 // get the field names
498 Reference< XColumnsSupplier > xColSupp(m_xTable, UNO_QUERY);
499 OSL_ENSURE(xColSupp.is(), "OTableController::doEditIndexes: no columns supplier!");
500 if (xColSupp.is())
502 Reference< XNameAccess > xCols = xColSupp->getColumns();
503 OSL_ENSURE(xCols.is(), "OTableController::doEditIndexes: no columns!");
504 if (xCols.is())
505 aFieldNames = xCols->getElementNames();
508 catch( const Exception& )
510 DBG_UNHANDLED_EXCEPTION();
513 if (!xIndexes.is())
514 return;
516 DbaIndexDialog aDialog(getView(), aFieldNames, xIndexes, getConnection(), getORB(), isConnected() ? getConnection()->getMetaData().is() && getConnection()->getMetaData()->getMaxColumnsInIndex() : sal_Int32(0));
517 if (RET_OK != aDialog.Execute())
518 return;
522 // -----------------------------------------------------------------------------
523 void OTableController::impl_initialize()
527 OTableController_BASE::impl_initialize();
529 const NamedValueCollection& rArguments( getInitParams() );
531 rArguments.get_ensureType( (OUString)PROPERTY_CURRENTTABLE, m_sName );
533 // read autoincrement value set in the datasource
534 ::dbaui::fillAutoIncrementValue(getDataSource(),m_bAllowAutoIncrementValue,m_sAutoIncrementValue);
536 assignTable();
538 catch( const Exception& )
540 DBG_UNHANDLED_EXCEPTION();
545 ::dbaui::fillTypeInfo(getConnection(),m_sTypeNames,m_aTypeInfo,m_aTypeInfoIndex); // fill the needed type information
547 catch(const SQLException&)
549 OSQLWarningBox( getView(), ModuleRes( STR_NO_TYPE_INFO_AVAILABLE ) ).Execute();
550 throw;
554 loadData(); // fill the column information form the table
555 getView()->initialize(); // show the windows and fill with our information
556 ClearUndoManager();
557 setModified(sal_False); // and we are not modified yet
559 catch( const Exception& )
561 DBG_UNHANDLED_EXCEPTION();
564 // -----------------------------------------------------------------------------
565 sal_Bool OTableController::Construct(Window* pParent)
567 setView( * new OTableDesignView( pParent, getORB(), *this ) );
568 OTableController_BASE::Construct(pParent);
569 return sal_True;
571 // -----------------------------------------------------------------------------
572 sal_Bool SAL_CALL OTableController::suspend(sal_Bool /*_bSuspend*/) throw( RuntimeException )
574 if ( getBroadcastHelper().bInDispose || getBroadcastHelper().bDisposed )
575 return sal_True;
577 SolarMutexGuard aSolarGuard;
578 ::osl::MutexGuard aGuard( getMutex() );
579 if ( getView() && getView()->IsInModalMode() )
580 return sal_False;
581 if ( getView() )
582 static_cast<OTableDesignView*>(getView())->GrabFocus();
583 sal_Bool bCheck = sal_True;
584 if ( isModified() )
586 ::std::vector< ::boost::shared_ptr<OTableRow> >::iterator aIter = ::std::find_if(m_vRowList.begin(),m_vRowList.end(),
587 ::boost::mem_fn(&OTableRow::isValid));
588 if ( aIter != m_vRowList.end() )
590 QueryBox aQry(getView(), ModuleRes(TABLE_DESIGN_SAVEMODIFIED));
591 switch (aQry.Execute())
593 case RET_YES:
594 Execute(ID_BROWSER_SAVEDOC,Sequence<PropertyValue>());
595 if ( isModified() )
596 bCheck = sal_False; // when we save the table this must be false else some press cancel
597 break;
598 case RET_CANCEL:
599 bCheck = sal_False;
600 default:
601 break;
604 else if ( !m_bNew )
606 QueryBox aQry(getView(), ModuleRes(TABLE_DESIGN_ALL_ROWS_DELETED));
607 switch (aQry.Execute())
609 case RET_YES:
613 Reference<XTablesSupplier> xTablesSup(getConnection(),UNO_QUERY);
614 Reference<XNameAccess> xTables = xTablesSup->getTables();
615 dropTable(xTables,m_sName);
617 catch(const Exception&)
619 OSL_FAIL("OTableController::suspend: nothing is expected to happen here!");
623 break;
624 case RET_CANCEL:
625 bCheck = sal_False;
626 default:
627 break;
632 return bCheck;
634 // -----------------------------------------------------------------------------
635 void OTableController::describeSupportedFeatures()
637 OSingleDocumentController::describeSupportedFeatures();
639 implDescribeSupportedFeature( ".uno:Redo", ID_BROWSER_REDO, CommandGroup::EDIT );
640 implDescribeSupportedFeature( ".uno:Save", ID_BROWSER_SAVEDOC, CommandGroup::EDIT );
641 implDescribeSupportedFeature( ".uno:Undo", ID_BROWSER_UNDO, CommandGroup::EDIT );
642 implDescribeSupportedFeature( ".uno:HelpMenu", SID_HELPMENU, CommandGroup::APPLICATION );
643 implDescribeSupportedFeature( ".uno:NewDoc", SID_NEWDOC, CommandGroup::DOCUMENT );
644 implDescribeSupportedFeature( ".uno:SaveAs", ID_BROWSER_SAVEASDOC, CommandGroup::DOCUMENT );
645 implDescribeSupportedFeature( ".uno:DBIndexDesign", SID_INDEXDESIGN, CommandGroup::APPLICATION );
646 implDescribeSupportedFeature( ".uno:EditDoc", ID_BROWSER_EDITDOC, CommandGroup::EDIT );
648 // -----------------------------------------------------------------------------
649 void OTableController::impl_onModifyChanged()
651 OSingleDocumentController::impl_onModifyChanged();
652 InvalidateFeature( SID_INDEXDESIGN );
654 // -----------------------------------------------------------------------------
655 void SAL_CALL OTableController::disposing( const EventObject& _rSource ) throw(RuntimeException)
657 if ( _rSource.Source == m_xTable )
658 { // some deleted our table so we have a new one
659 stopTableListening();
660 m_xTable = NULL;
661 m_bNew = sal_True;
662 setModified(sal_True);
664 else
665 OTableController_BASE::disposing( _rSource );
667 // -----------------------------------------------------------------------------
668 void OTableController::Save(const Reference< XObjectOutputStream>& _rxOut)
670 OStreamSection aSection(_rxOut.get());
673 // -----------------------------------------------------------------------------
674 void OTableController::Load(const Reference< XObjectInputStream>& _rxIn)
676 OStreamSection aSection(_rxIn.get());
679 // -----------------------------------------------------------------------------
680 void OTableController::losingConnection( )
682 // let the base class do it's reconnect
683 OTableController_BASE::losingConnection( );
685 // remove from the table
686 Reference< XComponent > xComponent(m_xTable, UNO_QUERY);
687 if (xComponent.is())
689 Reference<XEventListener> xEvtL( static_cast< ::cppu::OWeakObject*>(this), UNO_QUERY);
690 xComponent->removeEventListener(xEvtL);
692 stopTableListening();
693 m_xTable = NULL;
694 assignTable();
695 if(!m_xTable.is())
697 m_bNew = sal_True;
698 setModified(sal_True);
700 InvalidateAll();
702 // -----------------------------------------------------------------------------
703 TOTypeInfoSP OTableController::getTypeInfoByType(sal_Int32 _nDataType) const
705 return queryTypeInfoByType(_nDataType,m_aTypeInfo);
707 // -----------------------------------------------------------------------------
708 void OTableController::appendColumns(Reference<XColumnsSupplier>& _rxColSup,sal_Bool _bNew,sal_Bool _bKeyColumns)
712 // now append the columns
713 OSL_ENSURE(_rxColSup.is(),"No columns supplier");
714 if(!_rxColSup.is())
715 return;
716 Reference<XNameAccess> xColumns = _rxColSup->getColumns();
717 OSL_ENSURE(xColumns.is(),"No columns");
718 Reference<XDataDescriptorFactory> xColumnFactory(xColumns,UNO_QUERY);
720 Reference<XAppend> xAppend(xColumns,UNO_QUERY);
721 OSL_ENSURE(xAppend.is(),"No XAppend Interface!");
723 ::std::vector< ::boost::shared_ptr<OTableRow> >::iterator aIter = m_vRowList.begin();
724 ::std::vector< ::boost::shared_ptr<OTableRow> >::iterator aEnd = m_vRowList.end();
725 for(;aIter != aEnd;++aIter)
727 OSL_ENSURE(*aIter,"OTableRow is null!");
728 OFieldDescription* pField = (*aIter)->GetActFieldDescr();
729 if ( !pField || (!_bNew && (*aIter)->IsReadOnly() && !_bKeyColumns) )
730 continue;
732 Reference<XPropertySet> xColumn;
733 if(pField->IsPrimaryKey() || !_bKeyColumns)
734 xColumn = xColumnFactory->createDataDescriptor();
735 if(xColumn.is())
737 if(!_bKeyColumns)
738 ::dbaui::setColumnProperties(xColumn,pField);
739 else
740 xColumn->setPropertyValue(PROPERTY_NAME,makeAny(pField->GetName()));
742 xAppend->appendByDescriptor(xColumn);
743 xColumn = NULL;
744 // now only the settings are missing
745 if(xColumns->hasByName(pField->GetName()))
747 xColumns->getByName(pField->GetName()) >>= xColumn;
748 if(xColumn.is())
749 pField->copyColumnSettingsTo(xColumn);
751 else
753 OSL_FAIL("OTableController::appendColumns: invalid field name!");
759 catch(const SQLException& )
761 showError( SQLExceptionInfo( ::cppu::getCaughtException() ) );
763 catch( const Exception& )
765 DBG_UNHANDLED_EXCEPTION();
768 // -----------------------------------------------------------------------------
769 void OTableController::appendPrimaryKey(Reference<XKeysSupplier>& _rxSup,sal_Bool _bNew)
771 if(!_rxSup.is())
772 return; // the database doesn't support keys
774 OSL_ENSURE(_rxSup.is(),"No XKeysSupplier!");
775 Reference<XIndexAccess> xKeys(_rxSup->getKeys(),UNO_QUERY);
776 Reference<XPropertySet> xProp;
777 const sal_Int32 nCount = xKeys->getCount();
778 for(sal_Int32 i=0;i< nCount ;++i)
780 xKeys->getByIndex(i) >>= xProp;
781 sal_Int32 nKeyType = 0;
782 xProp->getPropertyValue(PROPERTY_TYPE) >>= nKeyType;
783 if(KeyType::PRIMARY == nKeyType)
785 return; // primary key already exists after appending a column
788 Reference<XDataDescriptorFactory> xKeyFactory(xKeys,UNO_QUERY);
789 OSL_ENSURE(xKeyFactory.is(),"No XDataDescriptorFactory Interface!");
790 if ( !xKeyFactory.is() )
791 return;
792 Reference<XAppend> xAppend(xKeyFactory,UNO_QUERY);
793 OSL_ENSURE(xAppend.is(),"No XAppend Interface!");
795 Reference<XPropertySet> xKey = xKeyFactory->createDataDescriptor();
796 OSL_ENSURE(xKey.is(),"Key is null!");
797 xKey->setPropertyValue(PROPERTY_TYPE,makeAny(KeyType::PRIMARY));
799 Reference<XColumnsSupplier> xColSup(xKey,UNO_QUERY);
800 if(xColSup.is())
802 appendColumns(xColSup,_bNew,sal_True);
803 Reference<XNameAccess> xColumns = xColSup->getColumns();
804 if(xColumns->hasElements())
805 xAppend->appendByDescriptor(xKey);
808 // -----------------------------------------------------------------------------
809 void OTableController::loadData()
811 //////////////////////////////////////////////////////////////////////
812 // Wenn Datenstruktur bereits vorhanden, Struktur leeren
813 m_vRowList.clear();
815 ::boost::shared_ptr<OTableRow> pTabEdRow;
816 Reference< XDatabaseMetaData> xMetaData = getMetaData( );
817 //////////////////////////////////////////////////////////////////////
818 // Datenstruktur mit Daten aus DatenDefinitionsObjekt fuellen
819 if(m_xTable.is() && xMetaData.is())
821 Reference<XColumnsSupplier> xColSup(m_xTable,UNO_QUERY);
822 OSL_ENSURE(xColSup.is(),"No XColumnsSupplier!");
823 Reference<XNameAccess> xColumns = xColSup->getColumns();
824 OFieldDescription* pActFieldDescr = NULL;
825 //////////////////////////////////////////////////////////////////////
826 // ReadOnly-Flag
827 // Bei Drop darf keine Zeile editierbar sein.
828 // Bei Add duerfen nur die leeren Zeilen editierbar sein.
829 // Bei Add und Drop koennen alle Zeilen editiert werden.
830 // sal_Bool bReadOldRow = xMetaData->supportsAlterTableWithAddColumn() && xMetaData->supportsAlterTableWithDropColumn();
831 sal_Bool bIsAlterAllowed = isAlterAllowed();
832 Sequence< OUString> aColumns = xColumns->getElementNames();
833 const OUString* pIter = aColumns.getConstArray();
834 const OUString* pEnd = pIter + aColumns.getLength();
836 for(;pIter != pEnd;++pIter)
838 Reference<XPropertySet> xColumn;
839 xColumns->getByName(*pIter) >>= xColumn;
840 sal_Int32 nType = 0;
841 sal_Int32 nScale = 0;
842 sal_Int32 nPrecision = 0;
843 sal_Int32 nNullable = 0;
844 sal_Int32 nFormatKey = 0;
845 sal_Int32 nAlign = 0;
847 sal_Bool bIsAutoIncrement = false, bIsCurrency = false;
848 OUString sName,sDescription,sTypeName,sHelpText;
849 Any aControlDefault;
851 // get the properties from the column
852 xColumn->getPropertyValue(PROPERTY_NAME) >>= sName;
853 xColumn->getPropertyValue(PROPERTY_TYPENAME) >>= sTypeName;
854 xColumn->getPropertyValue(PROPERTY_ISNULLABLE) >>= nNullable;
855 xColumn->getPropertyValue(PROPERTY_ISAUTOINCREMENT) >>= bIsAutoIncrement;
856 xColumn->getPropertyValue(PROPERTY_ISCURRENCY) >>= bIsCurrency;
857 xColumn->getPropertyValue(PROPERTY_TYPE) >>= nType;
858 xColumn->getPropertyValue(PROPERTY_SCALE) >>= nScale;
859 xColumn->getPropertyValue(PROPERTY_PRECISION) >>= nPrecision;
860 xColumn->getPropertyValue(PROPERTY_DESCRIPTION) >>= sDescription;
862 if(xColumn->getPropertySetInfo()->hasPropertyByName(PROPERTY_HELPTEXT))
863 xColumn->getPropertyValue(PROPERTY_HELPTEXT) >>= sHelpText;
865 if(xColumn->getPropertySetInfo()->hasPropertyByName(PROPERTY_CONTROLDEFAULT))
866 aControlDefault = xColumn->getPropertyValue(PROPERTY_CONTROLDEFAULT);
867 if(xColumn->getPropertySetInfo()->hasPropertyByName(PROPERTY_FORMATKEY))
868 xColumn->getPropertyValue(PROPERTY_FORMATKEY) >>= nFormatKey;
869 if(xColumn->getPropertySetInfo()->hasPropertyByName(PROPERTY_ALIGN))
870 xColumn->getPropertyValue(PROPERTY_ALIGN) >>= nAlign;
872 pTabEdRow.reset(new OTableRow());
873 pTabEdRow->SetReadOnly(!bIsAlterAllowed);
874 // search for type
875 sal_Bool bForce;
876 OUString sCreate("x");
877 TOTypeInfoSP pTypeInfo = ::dbaui::getTypeInfoFromType(m_aTypeInfo,nType,sTypeName,sCreate,nPrecision,nScale,bIsAutoIncrement,bForce);
878 if ( !pTypeInfo.get() )
879 pTypeInfo = m_pTypeInfo;
880 pTabEdRow->SetFieldType( pTypeInfo, bForce );
882 pActFieldDescr = pTabEdRow->GetActFieldDescr();
883 OSL_ENSURE(pActFieldDescr, "OTableController::loadData: invalid field description generated by the table row!");
884 if ( pActFieldDescr )
886 pActFieldDescr->SetName(sName);
887 pActFieldDescr->SetFormatKey(nFormatKey);
888 pActFieldDescr->SetDescription(sDescription);
889 pActFieldDescr->SetHelpText(sHelpText);
890 pActFieldDescr->SetAutoIncrement(bIsAutoIncrement);
891 pActFieldDescr->SetHorJustify(dbaui::mapTextJustify(nAlign));
892 pActFieldDescr->SetCurrency(bIsCurrency);
894 //////////////////////////////////////////////////////////////////////
895 // Spezielle Daten
896 pActFieldDescr->SetIsNullable(nNullable);
897 pActFieldDescr->SetControlDefault(aControlDefault);
898 pActFieldDescr->SetPrecision(nPrecision);
899 pActFieldDescr->SetScale(nScale);
901 m_vRowList.push_back( pTabEdRow);
903 // fill the primary key information
904 Reference<XNameAccess> xKeyColumns = getKeyColumns();
905 if(xKeyColumns.is())
907 Sequence< OUString> aKeyColumns = xKeyColumns->getElementNames();
908 const OUString* pKeyBegin = aKeyColumns.getConstArray();
909 const OUString* pKeyEnd = pKeyBegin + aKeyColumns.getLength();
911 for(;pKeyBegin != pKeyEnd;++pKeyBegin)
913 ::std::vector< ::boost::shared_ptr<OTableRow> >::iterator rowIter = m_vRowList.begin();
914 ::std::vector< ::boost::shared_ptr<OTableRow> >::iterator rowEnd = m_vRowList.end();
915 for(;rowIter != rowEnd;++rowIter)
917 if((*rowIter)->GetActFieldDescr()->GetName() == *pKeyBegin)
919 (*rowIter)->SetPrimaryKey(sal_True);
920 break;
927 //////////////////////////////////////////////////////////////////////
928 // Leere Zeilen fuellen
930 OTypeInfoMap::iterator aTypeIter = m_aTypeInfo.find(DataType::VARCHAR);
931 if(aTypeIter == m_aTypeInfo.end())
932 aTypeIter = m_aTypeInfo.begin();
934 OSL_ENSURE(aTypeIter != m_aTypeInfo.end(),"We have no type information!");
936 bool bReadRow = !isAddAllowed();
937 for(sal_Int32 i=m_vRowList.size(); i < NEWCOLS; i++ )
939 pTabEdRow.reset(new OTableRow());
940 pTabEdRow->SetReadOnly(bReadRow);
941 m_vRowList.push_back( pTabEdRow);
944 // -----------------------------------------------------------------------------
945 Reference<XNameAccess> OTableController::getKeyColumns() const
947 return getPrimaryKeyColumns_throw(m_xTable);
949 // -----------------------------------------------------------------------------
950 sal_Bool OTableController::checkColumns(sal_Bool _bNew) throw(::com::sun::star::sdbc::SQLException)
952 sal_Bool bOk = sal_True;
953 sal_Bool bFoundPKey = sal_False;
954 Reference< XDatabaseMetaData > xMetaData = getMetaData( );
955 DatabaseMetaData aMetaData( getConnection() );
957 ::comphelper::UStringMixEqual bCase(xMetaData.is() ? xMetaData->supportsMixedCaseQuotedIdentifiers() : sal_True);
958 ::std::vector< ::boost::shared_ptr<OTableRow> >::const_iterator aIter = m_vRowList.begin();
959 ::std::vector< ::boost::shared_ptr<OTableRow> >::const_iterator aEnd = m_vRowList.end();
960 for(;aIter != aEnd;++aIter)
962 OFieldDescription* pFieldDesc = (*aIter)->GetActFieldDescr();
963 if (pFieldDesc && !pFieldDesc->GetName().isEmpty())
965 bFoundPKey |= (*aIter)->IsPrimaryKey();
966 // first check for duplicate names
967 ::std::vector< ::boost::shared_ptr<OTableRow> >::const_iterator aIter2 = aIter+1;
968 for(;aIter2 != aEnd;++aIter2)
970 OFieldDescription* pCompareDesc = (*aIter2)->GetActFieldDescr();
971 if (pCompareDesc && bCase(pCompareDesc->GetName(),pFieldDesc->GetName()))
973 String strMessage = String(ModuleRes(STR_TABLEDESIGN_DUPLICATE_NAME));
974 strMessage.SearchAndReplaceAscii("$column$", pFieldDesc->GetName());
975 OSQLWarningBox( getView(), strMessage ).Execute();
976 return sal_False;
981 if ( _bNew && !bFoundPKey && aMetaData.supportsPrimaryKeys() )
983 String sTitle(ModuleRes(STR_TABLEDESIGN_NO_PRIM_KEY_HEAD));
984 String sMsg(ModuleRes(STR_TABLEDESIGN_NO_PRIM_KEY));
985 OSQLMessageBox aBox(getView(), sTitle,sMsg, WB_YES_NO_CANCEL | WB_DEF_YES);
987 switch ( aBox.Execute() )
989 case RET_YES:
991 ::boost::shared_ptr<OTableRow> pNewRow(new OTableRow());
992 TOTypeInfoSP pTypeInfo = ::dbaui::queryPrimaryKeyType(m_aTypeInfo);
993 if ( !pTypeInfo.get() )
994 break;
996 pNewRow->SetFieldType( pTypeInfo );
997 OFieldDescription* pActFieldDescr = pNewRow->GetActFieldDescr();
999 pActFieldDescr->SetAutoIncrement(sal_False);
1000 pActFieldDescr->SetIsNullable(ColumnValue::NO_NULLS);
1002 pActFieldDescr->SetName( createUniqueName(OUString("ID") ));
1003 pActFieldDescr->SetPrimaryKey( sal_True );
1004 m_vRowList.insert(m_vRowList.begin(),pNewRow);
1006 static_cast<OTableDesignView*>(getView())->GetEditorCtrl()->Invalidate();
1007 static_cast<OTableDesignView*>(getView())->GetEditorCtrl()->RowInserted(0);
1009 break;
1010 case RET_CANCEL:
1011 bOk = sal_False;
1012 break;
1015 return bOk;
1017 // -----------------------------------------------------------------------------
1018 void OTableController::alterColumns()
1020 Reference<XColumnsSupplier> xColSup(m_xTable,UNO_QUERY_THROW);
1021 OSL_ENSURE(xColSup.is(),"What happen here?!");
1023 Reference<XNameAccess> xColumns = xColSup->getColumns();
1024 Reference<XIndexAccess> xIdxColumns(xColumns,UNO_QUERY_THROW);
1025 OSL_ENSURE(xColumns.is(),"No columns");
1026 if ( !xColumns.is() )
1027 return;
1028 Reference<XAlterTable> xAlter(m_xTable,UNO_QUERY); // can be null
1030 sal_Int32 nColumnCount = xIdxColumns->getCount();
1031 Reference<XDrop> xDrop(xColumns,UNO_QUERY); // can be null
1032 Reference<XAppend> xAppend(xColumns,UNO_QUERY); // can be null
1033 Reference<XDataDescriptorFactory> xColumnFactory(xColumns,UNO_QUERY); // can be null
1035 sal_Bool bReload = sal_False; // refresh the data
1037 // contains all columns names which are already handled those which are not in the list will be deleted
1038 Reference< XDatabaseMetaData> xMetaData = getMetaData( );
1040 ::std::map< OUString,sal_Bool,::comphelper::UStringMixLess> aColumns(xMetaData.is() ? (xMetaData->supportsMixedCaseQuotedIdentifiers() ? true : false): sal_True);
1041 ::std::vector< ::boost::shared_ptr<OTableRow> >::iterator aIter = m_vRowList.begin();
1042 ::std::vector< ::boost::shared_ptr<OTableRow> >::iterator aEnd = m_vRowList.end();
1043 // first look for columns where something other than the name changed
1044 sal_Int32 nPos = 0;
1045 for(;aIter != aEnd;++aIter,++nPos)
1047 OSL_ENSURE(*aIter,"OTableRow is null!");
1048 OFieldDescription* pField = (*aIter)->GetActFieldDescr();
1049 if ( !pField )
1050 continue;
1051 if ( (*aIter)->IsReadOnly() )
1053 aColumns[pField->GetName()] = sal_True;
1054 continue;
1057 Reference<XPropertySet> xColumn;
1058 if ( xColumns->hasByName(pField->GetName()) )
1060 aColumns[pField->GetName()] = sal_True;
1061 xColumns->getByName(pField->GetName()) >>= xColumn;
1062 OSL_ENSURE(xColumn.is(),"Column is null!");
1064 sal_Int32 nType=0,nPrecision=0,nScale=0,nNullable=0;
1065 sal_Bool bAutoIncrement = false;
1066 OUString sTypeName,sDescription;
1068 xColumn->getPropertyValue(PROPERTY_TYPE) >>= nType;
1069 xColumn->getPropertyValue(PROPERTY_PRECISION) >>= nPrecision;
1070 xColumn->getPropertyValue(PROPERTY_SCALE) >>= nScale;
1071 xColumn->getPropertyValue(PROPERTY_ISNULLABLE) >>= nNullable;
1072 xColumn->getPropertyValue(PROPERTY_ISAUTOINCREMENT) >>= bAutoIncrement;
1073 xColumn->getPropertyValue(PROPERTY_DESCRIPTION) >>= sDescription;
1075 try { xColumn->getPropertyValue(PROPERTY_TYPENAME) >>= sTypeName; }
1076 catch( const Exception& )
1078 OSL_FAIL( "no TypeName property?!" );
1079 // since this is a last minute fix for #i41785#, I want to be on the safe side,
1080 // and catch errors here as early as possible (instead of the whole process of altering
1081 // the columns failing)
1082 // Normally, sdbcx::Column objects are expected to have a TypeName property
1085 // check if something changed
1086 if((nType != pField->GetType() ||
1087 sTypeName != pField->GetTypeName() ||
1088 (nPrecision != pField->GetPrecision() && nPrecision ) ||
1089 nScale != pField->GetScale() ||
1090 nNullable != pField->GetIsNullable() ||
1091 sDescription != pField->GetDescription() ||
1092 bAutoIncrement != pField->IsAutoIncrement())&&
1093 xColumnFactory.is())
1095 Reference<XPropertySet> xNewColumn;
1096 xNewColumn = xColumnFactory->createDataDescriptor();
1097 ::dbaui::setColumnProperties(xNewColumn,pField);
1098 // first try to alter the column
1099 sal_Bool bNotOk = sal_False;
1102 // first try if we can alter the column
1103 if(xAlter.is())
1104 xAlter->alterColumnByName(pField->GetName(),xNewColumn);
1106 catch(const SQLException&)
1108 if(xDrop.is() && xAppend.is())
1110 String aMessage( ModuleRes( STR_TABLEDESIGN_ALTER_ERROR ) );
1111 aMessage.SearchAndReplaceAscii( "$column$", pField->GetName() );
1113 SQLExceptionInfo aError( ::cppu::getCaughtException() );
1114 OSQLWarningBox aMsg( getView(), aMessage, WB_YES_NO | WB_DEF_YES , &aError );
1115 bNotOk = aMsg.Execute() == RET_YES;
1117 else
1118 throw;
1120 // if something went wrong or we can't alter columns
1121 // drop and append a new one
1122 if((!xAlter.is() || bNotOk) && xDrop.is() && xAppend.is())
1124 xDrop->dropByName(pField->GetName());
1127 xAppend->appendByDescriptor(xNewColumn);
1129 catch(const SQLException&)
1130 { // an error occurred so we try to reactivate the old one
1131 xAppend->appendByDescriptor(xColumn);
1132 throw;
1135 // exceptions are caught outside
1136 xNewColumn = NULL;
1137 if(xColumns->hasByName(pField->GetName()))
1138 xColumns->getByName(pField->GetName()) >>= xColumn;
1139 bReload = sal_True;
1144 else if(xColumnFactory.is() && xAlter.is() && nPos < nColumnCount)
1145 { // we can't find the column so we could try it with the index before we drop and append a new column
1148 Reference<XPropertySet> xNewColumn;
1149 xNewColumn = xColumnFactory->createDataDescriptor();
1150 ::dbaui::setColumnProperties(xNewColumn,pField);
1151 xAlter->alterColumnByIndex(nPos,xNewColumn);
1152 if(xColumns->hasByName(pField->GetName()))
1153 { // ask for the append by name
1154 aColumns[pField->GetName()] = sal_True;
1155 xColumns->getByName(pField->GetName()) >>= xColumn;
1156 if(xColumn.is())
1157 pField->copyColumnSettingsTo(xColumn);
1159 else
1161 OSL_FAIL("OTableController::alterColumns: invalid column (2)!");
1164 catch(const SQLException&)
1165 { // we couldn't alter the column so we have to add new columns
1166 bReload = sal_True;
1167 if(xDrop.is() && xAppend.is())
1169 String aMessage(ModuleRes(STR_TABLEDESIGN_ALTER_ERROR));
1170 aMessage.SearchAndReplaceAscii("$column$",pField->GetName());
1171 OSQLWarningBox aMsg( getView(), aMessage, WB_YES_NO | WB_DEF_YES );
1172 if ( aMsg.Execute() != RET_YES )
1174 Reference<XPropertySet> xNewColumn(xIdxColumns->getByIndex(nPos),UNO_QUERY_THROW);
1175 OUString sName;
1176 xNewColumn->getPropertyValue(PROPERTY_NAME) >>= sName;
1177 aColumns[sName] = sal_True;
1178 aColumns[pField->GetName()] = sal_True;
1179 continue;
1182 else
1183 throw;
1186 else
1187 bReload = sal_True;
1189 // alter column settings
1190 aIter = m_vRowList.begin();
1192 // first look for columns where something other than the name changed
1193 for(nPos = 0;aIter != aEnd;++aIter,++nPos)
1195 OSL_ENSURE(*aIter,"OTableRow is null!");
1196 OFieldDescription* pField = (*aIter)->GetActFieldDescr();
1197 if ( !pField )
1198 continue;
1199 if ( (*aIter)->IsReadOnly() )
1201 aColumns[pField->GetName()] = sal_True;
1202 continue;
1205 Reference<XPropertySet> xColumn;
1206 if ( xColumns->hasByName(pField->GetName()) )
1208 xColumns->getByName(pField->GetName()) >>= xColumn;
1209 Reference<XPropertySetInfo> xInfo = xColumn->getPropertySetInfo();
1210 if ( xInfo->hasPropertyByName(PROPERTY_HELPTEXT) )
1211 xColumn->setPropertyValue(PROPERTY_HELPTEXT,makeAny(pField->GetHelpText()));
1213 if(xInfo->hasPropertyByName(PROPERTY_CONTROLDEFAULT))
1214 xColumn->setPropertyValue(PROPERTY_CONTROLDEFAULT,pField->GetControlDefault());
1215 if(xInfo->hasPropertyByName(PROPERTY_FORMATKEY))
1216 xColumn->setPropertyValue(PROPERTY_FORMATKEY,makeAny(pField->GetFormatKey()));
1217 if(xInfo->hasPropertyByName(PROPERTY_ALIGN))
1218 xColumn->setPropertyValue(PROPERTY_ALIGN,makeAny(dbaui::mapTextAllign(pField->GetHorJustify())));
1221 // second drop all columns which could be found by name
1222 Reference<XNameAccess> xKeyColumns = getKeyColumns();
1223 // now we have to look for the columns who could be deleted
1224 if ( xDrop.is() )
1226 Sequence< OUString> aColumnNames = xColumns->getElementNames();
1227 const OUString* pIter = aColumnNames.getConstArray();
1228 const OUString* pEnd = pIter + aColumnNames.getLength();
1229 for(;pIter != pEnd;++pIter)
1231 if(aColumns.find(*pIter) == aColumns.end()) // found a column to delete
1233 if(xKeyColumns.is() && xKeyColumns->hasByName(*pIter)) // check if this column is a member of the primary key
1235 String aMsgT(ModuleRes(STR_TBL_COLUMN_IS_KEYCOLUMN));
1236 aMsgT.SearchAndReplaceAscii("$column$",*pIter);
1237 String aTitle(ModuleRes(STR_TBL_COLUMN_IS_KEYCOLUMN_TITLE));
1238 OSQLMessageBox aMsg(getView(),aTitle,aMsgT,WB_YES_NO| WB_DEF_YES);
1239 if(aMsg.Execute() == RET_YES)
1241 xKeyColumns = NULL;
1242 dropPrimaryKey();
1244 else
1246 bReload = sal_True;
1247 continue;
1252 xDrop->dropByName(*pIter);
1254 catch (const SQLException&)
1256 String sError( ModuleRes( STR_TABLEDESIGN_COULD_NOT_DROP_COL ) );
1257 sError.SearchAndReplaceAscii( "$column$", *pIter );
1259 SQLException aNewException;
1260 aNewException.Message = sError;
1261 aNewException.SQLState = OUString("S1000");
1262 aNewException.NextException = ::cppu::getCaughtException();
1264 throw aNewException;
1270 // third append the new columns
1271 aIter = m_vRowList.begin();
1272 for(;aIter != aEnd;++aIter)
1274 OSL_ENSURE(*aIter,"OTableRow is null!");
1275 OFieldDescription* pField = (*aIter)->GetActFieldDescr();
1276 if ( !pField || (*aIter)->IsReadOnly() || aColumns.find(pField->GetName()) != aColumns.end() )
1277 continue;
1279 Reference<XPropertySet> xColumn;
1280 if(!xColumns->hasByName(pField->GetName()))
1282 if(xColumnFactory.is() && xAppend.is())
1283 {// column not found by its name so we assume it is new
1284 // Column is new
1285 xColumn = xColumnFactory->createDataDescriptor();
1286 ::dbaui::setColumnProperties(xColumn,pField);
1287 xAppend->appendByDescriptor(xColumn);
1288 if(xColumns->hasByName(pField->GetName()))
1289 { // ask for the append by name
1290 aColumns[pField->GetName()] = sal_True;
1291 xColumns->getByName(pField->GetName()) >>= xColumn;
1292 if(xColumn.is())
1293 pField->copyColumnSettingsTo(xColumn);
1295 else
1297 OSL_FAIL("OTableController::alterColumns: invalid column!");
1304 // check if we have to do something with the primary key
1305 sal_Bool bNeedDropKey = sal_False;
1306 sal_Bool bNeedAppendKey = sal_False;
1307 if ( xKeyColumns.is() )
1309 aIter = m_vRowList.begin();
1310 for(;aIter != aEnd;++aIter)
1312 OSL_ENSURE(*aIter,"OTableRow is null!");
1313 OFieldDescription* pField = (*aIter)->GetActFieldDescr();
1314 if ( !pField )
1315 continue;
1317 if ( pField->IsPrimaryKey()
1318 && !xKeyColumns->hasByName( pField->GetName() )
1320 { // new primary key column inserted which isn't already in the columns selection
1321 bNeedDropKey = bNeedAppendKey = sal_True;
1322 break;
1324 else if ( !pField->IsPrimaryKey()
1325 && xKeyColumns->hasByName( pField->GetName() )
1327 { // found a column which currently is in the primary key, but is marked not to be anymore
1328 bNeedDropKey = bNeedAppendKey = sal_True;
1329 break;
1333 else
1334 { // no primary key available so we check if we should create one
1335 bNeedAppendKey = sal_True;
1338 if ( bNeedDropKey && xKeyColumns.is() && xKeyColumns->getElementNames().getLength() )
1339 dropPrimaryKey();
1341 if ( bNeedAppendKey )
1343 Reference< XKeysSupplier > xKeySup( m_xTable, UNO_QUERY );
1344 appendPrimaryKey( xKeySup ,sal_False);
1347 reSyncRows();
1349 if ( bReload )
1350 reload();
1352 // -----------------------------------------------------------------------------
1353 void OTableController::dropPrimaryKey()
1355 SQLExceptionInfo aInfo;
1358 Reference<XKeysSupplier> xKeySup(m_xTable,UNO_QUERY);
1359 Reference<XIndexAccess> xKeys;
1360 if(xKeySup.is())
1361 xKeys = xKeySup->getKeys();
1363 if(xKeys.is())
1365 Reference<XPropertySet> xProp;
1366 for(sal_Int32 i=0;i< xKeys->getCount();++i)
1368 xProp.set(xKeys->getByIndex(i),UNO_QUERY);
1369 sal_Int32 nKeyType = 0;
1370 xProp->getPropertyValue(PROPERTY_TYPE) >>= nKeyType;
1371 if(KeyType::PRIMARY == nKeyType)
1373 Reference<XDrop> xDrop(xKeys,UNO_QUERY);
1374 xDrop->dropByIndex(i); // delete the key
1375 break;
1380 catch(const SQLContext& e)
1382 aInfo = SQLExceptionInfo(e);
1384 catch(const SQLWarning& e)
1386 aInfo = SQLExceptionInfo(e);
1388 catch(const SQLException& e)
1390 aInfo = SQLExceptionInfo(e);
1392 catch( const Exception& )
1394 DBG_UNHANDLED_EXCEPTION();
1397 showError(aInfo);
1399 // -----------------------------------------------------------------------------
1400 void OTableController::assignTable()
1402 // get the table
1403 if(!m_sName.isEmpty())
1405 Reference<XNameAccess> xNameAccess;
1406 Reference<XTablesSupplier> xSup(getConnection(),UNO_QUERY);
1407 if(xSup.is())
1409 xNameAccess = xSup->getTables();
1410 OSL_ENSURE(xNameAccess.is(),"no nameaccess for the queries!");
1412 Reference<XPropertySet> xProp;
1413 if(xNameAccess->hasByName(m_sName) && ::cppu::extractInterface(xProp,xNameAccess->getByName(m_sName)) && xProp.is())
1415 m_xTable = xProp;
1416 startTableListening();
1418 // check if we set the table editable
1419 Reference<XDatabaseMetaData> xMeta = getConnection()->getMetaData();
1420 setEditable( xMeta.is() && !xMeta->isReadOnly() && (isAlterAllowed() || isDropAllowed() || isAddAllowed()) );
1421 if(!isEditable())
1423 ::std::for_each(m_vRowList.begin(),m_vRowList.end(),boost::bind( &OTableRow::SetReadOnly, _1, boost::cref( sal_True )));
1425 m_bNew = sal_False;
1426 // be notified when the table is in disposing
1427 InvalidateAll();
1432 // -----------------------------------------------------------------------------
1433 sal_Bool OTableController::isAddAllowed() const
1435 Reference<XColumnsSupplier> xColsSup(m_xTable,UNO_QUERY);
1436 sal_Bool bAddAllowed = !m_xTable.is();
1437 if(xColsSup.is())
1438 bAddAllowed = Reference<XAppend>(xColsSup->getColumns(),UNO_QUERY).is();
1442 Reference< XDatabaseMetaData > xMetaData = getMetaData( );
1443 bAddAllowed = bAddAllowed || ( xMetaData.is() && xMetaData->supportsAlterTableWithAddColumn());
1445 catch(Exception&)
1447 DBG_UNHANDLED_EXCEPTION();
1448 bAddAllowed = sal_False;
1451 return bAddAllowed;
1453 // -----------------------------------------------------------------------------
1454 sal_Bool OTableController::isDropAllowed() const
1456 Reference<XColumnsSupplier> xColsSup(m_xTable,UNO_QUERY);
1457 sal_Bool bDropAllowed = !m_xTable.is();
1458 if(xColsSup.is())
1460 Reference<XNameAccess> xNameAccess = xColsSup->getColumns();
1461 bDropAllowed = Reference<XDrop>(xNameAccess,UNO_QUERY).is() && xNameAccess->hasElements();
1464 Reference< XDatabaseMetaData> xMetaData = getMetaData( );
1465 bDropAllowed = bDropAllowed || ( xMetaData.is() && xMetaData->supportsAlterTableWithDropColumn());
1467 return bDropAllowed;
1469 // -----------------------------------------------------------------------------
1470 sal_Bool OTableController::isAlterAllowed() const
1472 sal_Bool bAllowed(!m_xTable.is() || Reference<XAlterTable>(m_xTable,UNO_QUERY).is());
1473 return bAllowed;
1475 // -----------------------------------------------------------------------------
1476 void OTableController::reSyncRows()
1478 sal_Bool bAlterAllowed = isAlterAllowed();
1479 sal_Bool bAddAllowed = isAddAllowed();
1480 ::std::vector< ::boost::shared_ptr<OTableRow> >::iterator aIter = m_vRowList.begin();
1481 ::std::vector< ::boost::shared_ptr<OTableRow> >::iterator aEnd = m_vRowList.end();
1482 for(;aIter != aEnd;++aIter)
1484 OSL_ENSURE(*aIter,"OTableRow is null!");
1485 OFieldDescription* pField = (*aIter)->GetActFieldDescr();
1486 if ( pField )
1487 (*aIter)->SetReadOnly(!bAlterAllowed);
1488 else
1489 (*aIter)->SetReadOnly(!bAddAllowed);
1492 static_cast<OTableDesignView*>(getView())->reSync(); // show the windows and fill with our information
1494 ClearUndoManager();
1495 setModified(sal_False); // and we are not modified yet
1497 // -----------------------------------------------------------------------------
1498 OUString OTableController::createUniqueName(const OUString& _rName)
1500 OUString sName = _rName;
1501 Reference< XDatabaseMetaData> xMetaData = getMetaData( );
1503 ::comphelper::UStringMixEqual bCase(xMetaData.is() ? xMetaData->supportsMixedCaseQuotedIdentifiers() : sal_True);
1505 ::std::vector< ::boost::shared_ptr<OTableRow> >::const_iterator aIter = m_vRowList.begin();
1506 ::std::vector< ::boost::shared_ptr<OTableRow> >::const_iterator aEnd = m_vRowList.end();
1507 for(sal_Int32 i=0;aIter != aEnd;++aIter)
1509 OFieldDescription* pFieldDesc = (*aIter)->GetActFieldDescr();
1510 if (pFieldDesc && !pFieldDesc->GetName().isEmpty() && bCase(sName,pFieldDesc->GetName()))
1511 { // found a second name of _rName so we need another
1512 sName = _rName + OUString::valueOf(++i);
1513 aIter = m_vRowList.begin(); // and retry
1516 return sName;
1518 // -----------------------------------------------------------------------------
1519 OUString OTableController::getPrivateTitle() const
1521 OUString sTitle;
1524 // get the table
1525 if ( !m_sName.isEmpty() && getConnection().is() )
1527 if ( m_xTable.is() )
1528 sTitle = ::dbtools::composeTableName( getConnection()->getMetaData(), m_xTable, ::dbtools::eInDataManipulation, false, false, false );
1529 else
1530 sTitle = m_sName;
1532 if ( sTitle.isEmpty() )
1534 String aName = String(ModuleRes(STR_TBL_TITLE));
1535 sTitle = aName.GetToken(0,' ');
1536 sTitle += OUString::valueOf(getCurrentStartNumber());
1539 catch( const Exception& )
1541 DBG_UNHANDLED_EXCEPTION();
1543 return sTitle;
1545 // -----------------------------------------------------------------------------
1546 void OTableController::reload()
1548 loadData(); // fill the column information form the table
1549 static_cast<OTableDesignView*>(getView())->reSync(); // show the windows and fill with our information
1550 ClearUndoManager();
1551 setModified(sal_False); // and we are not modified yet
1552 static_cast<OTableDesignView*>(getView())->Invalidate();
1554 // -----------------------------------------------------------------------------
1555 sal_Int32 OTableController::getFirstEmptyRowPosition()
1557 sal_Int32 nRet = -1;
1558 ::std::vector< ::boost::shared_ptr<OTableRow> >::const_iterator aIter = m_vRowList.begin();
1559 ::std::vector< ::boost::shared_ptr<OTableRow> >::const_iterator aEnd = m_vRowList.end();
1560 for(;aIter != aEnd;++aIter)
1562 if ( !*aIter || !(*aIter)->GetActFieldDescr() || (*aIter)->GetActFieldDescr()->GetName().isEmpty() )
1564 nRet = aIter - m_vRowList.begin();
1565 break;
1568 if ( nRet == -1 )
1570 bool bReadRow = !isAddAllowed();
1571 ::boost::shared_ptr<OTableRow> pTabEdRow(new OTableRow());
1572 pTabEdRow->SetReadOnly(bReadRow);
1573 nRet = m_vRowList.size();
1574 m_vRowList.push_back( pTabEdRow);
1576 return nRet;
1578 // -----------------------------------------------------------------------------
1579 bool OTableController::isAutoIncrementPrimaryKey() const
1581 return getSdbMetaData().isAutoIncrementPrimaryKey();
1583 // -----------------------------------------------------------------------------
1585 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */