xref: /trunk/main/dbaccess/source/ui/tabledesign/TableController.cxx (revision 4bb3d789e15445dbe3c012d13e69fce7f27b45dd)
1 /**************************************************************
2  *
3  * Licensed to the Apache Software Foundation (ASF) under one
4  * or more contributor license agreements.  See the NOTICE file
5  * distributed with this work for additional information
6  * regarding copyright ownership.  The ASF licenses this file
7  * to you under the Apache License, Version 2.0 (the
8  * "License"); you may not use this file except in compliance
9  * with the License.  You may obtain a copy of the License at
10  *
11  *   http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing,
14  * software distributed under the License is distributed on an
15  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16  * KIND, either express or implied.  See the License for the
17  * specific language governing permissions and limitations
18  * under the License.
19  *
20  *************************************************************/
21 
22 // MARKER(update_precomp.py): autogen include statement, do not remove
23 #include "precompiled_dbui.hxx"
24 
25 #include "FieldDescriptions.hxx"
26 #include "TEditControl.hxx"
27 #include "TableController.hxx"
28 #include "TableDesignView.hxx"
29 #include "TableRow.hxx"
30 #include "TypeInfo.hxx"
31 #include "UITools.hxx"
32 #include "browserids.hxx"
33 #include "dbu_reghelper.hxx"
34 #include "dbu_tbl.hrc"
35 #include "dbustrings.hrc"
36 #include "defaultobjectnamecheck.hxx"
37 #include "dlgsave.hxx"
38 #include "dsmeta.hxx"
39 #include "indexdialog.hxx"
40 #include "sqlmessage.hxx"
41 
42 /** === begin UNO includes === **/
43 #include <com/sun/star/container/XChild.hpp>
44 #include <com/sun/star/container/XNameContainer.hpp>
45 #include <com/sun/star/frame/FrameSearchFlag.hpp>
46 #include <com/sun/star/frame/XTitleChangeListener.hpp>
47 #include <com/sun/star/frame/XUntitledNumbers.hpp>
48 #include <com/sun/star/io/XActiveDataSink.hpp>
49 #include <com/sun/star/io/XActiveDataSource.hpp>
50 #include <com/sun/star/sdb/CommandType.hpp>
51 #include <com/sun/star/sdb/SQLContext.hpp>
52 #include <com/sun/star/sdbc/ColumnValue.hpp>
53 #include <com/sun/star/sdbc/SQLWarning.hpp>
54 #include <com/sun/star/sdbc/XRow.hpp>
55 #include <com/sun/star/sdbcx/KeyType.hpp>
56 #include <com/sun/star/sdbcx/XAlterTable.hpp>
57 #include <com/sun/star/sdbcx/XAppend.hpp>
58 #include <com/sun/star/sdbcx/XDataDescriptorFactory.hpp>
59 #include <com/sun/star/sdbcx/XDrop.hpp>
60 #include <com/sun/star/sdbcx/XIndexesSupplier.hpp>
61 #include <com/sun/star/sdbcx/XTablesSupplier.hpp>
62 #include <com/sun/star/ui/dialogs/XExecutableDialog.hpp>
63 /** === end UNO includes === **/
64 
65 #include <comphelper/extract.hxx>
66 #include <comphelper/streamsection.hxx>
67 #include <comphelper/types.hxx>
68 #include <connectivity/dbexception.hxx>
69 #include <connectivity/dbtools.hxx>
70 #include <connectivity/dbmetadata.hxx>
71 #include <cppuhelper/exc_hlp.hxx>
72 #include <sfx2/sfxsids.hrc>
73 #include <tools/diagnose_ex.h>
74 #include <tools/string.hxx>
75 #include <vcl/msgbox.hxx>
76 
77 #include <boost/mem_fn.hpp>
78 #include <boost/bind.hpp>
79 
80 #include <algorithm>
81 #include <functional>
82 
83 extern "C" void SAL_CALL createRegistryInfo_OTableControl()
84 {
85     static ::dbaui::OMultiInstanceAutoRegistration< ::dbaui::OTableController > aAutoRegistration;
86 }
87 
88 using namespace ::com::sun::star;
89 using namespace ::com::sun::star::uno;
90 using namespace ::com::sun::star::io;
91 using namespace ::com::sun::star::beans;
92 using namespace ::com::sun::star::frame;
93 using namespace ::com::sun::star::util;
94 using namespace ::com::sun::star::lang;
95 using namespace ::com::sun::star::container;
96 using namespace ::com::sun::star::sdbcx;
97 using namespace ::com::sun::star::sdbc;
98 using namespace ::com::sun::star::sdb;
99 using namespace ::com::sun::star::ui;
100 using namespace ::com::sun::star::util;
101 using namespace ::dbtools;
102 using namespace ::dbaui;
103 using namespace ::comphelper;
104 
105 // Anzahl Spalten beim Neuanlegen
106 #define NEWCOLS        128
107 
108 namespace
109 {
110     void dropTable(const Reference<XNameAccess>& _rxTable,const ::rtl::OUString& _sTableName)
111     {
112         if ( _rxTable->hasByName(_sTableName) )
113         {
114             Reference<XDrop> xNameCont(_rxTable,UNO_QUERY);
115             OSL_ENSURE(xNameCont.is(),"No drop interface for tables!");
116             if ( xNameCont.is() )
117                 xNameCont->dropByName(_sTableName);
118         }
119     }
120     //------------------------------------------------------------------------------
121     struct OTableRowCompare : public ::std::binary_function<  ::boost::shared_ptr<OTableRow> , ::rtl::OUString, bool>
122     {
123         bool operator() (const  ::boost::shared_ptr<OTableRow>  lhs, const ::rtl::OUString& rhs) const
124         {
125             OFieldDescription* pField = lhs->GetActFieldDescr();
126             return pField && pField->GetName() == rhs;
127         }
128     };
129 
130 }
131 
132 //------------------------------------------------------------------------------
133 ::rtl::OUString SAL_CALL OTableController::getImplementationName() throw( RuntimeException )
134 {
135     return getImplementationName_Static();
136 }
137 
138 //------------------------------------------------------------------------------
139 ::rtl::OUString OTableController::getImplementationName_Static() throw( RuntimeException )
140 {
141     return ::rtl::OUString::createFromAscii("org.openoffice.comp.dbu.OTableDesign");
142 }
143 //------------------------------------------------------------------------------
144 Sequence< ::rtl::OUString> OTableController::getSupportedServiceNames_Static(void) throw( RuntimeException )
145 {
146     Sequence< ::rtl::OUString> aSupported(1);
147     aSupported.getArray()[0] = ::rtl::OUString::createFromAscii("com.sun.star.sdb.TableDesign");
148     return aSupported;
149 }
150 //-------------------------------------------------------------------------
151 Sequence< ::rtl::OUString> SAL_CALL OTableController::getSupportedServiceNames() throw(RuntimeException)
152 {
153     return getSupportedServiceNames_Static();
154 }
155 // -------------------------------------------------------------------------
156 Reference< XInterface > SAL_CALL OTableController::Create(const Reference<XMultiServiceFactory >& _rxFactory)
157 {
158     return *(new OTableController(_rxFactory));
159 }
160 
161 DBG_NAME(OTableController)
162 // -----------------------------------------------------------------------------
163 OTableController::OTableController(const Reference< XMultiServiceFactory >& _rM) : OTableController_BASE(_rM)
164     ,m_sTypeNames(ModuleRes(STR_TABLEDESIGN_DBFIELDTYPES))
165     ,m_pTypeInfo()
166     ,m_bAllowAutoIncrementValue(sal_False)
167     ,m_bNew(sal_True)
168 {
169     DBG_CTOR(OTableController,NULL);
170 
171     InvalidateAll();
172     m_pTypeInfo = TOTypeInfoSP(new OTypeInfo());
173     m_pTypeInfo->aUIName = m_sTypeNames.GetToken(TYPE_OTHER);
174 }
175 // -----------------------------------------------------------------------------
176 OTableController::~OTableController()
177 {
178     m_aTypeInfoIndex.clear();
179     m_aTypeInfo.clear();
180 
181     DBG_DTOR(OTableController,NULL);
182 }
183 
184 // -----------------------------------------------------------------------------
185 void OTableController::startTableListening()
186 {
187     Reference< XComponent >  xComponent(m_xTable, UNO_QUERY);
188     if (xComponent.is())
189         xComponent->addEventListener(static_cast<XModifyListener*>(this));
190 }
191 
192 // -----------------------------------------------------------------------------
193 void OTableController::stopTableListening()
194 {
195     Reference< XComponent >  xComponent(m_xTable, UNO_QUERY);
196     if (xComponent.is())
197         xComponent->removeEventListener(static_cast<XModifyListener*>(this));
198 }
199 
200 // -----------------------------------------------------------------------------
201 void OTableController::disposing()
202 {
203     OTableController_BASE::disposing();
204     clearView();
205 
206     m_vRowList.clear();
207 }
208 // -----------------------------------------------------------------------------
209 FeatureState OTableController::GetState(sal_uInt16 _nId) const
210 {
211     FeatureState aReturn;
212     // (disabled automatically)
213 
214     switch (_nId)
215     {
216         case ID_BROWSER_CLOSE:
217             aReturn.bEnabled = sal_True;
218             break;
219         case ID_BROWSER_EDITDOC:
220             aReturn.bChecked = isEditable();
221             aReturn.bEnabled = m_bNew || isEditable();// the editable flag is set through this one -> || isAddAllowed() || isDropAllowed() || isAlterAllowed();
222             break;
223         case ID_BROWSER_SAVEDOC:
224             aReturn.bEnabled = impl_isModified();
225             if ( aReturn.bEnabled )
226             {
227                 ::std::vector< ::boost::shared_ptr<OTableRow> >::const_iterator aIter = ::std::find_if(m_vRowList.begin(),m_vRowList.end(),
228                     ::boost::mem_fn(&OTableRow::isValid));
229                 aReturn.bEnabled = aIter != m_vRowList.end();
230             }
231             break;
232         case ID_BROWSER_SAVEASDOC:
233             aReturn.bEnabled = isConnected() && isEditable();
234             if ( aReturn.bEnabled )
235             {
236                 ::std::vector< ::boost::shared_ptr<OTableRow> >::const_iterator aIter = ::std::find_if(m_vRowList.begin(),m_vRowList.end(),
237                     ::boost::mem_fn(&OTableRow::isValid));
238                 aReturn.bEnabled = aIter != m_vRowList.end();
239             }
240             break;
241 
242         case ID_BROWSER_CUT:
243             aReturn.bEnabled = isEditable() && m_aCurrentFrame.isActive() && getView() && static_cast<OTableDesignView*>(getView())->isCutAllowed();
244             break;
245         case ID_BROWSER_COPY:
246             aReturn.bEnabled = m_aCurrentFrame.isActive() && getView() && static_cast<OTableDesignView*>(getView())->isCopyAllowed();
247             break;
248         case ID_BROWSER_PASTE:
249             aReturn.bEnabled = isEditable() && m_aCurrentFrame.isActive() && getView() && static_cast<OTableDesignView*>(getView())->isPasteAllowed();
250             break;
251         case SID_INDEXDESIGN:
252             aReturn.bEnabled =
253                 (   (   ((!m_bNew && impl_isModified()) || impl_isModified())
254                     ||  Reference< XIndexesSupplier >(m_xTable, UNO_QUERY).is()
255                     )
256                 &&  isConnected()
257                 );
258             if ( aReturn.bEnabled )
259             {
260                 ::std::vector< ::boost::shared_ptr<OTableRow> >::const_iterator aIter = ::std::find_if(m_vRowList.begin(),m_vRowList.end(),
261                     ::boost::mem_fn(&OTableRow::isValid));
262                 aReturn.bEnabled = aIter != m_vRowList.end();
263             }
264             break;
265         default:
266             aReturn = OTableController_BASE::GetState(_nId);
267     }
268     return aReturn;
269 }
270 // -----------------------------------------------------------------------------
271 void OTableController::Execute(sal_uInt16 _nId, const Sequence< PropertyValue >& aArgs)
272 {
273     switch(_nId)
274     {
275         case ID_BROWSER_EDITDOC:
276             setEditable(!isEditable());
277             static_cast<OTableDesignView*>(getView())->setReadOnly(!isEditable());
278             InvalidateFeature(ID_BROWSER_PASTE);
279             InvalidateFeature(SID_BROWSER_CLEAR_QUERY);
280             break;
281         case ID_BROWSER_SAVEASDOC:
282             doSaveDoc(sal_True);
283             break;
284         case ID_BROWSER_SAVEDOC:
285             static_cast<OTableDesignView*>(getView())->GetEditorCtrl()->SaveCurRow();
286             doSaveDoc(sal_False);
287             break;
288         case ID_BROWSER_CUT:
289             static_cast<OTableDesignView*>(getView())->cut();
290             break;
291         case ID_BROWSER_COPY:
292             static_cast<OTableDesignView*>(getView())->copy();
293             break;
294         case ID_BROWSER_PASTE:
295             static_cast<OTableDesignView*>(getView())->paste();
296             break;
297         case SID_INDEXDESIGN:
298             doEditIndexes();
299             break;
300         default:
301             OTableController_BASE::Execute(_nId,aArgs);
302     }
303     InvalidateFeature(_nId);
304 }
305 
306 // -----------------------------------------------------------------------------
307 sal_Bool OTableController::doSaveDoc(sal_Bool _bSaveAs)
308 {
309     if (!isConnected())
310         reconnect(sal_True); // ask the user for a new connection
311     Reference<XTablesSupplier> xTablesSup(getConnection(),UNO_QUERY);
312 
313     if (!xTablesSup.is())
314     {
315         String aMessage(ModuleRes(STR_TABLEDESIGN_CONNECTION_MISSING));
316         OSQLWarningBox( getView(), aMessage ).Execute();
317         return sal_False;
318     }
319 
320     // check if a column exists
321     // TODO
322 
323     Reference<XNameAccess> xTables;
324     ::rtl::OUString sCatalog, sSchema;
325 
326     sal_Bool bNew = (0 == m_sName.getLength());
327     bNew = bNew || m_bNew || _bSaveAs;
328 
329     try
330     {
331         xTables = xTablesSup->getTables();
332         OSL_ENSURE(xTables.is(),"The tables can't be null!");
333         bNew = bNew || (xTables.is() && !xTables->hasByName(m_sName));
334 
335         // first we need a name for our query so ask the user
336         if(bNew)
337         {
338             String aDefaultName;
339             if (_bSaveAs && !bNew)
340                  aDefaultName = String(m_sName);
341             else
342             {
343                 String aName = String(ModuleRes(STR_TBL_TITLE));
344                 aDefaultName = aName.GetToken(0,' ');
345                 //aDefaultName = getPrivateTitle();
346                 aDefaultName = ::dbtools::createUniqueName(xTables,aDefaultName);
347             }
348 
349             DynamicTableOrQueryNameCheck aNameChecker( getConnection(), CommandType::TABLE );
350             OSaveAsDlg aDlg( getView(), CommandType::TABLE, getORB(), getConnection(), aDefaultName, aNameChecker );
351             if ( aDlg.Execute() != RET_OK )
352                 return sal_False;
353 
354             m_sName = aDlg.getName();
355             sCatalog = aDlg.getCatalog();
356             sSchema  = aDlg.getSchema();
357         }
358 
359         // did we get a name
360         if(!m_sName.getLength())
361             return sal_False;
362     }
363     catch(Exception&)
364     {
365         OSL_ENSURE(sal_False, "OTableController::doSaveDoc: nothing is expected to happen here!");
366     }
367 
368     sal_Bool bAlter = sal_False;
369     sal_Bool bError = sal_False;
370     SQLExceptionInfo aInfo;
371     try
372     {
373         // check the columns for double names
374         if(!checkColumns(bNew || !xTables->hasByName(m_sName)))
375         {
376             // #105323# OJ
377             return sal_False;
378         }
379 
380         Reference<XPropertySet> xTable;
381         if(bNew || !xTables->hasByName(m_sName)) // just to make sure the table already exists
382         {
383             dropTable(xTables,m_sName);
384 
385             Reference<XDataDescriptorFactory> xFact(xTables,UNO_QUERY);
386             OSL_ENSURE(xFact.is(),"OTableController::doSaveDoc: No XDataDescriptorFactory available!");
387             xTable = xFact->createDataDescriptor();
388             OSL_ENSURE(xTable.is(),"OTableController::doSaveDoc: Create query failed!");
389             // to set the name is only allowed when the query is new
390             xTable->setPropertyValue(PROPERTY_CATALOGNAME,makeAny(sCatalog));
391             xTable->setPropertyValue(PROPERTY_SCHEMANAME,makeAny(sSchema));
392             xTable->setPropertyValue(PROPERTY_NAME,makeAny(m_sName));
393 
394             // now append the columns
395             Reference<XColumnsSupplier> xColSup(xTable,UNO_QUERY);
396             appendColumns(xColSup,bNew);
397             // now append the primary key
398             Reference<XKeysSupplier> xKeySup(xTable,UNO_QUERY);
399             appendPrimaryKey(xKeySup,bNew);
400         }
401         // now set the properties
402         if(bNew)
403         {
404             Reference<XAppend> xAppend(xTables,UNO_QUERY);
405             OSL_ENSURE(xAppend.is(),"OTableController::doSaveDoc: No XAppend Interface!");
406             xAppend->appendByDescriptor(xTable);
407 
408             assignTable();
409             if(!m_xTable.is()) // correct name and try again
410             {
411                 // it can be that someone inserted new data for us
412                 m_sName = ::dbtools::composeTableName( getConnection()->getMetaData(), xTable, ::dbtools::eInDataManipulation, false, false, false );
413                 assignTable();
414             }
415             // now check if our datasource has set a tablefilter and if append the new table name to it
416             ::dbaui::appendToFilter(getConnection(),m_sName,getORB(),getView()); // we are not interested in the return value
417             Reference< frame::XTitleChangeListener> xEventListener(impl_getTitleHelper_throw(),UNO_QUERY);
418             if ( xEventListener.is() )
419             {
420                 frame::TitleChangedEvent aEvent;
421                 xEventListener->titleChanged(aEvent);
422             }
423             releaseNumberForComponent();
424         }
425         else if(m_xTable.is())
426         {
427             bAlter = sal_True;
428             alterColumns();
429         }
430         reSyncRows();
431     }
432     catch(const SQLContext& e)
433     {
434         aInfo = SQLExceptionInfo(e);
435     }
436     catch(const SQLWarning& e)
437     {
438         aInfo = SQLExceptionInfo(e);
439     }
440     catch(const SQLException& e)
441     {
442         aInfo = SQLExceptionInfo(e);
443     }
444     catch(const ElementExistException& )
445     {
446         String sText( ModuleRes( STR_NAME_ALREADY_EXISTS ) );
447         sText.SearchAndReplaceAscii( "#" , m_sName);
448         OSQLMessageBox aDlg( getView(), String( ModuleRes( STR_ERROR_DURING_CREATION ) ), sText, WB_OK, OSQLMessageBox::Error );
449 
450         aDlg.Execute();
451         bError = sal_True;
452     }
453     catch( const Exception& )
454     {
455         bError = sal_True;
456         DBG_UNHANDLED_EXCEPTION();
457     }
458 
459     if ( aInfo.isValid() )
460         aInfo.prepend( String( ModuleRes( STR_TABLEDESIGN_SAVE_ERROR ) ) );
461     showError(aInfo);
462 
463     if (aInfo.isValid() || bError)
464     {
465         if(!bAlter || bNew)
466         {
467             m_sName = ::rtl::OUString();
468             stopTableListening();
469             m_xTable = NULL;
470         }
471         //  reload(); // a error occurred so we have to reload
472     }
473     return ! (aInfo.isValid() || bError);
474 }
475 
476 // -----------------------------------------------------------------------------
477 void OTableController::doEditIndexes()
478 {
479     // table needs to be saved before editing indexes
480     if (m_bNew || isModified())
481     {
482         QueryBox aAsk(getView(), ModuleRes(QUERY_SAVE_TABLE_EDIT_INDEXES));
483         if (RET_YES != aAsk.Execute())
484             return;
485 
486         if (!doSaveDoc(sal_False))
487             return;
488 
489         OSL_ENSURE(!m_bNew && !isModified(), "OTableController::doEditIndexes: what the hell did doSaveDoc do?");
490     }
491 
492     Reference< XNameAccess > xIndexes;          // will be the keys of the table
493     Sequence< ::rtl::OUString > aFieldNames;    // will be the column names of the table
494     try
495     {
496         // get the keys
497         Reference< XIndexesSupplier > xIndexesSupp(m_xTable, UNO_QUERY);
498         if (xIndexesSupp.is())
499         {
500             xIndexes = xIndexesSupp->getIndexes();
501             OSL_ENSURE(xIndexes.is(), "OTableController::doEditIndexes: no keys got from the indexes supplier!");
502         }
503         else
504             OSL_ENSURE(sal_False, "OTableController::doEditIndexes: should never have reached this (no indexes supplier)!");
505 
506         // get the field names
507         Reference< XColumnsSupplier > xColSupp(m_xTable, UNO_QUERY);
508         OSL_ENSURE(xColSupp.is(), "OTableController::doEditIndexes: no columns supplier!");
509         if (xColSupp.is())
510         {
511             Reference< XNameAccess > xCols = xColSupp->getColumns();
512             OSL_ENSURE(xCols.is(), "OTableController::doEditIndexes: no columns!");
513             if (xCols.is())
514                 aFieldNames = xCols->getElementNames();
515         }
516     }
517     catch( const Exception& )
518     {
519         DBG_UNHANDLED_EXCEPTION();
520     }
521 
522     if (!xIndexes.is())
523         return;
524 
525     DbaIndexDialog aDialog(getView(), aFieldNames, xIndexes, getConnection(),getORB(),isConnected() ? getConnection()->getMetaData().is() && getConnection()->getMetaData()->getMaxColumnsInIndex() : sal_Int32(0));
526     if (RET_OK != aDialog.Execute())
527         return;
528 
529 }
530 
531 // -----------------------------------------------------------------------------
532 void OTableController::impl_initialize()
533 {
534     try
535     {
536         OTableController_BASE::impl_initialize();
537 
538         const NamedValueCollection& rArguments( getInitParams() );
539 
540         rArguments.get_ensureType( (::rtl::OUString)PROPERTY_CURRENTTABLE, m_sName );
541 
542         // read autoincrement value set in the datasource
543         ::dbaui::fillAutoIncrementValue(getDataSource(),m_bAllowAutoIncrementValue,m_sAutoIncrementValue);
544 
545         assignTable();
546     }
547     catch( const Exception& )
548     {
549         DBG_UNHANDLED_EXCEPTION();
550     }
551 
552     try
553     {
554         ::dbaui::fillTypeInfo(getConnection(),m_sTypeNames,m_aTypeInfo,m_aTypeInfoIndex);               // fill the needed type information
555     }
556     catch(const SQLException&)
557     {
558         OSQLWarningBox( getView(), ModuleRes( STR_NO_TYPE_INFO_AVAILABLE ) ).Execute();
559         throw;
560     }
561     try
562     {
563         loadData();                 // fill the column information form the table
564         getView()->initialize();    // show the windows and fill with our information
565         ClearUndoManager();
566         setModified(sal_False);     // and we are not modified yet
567     }
568     catch( const Exception& )
569     {
570         DBG_UNHANDLED_EXCEPTION();
571     }
572 }
573 // -----------------------------------------------------------------------------
574 sal_Bool OTableController::Construct(Window* pParent)
575 {
576     setView( * new OTableDesignView( pParent, getORB(), *this ) );
577     OTableController_BASE::Construct(pParent);
578 //  m_pView->Construct();
579 //  m_pView->Show();
580     return sal_True;
581 }
582 // -----------------------------------------------------------------------------
583 sal_Bool SAL_CALL OTableController::suspend(sal_Bool /*_bSuspend*/) throw( RuntimeException )
584 {
585     if ( getBroadcastHelper().bInDispose || getBroadcastHelper().bDisposed )
586         return sal_True;
587 
588     vos::OGuard aSolarGuard( Application::GetSolarMutex() );
589     ::osl::MutexGuard aGuard( getMutex() );
590     if ( getView() && getView()->IsInModalMode() )
591         return sal_False;
592     if ( getView() )
593         static_cast<OTableDesignView*>(getView())->GrabFocus();
594     sal_Bool bCheck = sal_True;
595     if ( isModified() )
596     {
597         ::std::vector< ::boost::shared_ptr<OTableRow> >::iterator aIter = ::std::find_if(m_vRowList.begin(),m_vRowList.end(),
598             ::boost::mem_fn(&OTableRow::isValid));
599         if ( aIter != m_vRowList.end() )
600         {
601             QueryBox aQry(getView(), ModuleRes(TABLE_DESIGN_SAVEMODIFIED));
602             switch (aQry.Execute())
603             {
604                 case RET_YES:
605                     Execute(ID_BROWSER_SAVEDOC,Sequence<PropertyValue>());
606                     if ( isModified() )
607                         bCheck = sal_False; // when we save the table this must be false else some press cancel
608                     break;
609                 case RET_CANCEL:
610                     bCheck = sal_False;
611                 default:
612                     break;
613             }
614         }
615         else if ( !m_bNew )
616         {
617             QueryBox aQry(getView(), ModuleRes(TABLE_DESIGN_ALL_ROWS_DELETED));
618             switch (aQry.Execute())
619             {
620                 case RET_YES:
621                     {
622                         try
623                         {
624                             Reference<XTablesSupplier> xTablesSup(getConnection(),UNO_QUERY);
625                             Reference<XNameAccess> xTables = xTablesSup->getTables();
626                             dropTable(xTables,m_sName);
627                         }
628                         catch(const Exception&)
629                         {
630                             OSL_ENSURE(sal_False, "OTableController::suspend: nothing is expected to happen here!");
631                         }
632 
633                     }
634                     break;
635                 case RET_CANCEL:
636                     bCheck = sal_False;
637                 default:
638                     break;
639             }
640         }
641     }
642 /*
643     if ( bCheck )
644         OSingleDocumentController::suspend(_bSuspend);
645 */
646     return bCheck;
647 }
648 // -----------------------------------------------------------------------------
649 void OTableController::describeSupportedFeatures()
650 {
651     OSingleDocumentController::describeSupportedFeatures();
652 
653     implDescribeSupportedFeature( ".uno:Redo",          ID_BROWSER_REDO,        CommandGroup::EDIT );
654     implDescribeSupportedFeature( ".uno:Save",          ID_BROWSER_SAVEDOC,     CommandGroup::EDIT );
655     implDescribeSupportedFeature( ".uno:Undo",          ID_BROWSER_UNDO,        CommandGroup::EDIT );
656     implDescribeSupportedFeature( ".uno:HelpMenu",      SID_HELPMENU,           CommandGroup::APPLICATION );
657     implDescribeSupportedFeature( ".uno:NewDoc",        SID_NEWDOC,             CommandGroup::DOCUMENT );
658     implDescribeSupportedFeature( ".uno:SaveAs",        ID_BROWSER_SAVEASDOC,   CommandGroup::DOCUMENT );
659     implDescribeSupportedFeature( ".uno:DBIndexDesign", SID_INDEXDESIGN,        CommandGroup::APPLICATION );
660     implDescribeSupportedFeature( ".uno:EditDoc",       ID_BROWSER_EDITDOC,     CommandGroup::EDIT );
661 }
662 // -----------------------------------------------------------------------------
663 void OTableController::impl_onModifyChanged()
664 {
665     OSingleDocumentController::impl_onModifyChanged();
666     InvalidateFeature( SID_INDEXDESIGN );
667 }
668 // -----------------------------------------------------------------------------
669 void SAL_CALL OTableController::disposing( const EventObject& _rSource ) throw(RuntimeException)
670 {
671     if ( _rSource.Source == m_xTable )
672     {   // some deleted our table so we have a new one
673         stopTableListening();
674         m_xTable    = NULL;
675         m_bNew      = sal_True;
676         setModified(sal_True);
677     }
678     else
679         OTableController_BASE::disposing( _rSource );
680 }
681 // -----------------------------------------------------------------------------
682 void OTableController::Save(const Reference< XObjectOutputStream>& _rxOut)
683 {
684     OStreamSection aSection(_rxOut.get());
685 
686 }
687 // -----------------------------------------------------------------------------
688 void OTableController::Load(const Reference< XObjectInputStream>& _rxIn)
689 {
690     OStreamSection aSection(_rxIn.get());
691 }
692 
693 // -----------------------------------------------------------------------------
694 void OTableController::losingConnection( )
695 {
696     // let the base class do its reconnect
697     OTableController_BASE::losingConnection( );
698 
699     // remove from the table
700     Reference< XComponent >  xComponent(m_xTable, UNO_QUERY);
701     if (xComponent.is())
702     {
703         Reference<XEventListener> xEvtL( static_cast< ::cppu::OWeakObject*>(this), UNO_QUERY);
704         xComponent->removeEventListener(xEvtL);
705     }
706     stopTableListening();
707     m_xTable    = NULL;
708     assignTable();
709     if(!m_xTable.is())
710     {
711         m_bNew      = sal_True;
712         setModified(sal_True);
713     }
714     InvalidateAll();
715 }
716 // -----------------------------------------------------------------------------
717 TOTypeInfoSP OTableController::getTypeInfoByType(sal_Int32 _nDataType) const
718 {
719     return queryTypeInfoByType(_nDataType,m_aTypeInfo);
720 }
721 // -----------------------------------------------------------------------------
722 void OTableController::appendColumns(Reference<XColumnsSupplier>& _rxColSup,sal_Bool _bNew,sal_Bool _bKeyColumns)
723 {
724     try
725     {
726         // now append the columns
727         OSL_ENSURE(_rxColSup.is(),"No columns supplier");
728         if(!_rxColSup.is())
729             return;
730         Reference<XNameAccess> xColumns = _rxColSup->getColumns();
731         OSL_ENSURE(xColumns.is(),"No columns");
732         Reference<XDataDescriptorFactory> xColumnFactory(xColumns,UNO_QUERY);
733 
734         Reference<XAppend> xAppend(xColumns,UNO_QUERY);
735         OSL_ENSURE(xAppend.is(),"No XAppend Interface!");
736 
737         ::std::vector< ::boost::shared_ptr<OTableRow> >::iterator aIter = m_vRowList.begin();
738         ::std::vector< ::boost::shared_ptr<OTableRow> >::iterator aEnd = m_vRowList.end();
739         for(;aIter != aEnd;++aIter)
740         {
741             OSL_ENSURE(*aIter,"OTableRow is null!");
742             OFieldDescription* pField = (*aIter)->GetActFieldDescr();
743             if ( !pField || (!_bNew && (*aIter)->IsReadOnly() && !_bKeyColumns) )
744                 continue;
745 
746             Reference<XPropertySet> xColumn;
747             if(pField->IsPrimaryKey() || !_bKeyColumns)
748                 xColumn = xColumnFactory->createDataDescriptor();
749             if(xColumn.is())
750             {
751                 if(!_bKeyColumns)
752                     ::dbaui::setColumnProperties(xColumn,pField);
753                 else
754                     xColumn->setPropertyValue(PROPERTY_NAME,makeAny(pField->GetName()));
755 
756                 xAppend->appendByDescriptor(xColumn);
757                 xColumn = NULL;
758                 // now only the settings are missing
759                 if(xColumns->hasByName(pField->GetName()))
760                 {
761                     xColumns->getByName(pField->GetName()) >>= xColumn;
762                     if(xColumn.is())
763                         pField->copyColumnSettingsTo(xColumn);
764                 }
765                 else
766                 {
767                     OSL_ENSURE(sal_False, "OTableController::appendColumns: invalid field name!");
768                 }
769 
770             }
771         }
772     }
773     catch(const SQLException& )
774     {
775         showError( SQLExceptionInfo( ::cppu::getCaughtException() ) );
776     }
777     catch( const Exception& )
778     {
779         DBG_UNHANDLED_EXCEPTION();
780     }
781 }
782 // -----------------------------------------------------------------------------
783 void OTableController::appendPrimaryKey(Reference<XKeysSupplier>& _rxSup,sal_Bool _bNew)
784 {
785     if(!_rxSup.is())
786         return; // the database doesn't support keys
787 
788     OSL_ENSURE(_rxSup.is(),"No XKeysSupplier!");
789     Reference<XIndexAccess> xKeys(_rxSup->getKeys(),UNO_QUERY);
790     Reference<XPropertySet> xProp;
791     const sal_Int32 nCount = xKeys->getCount();
792     for(sal_Int32 i=0;i< nCount ;++i)
793     {
794         xKeys->getByIndex(i) >>= xProp;
795         sal_Int32 nKeyType = 0;
796         xProp->getPropertyValue(PROPERTY_TYPE) >>= nKeyType;
797         if(KeyType::PRIMARY == nKeyType)
798         {
799             return; // primary key already exists after appending a column
800         }
801     }
802     Reference<XDataDescriptorFactory> xKeyFactory(xKeys,UNO_QUERY);
803     OSL_ENSURE(xKeyFactory.is(),"No XDataDescriptorFactory Interface!");
804     if ( !xKeyFactory.is() )
805         return;
806     Reference<XAppend> xAppend(xKeyFactory,UNO_QUERY);
807     OSL_ENSURE(xAppend.is(),"No XAppend Interface!");
808 
809     Reference<XPropertySet> xKey = xKeyFactory->createDataDescriptor();
810     OSL_ENSURE(xKey.is(),"Key is null!");
811     xKey->setPropertyValue(PROPERTY_TYPE,makeAny(KeyType::PRIMARY));
812 
813     Reference<XColumnsSupplier> xColSup(xKey,UNO_QUERY);
814     if(xColSup.is())
815     {
816         appendColumns(xColSup,_bNew,sal_True);
817         Reference<XNameAccess> xColumns = xColSup->getColumns();
818         if(xColumns->hasElements())
819             xAppend->appendByDescriptor(xKey);
820     }
821 }
822 // -----------------------------------------------------------------------------
823 void OTableController::loadData()
824 {
825     //////////////////////////////////////////////////////////////////////
826     // Wenn Datenstruktur bereits vorhanden, Struktur leeren
827     m_vRowList.clear();
828 
829     ::boost::shared_ptr<OTableRow>  pTabEdRow;
830     Reference< XDatabaseMetaData> xMetaData = getMetaData( );
831     //////////////////////////////////////////////////////////////////////
832     // Datenstruktur mit Daten aus DatenDefinitionsObjekt füllen
833     if(m_xTable.is() && xMetaData.is())
834     {
835         Reference<XColumnsSupplier> xColSup(m_xTable,UNO_QUERY);
836         OSL_ENSURE(xColSup.is(),"No XColumnsSupplier!");
837         Reference<XNameAccess> xColumns = xColSup->getColumns();
838         OFieldDescription* pActFieldDescr = NULL;
839         String aType;
840         //////////////////////////////////////////////////////////////////////
841         // ReadOnly-Flag
842         // Bei Drop darf keine Zeile editierbar sein.
843         // Bei Add dürfen nur die leeren Zeilen editierbar sein.
844         // Bei Add und Drop können alle Zeilen editiert werden.
845         //  sal_Bool bReadOldRow = xMetaData->supportsAlterTableWithAddColumn() && xMetaData->supportsAlterTableWithDropColumn();
846         sal_Bool bIsAlterAllowed = isAlterAllowed();
847         Sequence< ::rtl::OUString> aColumns = xColumns->getElementNames();
848         const ::rtl::OUString* pIter    = aColumns.getConstArray();
849         const ::rtl::OUString* pEnd     = pIter + aColumns.getLength();
850 
851         for(;pIter != pEnd;++pIter)
852         {
853             Reference<XPropertySet> xColumn;
854             xColumns->getByName(*pIter) >>= xColumn;
855             sal_Int32 nType         = 0;
856             sal_Int32 nScale        = 0;
857             sal_Int32 nPrecision    = 0;
858             sal_Int32 nNullable     = 0;
859             sal_Int32 nFormatKey    = 0;
860             sal_Int32 nAlign        = 0;
861 
862             sal_Bool bIsAutoIncrement = false, bIsCurrency = false;
863             ::rtl::OUString sName,sDescription,sTypeName,sHelpText;
864             Any aControlDefault;
865 
866             // get the properties from the column
867             xColumn->getPropertyValue(PROPERTY_NAME)            >>= sName;
868             xColumn->getPropertyValue(PROPERTY_TYPENAME)        >>= sTypeName;
869             xColumn->getPropertyValue(PROPERTY_ISNULLABLE)      >>= nNullable;
870             xColumn->getPropertyValue(PROPERTY_ISAUTOINCREMENT) >>= bIsAutoIncrement;
871             xColumn->getPropertyValue(PROPERTY_ISCURRENCY)      >>= bIsCurrency;
872             xColumn->getPropertyValue(PROPERTY_TYPE)            >>= nType;
873             xColumn->getPropertyValue(PROPERTY_SCALE)           >>= nScale;
874             xColumn->getPropertyValue(PROPERTY_PRECISION)       >>= nPrecision;
875             xColumn->getPropertyValue(PROPERTY_DESCRIPTION)     >>= sDescription;
876 
877             if(xColumn->getPropertySetInfo()->hasPropertyByName(PROPERTY_HELPTEXT))
878                 xColumn->getPropertyValue(PROPERTY_HELPTEXT)    >>= sHelpText;
879 
880             if(xColumn->getPropertySetInfo()->hasPropertyByName(PROPERTY_CONTROLDEFAULT))
881                 aControlDefault = xColumn->getPropertyValue(PROPERTY_CONTROLDEFAULT);
882             if(xColumn->getPropertySetInfo()->hasPropertyByName(PROPERTY_FORMATKEY))
883                 xColumn->getPropertyValue(PROPERTY_FORMATKEY)   >>= nFormatKey;
884             if(xColumn->getPropertySetInfo()->hasPropertyByName(PROPERTY_ALIGN))
885                 xColumn->getPropertyValue(PROPERTY_ALIGN)       >>= nAlign;
886 
887             pTabEdRow.reset(new OTableRow());
888             pTabEdRow->SetReadOnly(!bIsAlterAllowed);
889             // search for type
890             sal_Bool bForce;
891             ::rtl::OUString sCreate(RTL_CONSTASCII_USTRINGPARAM("x"));
892             TOTypeInfoSP pTypeInfo = ::dbaui::getTypeInfoFromType(m_aTypeInfo,nType,sTypeName,sCreate,nPrecision,nScale,bIsAutoIncrement,bForce);
893             if ( !pTypeInfo.get() )
894                 pTypeInfo = m_pTypeInfo;
895             pTabEdRow->SetFieldType( pTypeInfo, bForce );
896 
897             pActFieldDescr = pTabEdRow->GetActFieldDescr();
898             OSL_ENSURE(pActFieldDescr, "OTableController::loadData: invalid field description generated by the table row!");
899             if ( pActFieldDescr )
900             {
901                 pActFieldDescr->SetName(sName);
902                 pActFieldDescr->SetFormatKey(nFormatKey);
903                 //  pActFieldDescr->SetPrimaryKey(pPrimary->GetValue());
904                 pActFieldDescr->SetDescription(sDescription);
905                 pActFieldDescr->SetHelpText(sHelpText);
906                 pActFieldDescr->SetAutoIncrement(bIsAutoIncrement);
907                 pActFieldDescr->SetHorJustify(dbaui::mapTextJustify(nAlign));
908                 pActFieldDescr->SetCurrency(bIsCurrency);
909 
910                 //////////////////////////////////////////////////////////////////////
911                 // Spezielle Daten
912                 pActFieldDescr->SetIsNullable(nNullable);
913                 pActFieldDescr->SetControlDefault(aControlDefault);
914                 pActFieldDescr->SetPrecision(nPrecision);
915                 pActFieldDescr->SetScale(nScale);
916             }
917             m_vRowList.push_back( pTabEdRow);
918         }
919         // fill the primary  key information
920         Reference<XNameAccess> xKeyColumns  = getKeyColumns();
921         if(xKeyColumns.is())
922         {
923             Sequence< ::rtl::OUString> aKeyColumns = xKeyColumns->getElementNames();
924             const ::rtl::OUString* pKeyBegin    = aKeyColumns.getConstArray();
925             const ::rtl::OUString* pKeyEnd      = pKeyBegin + aKeyColumns.getLength();
926 
927             for(;pKeyBegin != pKeyEnd;++pKeyBegin)
928             {
929                 ::std::vector< ::boost::shared_ptr<OTableRow> >::iterator rowIter = m_vRowList.begin();
930                 ::std::vector< ::boost::shared_ptr<OTableRow> >::iterator rowEnd = m_vRowList.end();
931                 for(;rowIter != rowEnd;++rowIter)
932                 {
933                     if((*rowIter)->GetActFieldDescr()->GetName() == *pKeyBegin)
934                     {
935                         (*rowIter)->SetPrimaryKey(sal_True);
936                         break;
937                     }
938                 }
939             }
940         }
941     }
942 
943     //////////////////////////////////////////////////////////////////////
944     // Leere Zeilen füllen
945 
946     OTypeInfoMap::iterator aTypeIter = m_aTypeInfo.find(DataType::VARCHAR);
947     if(aTypeIter == m_aTypeInfo.end())
948         aTypeIter = m_aTypeInfo.begin();
949 
950     OSL_ENSURE(aTypeIter != m_aTypeInfo.end(),"We have no type information!");
951 
952     bool bReadRow = !isAddAllowed();
953     for(sal_Int32 i=m_vRowList.size(); i < NEWCOLS; i++ )
954     {
955         pTabEdRow.reset(new OTableRow());
956         pTabEdRow->SetReadOnly(bReadRow);
957         m_vRowList.push_back( pTabEdRow);
958     }
959 }
960 // -----------------------------------------------------------------------------
961 Reference<XNameAccess> OTableController::getKeyColumns() const
962 {
963     return getPrimaryKeyColumns_throw(m_xTable);
964 }
965 // -----------------------------------------------------------------------------
966 sal_Bool OTableController::checkColumns(sal_Bool _bNew) throw(::com::sun::star::sdbc::SQLException)
967 {
968     sal_Bool bOk = sal_True;
969     sal_Bool bFoundPKey = sal_False;
970     Reference< XDatabaseMetaData > xMetaData = getMetaData( );
971     DatabaseMetaData aMetaData( getConnection() );
972 
973     ::comphelper::UStringMixEqual bCase(xMetaData.is() ? xMetaData->supportsMixedCaseQuotedIdentifiers() : sal_True);
974     ::std::vector< ::boost::shared_ptr<OTableRow> >::const_iterator aIter = m_vRowList.begin();
975     ::std::vector< ::boost::shared_ptr<OTableRow> >::const_iterator aEnd = m_vRowList.end();
976     for(;aIter != aEnd;++aIter)
977     {
978         OFieldDescription* pFieldDesc = (*aIter)->GetActFieldDescr();
979         if (pFieldDesc && pFieldDesc->GetName().getLength())
980         {
981             bFoundPKey |=  (*aIter)->IsPrimaryKey();
982             // first check for duplicate names
983             ::std::vector< ::boost::shared_ptr<OTableRow> >::const_iterator aIter2 = aIter+1;
984             for(;aIter2 != aEnd;++aIter2)
985             {
986                 OFieldDescription* pCompareDesc = (*aIter2)->GetActFieldDescr();
987                 if (pCompareDesc && bCase(pCompareDesc->GetName(),pFieldDesc->GetName()))
988                 {
989                     String strMessage = String(ModuleRes(STR_TABLEDESIGN_DUPLICATE_NAME));
990                     strMessage.SearchAndReplaceAscii("$column$", pFieldDesc->GetName());
991                     OSQLWarningBox( getView(), strMessage ).Execute();
992                     return sal_False;
993                 }
994             }
995         }
996     }
997     if ( _bNew && !bFoundPKey && aMetaData.supportsPrimaryKeys() )
998     {
999         String sTitle(ModuleRes(STR_TABLEDESIGN_NO_PRIM_KEY_HEAD));
1000         String sMsg(ModuleRes(STR_TABLEDESIGN_NO_PRIM_KEY));
1001         OSQLMessageBox aBox(getView(), sTitle,sMsg, WB_YES_NO_CANCEL | WB_DEF_YES);
1002 
1003         switch ( aBox.Execute() )
1004         {
1005         case RET_YES:
1006         {
1007             ::boost::shared_ptr<OTableRow>  pNewRow(new OTableRow());
1008             TOTypeInfoSP pTypeInfo = ::dbaui::queryPrimaryKeyType(m_aTypeInfo);
1009             if ( !pTypeInfo.get() )
1010                 break;
1011 
1012             pNewRow->SetFieldType( pTypeInfo );
1013             OFieldDescription* pActFieldDescr = pNewRow->GetActFieldDescr();
1014 
1015             pActFieldDescr->SetAutoIncrement(sal_False); // #95927# pTypeInfo->bAutoIncrement
1016             pActFieldDescr->SetIsNullable(ColumnValue::NO_NULLS);
1017 
1018             pActFieldDescr->SetName( createUniqueName(::rtl::OUString::createFromAscii("ID") ));
1019             pActFieldDescr->SetPrimaryKey( sal_True );
1020             m_vRowList.insert(m_vRowList.begin(),pNewRow);
1021 
1022             static_cast<OTableDesignView*>(getView())->GetEditorCtrl()->Invalidate();
1023             static_cast<OTableDesignView*>(getView())->GetEditorCtrl()->RowInserted(0);
1024         }
1025         break;
1026         case RET_CANCEL:
1027             bOk = sal_False;
1028             break;
1029         }
1030     }
1031     return bOk;
1032 }
1033 // -----------------------------------------------------------------------------
1034 void OTableController::alterColumns()
1035 {
1036     Reference<XColumnsSupplier> xColSup(m_xTable,UNO_QUERY_THROW);
1037     OSL_ENSURE(xColSup.is(),"What happen here?!");
1038 
1039     Reference<XNameAccess> xColumns = xColSup->getColumns();
1040     Reference<XIndexAccess> xIdxColumns(xColumns,UNO_QUERY_THROW);
1041     OSL_ENSURE(xColumns.is(),"No columns");
1042     if ( !xColumns.is() )
1043         return;
1044     Reference<XAlterTable> xAlter(m_xTable,UNO_QUERY);  // can be null
1045 
1046     sal_Int32 nColumnCount = xIdxColumns->getCount();
1047     Reference<XDrop> xDrop(xColumns,UNO_QUERY);         // can be null
1048     Reference<XAppend> xAppend(xColumns,UNO_QUERY);     // can be null
1049     Reference<XDataDescriptorFactory> xColumnFactory(xColumns,UNO_QUERY); // can be null
1050 
1051     sal_Bool bReload = sal_False; // refresh the data
1052 
1053     // contains all columns names which are already handled those which are not in the list will be deleted
1054     Reference< XDatabaseMetaData> xMetaData = getMetaData( );
1055 
1056     ::std::map< ::rtl::OUString,sal_Bool,::comphelper::UStringMixLess> aColumns(xMetaData.is() ? (xMetaData->supportsMixedCaseQuotedIdentifiers() ? true : false): sal_True);
1057     ::std::vector< ::boost::shared_ptr<OTableRow> >::iterator aIter = m_vRowList.begin();
1058     ::std::vector< ::boost::shared_ptr<OTableRow> >::iterator aEnd = m_vRowList.end();
1059     // first look for columns where something other than the name changed
1060     sal_Int32 nPos = 0;
1061     for(;aIter != aEnd;++aIter,++nPos)
1062     {
1063         OSL_ENSURE(*aIter,"OTableRow is null!");
1064         OFieldDescription* pField = (*aIter)->GetActFieldDescr();
1065         if ( !pField )
1066             continue;
1067         if ( (*aIter)->IsReadOnly() )
1068         {
1069             aColumns[pField->GetName()] = sal_True;
1070             continue;
1071         }
1072 
1073         Reference<XPropertySet> xColumn;
1074         if ( xColumns->hasByName(pField->GetName()) )
1075         {
1076             aColumns[pField->GetName()] = sal_True;
1077             xColumns->getByName(pField->GetName()) >>= xColumn;
1078             OSL_ENSURE(xColumn.is(),"Column is null!");
1079 
1080             sal_Int32 nType=0,nPrecision=0,nScale=0,nNullable=0;
1081             sal_Bool bAutoIncrement = false;
1082             ::rtl::OUString sTypeName,sDescription;
1083 
1084             xColumn->getPropertyValue(PROPERTY_TYPE)            >>= nType;
1085             xColumn->getPropertyValue(PROPERTY_PRECISION)       >>= nPrecision;
1086             xColumn->getPropertyValue(PROPERTY_SCALE)           >>= nScale;
1087             xColumn->getPropertyValue(PROPERTY_ISNULLABLE)      >>= nNullable;
1088             xColumn->getPropertyValue(PROPERTY_ISAUTOINCREMENT) >>= bAutoIncrement;
1089             xColumn->getPropertyValue(PROPERTY_DESCRIPTION)     >>= sDescription;
1090 
1091             try { xColumn->getPropertyValue(PROPERTY_TYPENAME) >>= sTypeName; }
1092             catch( const Exception& )
1093             {
1094                 OSL_ENSURE( sal_False, "no TypeName property?!" );
1095                 // since this is a last minute fix for #i41785#, I want to be on the safe side,
1096                 // and catch errors here as early as possible (instead of the whole process of altering
1097                 // the columns failing)
1098                 // Normally, sdbcx::Column objects are expected to have a TypeName property
1099             }
1100 
1101             //  xColumn->getPropertyValue(PROPERTY_ISCURRENCY,::cppu::bool2any(pField->IsCurrency()));
1102             // check if something changed
1103             if((nType != pField->GetType()                  ||
1104                 sTypeName != pField->GetTypeName()         ||
1105                 (nPrecision != pField->GetPrecision() && nPrecision )       ||
1106                 nScale != pField->GetScale()                ||
1107                 nNullable != pField->GetIsNullable()        ||
1108                 sDescription != pField->GetDescription()        ||
1109                 bAutoIncrement != pField->IsAutoIncrement())&&
1110                 xColumnFactory.is())
1111             {
1112                 Reference<XPropertySet> xNewColumn;
1113                 xNewColumn = xColumnFactory->createDataDescriptor();
1114                 ::dbaui::setColumnProperties(xNewColumn,pField);
1115                 // first try to alter the column
1116                 sal_Bool bNotOk = sal_False;
1117                 try
1118                 {
1119                     // first try if we can alter the column
1120                     if(xAlter.is())
1121                         xAlter->alterColumnByName(pField->GetName(),xNewColumn);
1122                 }
1123                 catch(const SQLException&)
1124                 {
1125                     if(xDrop.is() && xAppend.is())
1126                     {
1127                         String aMessage( ModuleRes( STR_TABLEDESIGN_ALTER_ERROR ) );
1128                         aMessage.SearchAndReplaceAscii( "$column$", pField->GetName() );
1129 
1130                         SQLExceptionInfo aError( ::cppu::getCaughtException() );
1131                         OSQLWarningBox aMsg( getView(), aMessage, WB_YES_NO | WB_DEF_YES , &aError );
1132                         bNotOk = aMsg.Execute() == RET_YES;
1133                     }
1134                     else
1135                         throw;
1136                 }
1137                 // if something went wrong or we can't alter columns
1138                 // drop and append a new one
1139                 if((!xAlter.is() || bNotOk) && xDrop.is() && xAppend.is())
1140                 {
1141                     xDrop->dropByName(pField->GetName());
1142                     try
1143                     {
1144                         xAppend->appendByDescriptor(xNewColumn);
1145                     }
1146                     catch(const SQLException&)
1147                     { // an error occurred so we try to reactivate the old one
1148                         xAppend->appendByDescriptor(xColumn);
1149                         throw;
1150                     }
1151                 }
1152                 // exceptions are caught outside
1153                 xNewColumn = NULL;
1154                 if(xColumns->hasByName(pField->GetName()))
1155                     xColumns->getByName(pField->GetName()) >>= xColumn;
1156                 bReload = sal_True;
1157             }
1158 
1159 
1160         }
1161         else if(xColumnFactory.is() && xAlter.is() && nPos < nColumnCount)
1162         { // we can't find the column so we could try it with the index before we drop and append a new column
1163             try
1164             {
1165                 Reference<XPropertySet> xNewColumn;
1166                 xNewColumn = xColumnFactory->createDataDescriptor();
1167                 ::dbaui::setColumnProperties(xNewColumn,pField);
1168                 xAlter->alterColumnByIndex(nPos,xNewColumn);
1169                 if(xColumns->hasByName(pField->GetName()))
1170                 {   // ask for the append by name
1171                     aColumns[pField->GetName()] = sal_True;
1172                     xColumns->getByName(pField->GetName()) >>= xColumn;
1173                     if(xColumn.is())
1174                         pField->copyColumnSettingsTo(xColumn);
1175                 }
1176                 else
1177                 {
1178                     OSL_ENSURE(sal_False, "OTableController::alterColumns: invalid column (2)!");
1179                 }
1180             }
1181             catch(const SQLException&)
1182             { // we couldn't alter the column so we have to add new columns
1183                 bReload = sal_True;
1184                 if(xDrop.is() && xAppend.is())
1185                 {
1186                     String aMessage(ModuleRes(STR_TABLEDESIGN_ALTER_ERROR));
1187                     aMessage.SearchAndReplaceAscii("$column$",pField->GetName());
1188                     OSQLWarningBox aMsg( getView(), aMessage, WB_YES_NO | WB_DEF_YES );
1189                     if ( aMsg.Execute() != RET_YES )
1190                     {
1191                         Reference<XPropertySet> xNewColumn(xIdxColumns->getByIndex(nPos),UNO_QUERY_THROW);
1192                         ::rtl::OUString sName;
1193                         xNewColumn->getPropertyValue(PROPERTY_NAME) >>= sName;
1194                         aColumns[sName] = sal_True;
1195                         aColumns[pField->GetName()] = sal_True;
1196                         continue;
1197                     }
1198                 }
1199                 else
1200                     throw;
1201             }
1202         }
1203         else
1204             bReload = sal_True;
1205     } // for(sal_Int32 nPos = 0;aIter != aEnd;++aIter,++nPos)
1206     // alter column settings
1207     aIter = m_vRowList.begin();
1208 
1209     // first look for columns where something other than the name changed
1210     for(nPos = 0;aIter != aEnd;++aIter,++nPos)
1211     {
1212         OSL_ENSURE(*aIter,"OTableRow is null!");
1213         OFieldDescription* pField = (*aIter)->GetActFieldDescr();
1214         if ( !pField )
1215             continue;
1216         if ( (*aIter)->IsReadOnly() )
1217         {
1218             aColumns[pField->GetName()] = sal_True;
1219             continue;
1220         }
1221 
1222         Reference<XPropertySet> xColumn;
1223         if ( xColumns->hasByName(pField->GetName()) )
1224         {
1225             xColumns->getByName(pField->GetName()) >>= xColumn;
1226             Reference<XPropertySetInfo> xInfo = xColumn->getPropertySetInfo();
1227             if ( xInfo->hasPropertyByName(PROPERTY_HELPTEXT) )
1228                 xColumn->setPropertyValue(PROPERTY_HELPTEXT,makeAny(pField->GetHelpText()));
1229 
1230             if(xInfo->hasPropertyByName(PROPERTY_CONTROLDEFAULT))
1231                 xColumn->setPropertyValue(PROPERTY_CONTROLDEFAULT,pField->GetControlDefault());
1232             if(xInfo->hasPropertyByName(PROPERTY_FORMATKEY))
1233                 xColumn->setPropertyValue(PROPERTY_FORMATKEY,makeAny(pField->GetFormatKey()));
1234             if(xInfo->hasPropertyByName(PROPERTY_ALIGN))
1235                 xColumn->setPropertyValue(PROPERTY_ALIGN,makeAny(dbaui::mapTextAllign(pField->GetHorJustify())));
1236         } // if ( xColumns->hasByName(pField->GetName()) )
1237     }
1238     // second drop all columns which could be found by name
1239     Reference<XNameAccess> xKeyColumns  = getKeyColumns();
1240     // now we have to look for the columns who could be deleted
1241     if ( xDrop.is() )
1242     {
1243         Sequence< ::rtl::OUString> aColumnNames = xColumns->getElementNames();
1244         const ::rtl::OUString* pIter = aColumnNames.getConstArray();
1245         const ::rtl::OUString* pEnd = pIter + aColumnNames.getLength();
1246         for(;pIter != pEnd;++pIter)
1247         {
1248             if(aColumns.find(*pIter) == aColumns.end()) // found a column to delete
1249             {
1250                 if(xKeyColumns.is() && xKeyColumns->hasByName(*pIter)) // check if this column is a member of the primary key
1251                 {
1252                     String aMsgT(ModuleRes(STR_TBL_COLUMN_IS_KEYCOLUMN));
1253                     aMsgT.SearchAndReplaceAscii("$column$",*pIter);
1254                     String aTitle(ModuleRes(STR_TBL_COLUMN_IS_KEYCOLUMN_TITLE));
1255                     OSQLMessageBox aMsg(getView(),aTitle,aMsgT,WB_YES_NO| WB_DEF_YES);
1256                     if(aMsg.Execute() == RET_YES)
1257                     {
1258                         xKeyColumns = NULL;
1259                         dropPrimaryKey();
1260                     }
1261                     else
1262                     {
1263                         bReload = sal_True;
1264                         continue;
1265                     }
1266                 }
1267                 try
1268                 {
1269                     xDrop->dropByName(*pIter);
1270                 }
1271                 catch (const SQLException&)
1272                 {
1273                     String sError( ModuleRes( STR_TABLEDESIGN_COULD_NOT_DROP_COL ) );
1274                     sError.SearchAndReplaceAscii( "$column$", *pIter );
1275 
1276                     SQLException aNewException;
1277                     aNewException.Message = sError;
1278                     aNewException.SQLState = ::rtl::OUString::createFromAscii( "S1000" );
1279                     aNewException.NextException = ::cppu::getCaughtException();
1280 
1281                     throw aNewException;
1282                 }
1283             }
1284         }
1285     }
1286 
1287     // third append the new columns
1288     aIter = m_vRowList.begin();
1289     for(;aIter != aEnd;++aIter)
1290     {
1291         OSL_ENSURE(*aIter,"OTableRow is null!");
1292         OFieldDescription* pField = (*aIter)->GetActFieldDescr();
1293         if ( !pField || (*aIter)->IsReadOnly() || aColumns.find(pField->GetName()) != aColumns.end() )
1294             continue;
1295 
1296         Reference<XPropertySet> xColumn;
1297         if(!xColumns->hasByName(pField->GetName()))
1298         {
1299             if(xColumnFactory.is() && xAppend.is())
1300             {// column not found by its name so we assume it is new
1301                 // Column is new
1302                 xColumn = xColumnFactory->createDataDescriptor();
1303                 ::dbaui::setColumnProperties(xColumn,pField);
1304                 xAppend->appendByDescriptor(xColumn);
1305                 if(xColumns->hasByName(pField->GetName()))
1306                 {   // ask for the append by name
1307                     aColumns[pField->GetName()] = sal_True;
1308                     xColumns->getByName(pField->GetName()) >>= xColumn;
1309                     if(xColumn.is())
1310                         pField->copyColumnSettingsTo(xColumn);
1311                 }
1312                 else
1313                 {
1314                     OSL_ENSURE(sal_False, "OTableController::alterColumns: invalid column!");
1315                 }
1316             }
1317         }
1318     }
1319 
1320 
1321     // check if we have to do something with the primary key
1322     sal_Bool bNeedDropKey = sal_False;
1323     sal_Bool bNeedAppendKey = sal_False;
1324     if ( xKeyColumns.is() )
1325     {
1326         aIter = m_vRowList.begin();
1327         for(;aIter != aEnd;++aIter)
1328         {
1329             OSL_ENSURE(*aIter,"OTableRow is null!");
1330             OFieldDescription* pField = (*aIter)->GetActFieldDescr();
1331             if ( !pField )
1332                 continue;
1333 
1334             if  (   pField->IsPrimaryKey()
1335                 &&  !xKeyColumns->hasByName( pField->GetName() )
1336                 )
1337             {   // new primary key column inserted which isn't already in the columns selection
1338                 bNeedDropKey = bNeedAppendKey = sal_True;
1339                 break;
1340             }
1341             else if (   !pField->IsPrimaryKey()
1342                     &&  xKeyColumns->hasByName( pField->GetName() )
1343                     )
1344             {   // found a column which currently is in the primary key, but is marked not to be anymore
1345                 bNeedDropKey = bNeedAppendKey = sal_True;
1346                 break;
1347             }
1348         }
1349     }
1350     else
1351     {   // no primary key available so we check if we should create one
1352         bNeedAppendKey = sal_True;
1353     }
1354 
1355     if ( bNeedDropKey && xKeyColumns.is() && xKeyColumns->getElementNames().getLength() )
1356         dropPrimaryKey();
1357 
1358     if ( bNeedAppendKey )
1359     {
1360         Reference< XKeysSupplier > xKeySup( m_xTable, UNO_QUERY );
1361         appendPrimaryKey( xKeySup ,sal_False);
1362     }
1363 
1364     reSyncRows();
1365 
1366     if ( bReload )
1367         reload();
1368 }
1369 // -----------------------------------------------------------------------------
1370 void OTableController::dropPrimaryKey()
1371 {
1372     SQLExceptionInfo aInfo;
1373     try
1374     {
1375         Reference<XKeysSupplier> xKeySup(m_xTable,UNO_QUERY);
1376         Reference<XIndexAccess> xKeys;
1377         if(xKeySup.is())
1378             xKeys = xKeySup->getKeys();
1379 
1380         if(xKeys.is())
1381         {
1382             Reference<XPropertySet> xProp;
1383             for(sal_Int32 i=0;i< xKeys->getCount();++i)
1384             {
1385                 xProp.set(xKeys->getByIndex(i),UNO_QUERY);
1386                 sal_Int32 nKeyType = 0;
1387                 xProp->getPropertyValue(PROPERTY_TYPE) >>= nKeyType;
1388                 if(KeyType::PRIMARY == nKeyType)
1389                 {
1390                     Reference<XDrop> xDrop(xKeys,UNO_QUERY);
1391                     xDrop->dropByIndex(i); // delete the key
1392                     break;
1393                 }
1394             }
1395         }
1396     }
1397     catch(const SQLContext& e)
1398     {
1399         aInfo = SQLExceptionInfo(e);
1400     }
1401     catch(const SQLWarning& e)
1402     {
1403         aInfo = SQLExceptionInfo(e);
1404     }
1405     catch(const SQLException& e)
1406     {
1407         aInfo = SQLExceptionInfo(e);
1408     }
1409     catch( const Exception& )
1410     {
1411         DBG_UNHANDLED_EXCEPTION();
1412     }
1413 
1414     showError(aInfo);
1415 }
1416 // -----------------------------------------------------------------------------
1417 void OTableController::assignTable()
1418 {
1419     ::rtl::OUString sComposedName;
1420     // get the table
1421     if(m_sName.getLength())
1422     {
1423         Reference<XNameAccess> xNameAccess;
1424         Reference<XTablesSupplier> xSup(getConnection(),UNO_QUERY);
1425         if(xSup.is())
1426         {
1427             xNameAccess = xSup->getTables();
1428             OSL_ENSURE(xNameAccess.is(),"no nameaccess for the queries!");
1429 
1430             Reference<XPropertySet> xProp;
1431             if(xNameAccess->hasByName(m_sName) && ::cppu::extractInterface(xProp,xNameAccess->getByName(m_sName)) && xProp.is())
1432             {
1433                 m_xTable = xProp;
1434                 startTableListening();
1435 
1436                 // check if we set the table editable
1437                 Reference<XDatabaseMetaData> xMeta = getConnection()->getMetaData();
1438                 setEditable( xMeta.is() && !xMeta->isReadOnly() && (isAlterAllowed() || isDropAllowed() || isAddAllowed()) );
1439                 if(!isEditable())
1440                 {
1441                     static const sal_Bool aTrue = sal_True;
1442                     ::std::for_each(m_vRowList.begin(),m_vRowList.end(),boost::bind( &OTableRow::SetReadOnly, _1, boost::cref( aTrue )));
1443                 }
1444                 m_bNew = sal_False;
1445                 // be notified when the table is in disposing
1446                 InvalidateAll();
1447             }
1448         }
1449     }
1450     //updateTitle();
1451 }
1452 // -----------------------------------------------------------------------------
1453 sal_Bool OTableController::isAddAllowed() const
1454 {
1455     Reference<XColumnsSupplier> xColsSup(m_xTable,UNO_QUERY);
1456     sal_Bool bAddAllowed = !m_xTable.is();
1457     if(xColsSup.is())
1458         bAddAllowed = Reference<XAppend>(xColsSup->getColumns(),UNO_QUERY).is();
1459 
1460     try
1461     {
1462         Reference< XDatabaseMetaData > xMetaData = getMetaData( );
1463         bAddAllowed = bAddAllowed || ( xMetaData.is() && xMetaData->supportsAlterTableWithAddColumn());
1464     }
1465     catch(Exception&)
1466     {
1467         DBG_UNHANDLED_EXCEPTION();
1468         bAddAllowed = sal_False;
1469     }
1470 
1471     return bAddAllowed;
1472 }
1473 // -----------------------------------------------------------------------------
1474 sal_Bool OTableController::isDropAllowed() const
1475 {
1476     Reference<XColumnsSupplier> xColsSup(m_xTable,UNO_QUERY);
1477     sal_Bool bDropAllowed = !m_xTable.is();
1478     if(xColsSup.is())
1479     {
1480         Reference<XNameAccess> xNameAccess = xColsSup->getColumns();
1481         bDropAllowed = Reference<XDrop>(xNameAccess,UNO_QUERY).is() && xNameAccess->hasElements();
1482     }
1483 
1484     Reference< XDatabaseMetaData> xMetaData = getMetaData( );
1485     bDropAllowed = bDropAllowed || ( xMetaData.is() && xMetaData->supportsAlterTableWithDropColumn());
1486 
1487     return bDropAllowed;
1488 }
1489 // -----------------------------------------------------------------------------
1490 sal_Bool OTableController::isAlterAllowed() const
1491 {
1492     sal_Bool bAllowed(!m_xTable.is() || Reference<XAlterTable>(m_xTable,UNO_QUERY).is());
1493     return bAllowed;
1494 }
1495 // -----------------------------------------------------------------------------
1496 void OTableController::reSyncRows()
1497 {
1498     sal_Bool bAlterAllowed  = isAlterAllowed();
1499     sal_Bool bAddAllowed    = isAddAllowed();
1500     ::std::vector< ::boost::shared_ptr<OTableRow> >::iterator aIter = m_vRowList.begin();
1501     ::std::vector< ::boost::shared_ptr<OTableRow> >::iterator aEnd = m_vRowList.end();
1502     for(;aIter != aEnd;++aIter)
1503     {
1504         OSL_ENSURE(*aIter,"OTableRow is null!");
1505         OFieldDescription* pField = (*aIter)->GetActFieldDescr();
1506         if ( pField )
1507             (*aIter)->SetReadOnly(!bAlterAllowed);
1508         else
1509             (*aIter)->SetReadOnly(!bAddAllowed);
1510 
1511     }
1512     static_cast<OTableDesignView*>(getView())->reSync();    // show the windows and fill with our information
1513 
1514     ClearUndoManager();
1515     setModified(sal_False);     // and we are not modified yet
1516 }
1517 // -----------------------------------------------------------------------------
1518 ::rtl::OUString OTableController::createUniqueName(const ::rtl::OUString& _rName)
1519 {
1520     ::rtl::OUString sName = _rName;
1521     Reference< XDatabaseMetaData> xMetaData = getMetaData( );
1522 
1523     ::comphelper::UStringMixEqual bCase(xMetaData.is() ? xMetaData->supportsMixedCaseQuotedIdentifiers() : sal_True);
1524 
1525     ::std::vector< ::boost::shared_ptr<OTableRow> >::const_iterator aIter = m_vRowList.begin();
1526     ::std::vector< ::boost::shared_ptr<OTableRow> >::const_iterator aEnd = m_vRowList.end();
1527     for(sal_Int32 i=0;aIter != aEnd;++aIter)
1528     {
1529         OFieldDescription* pFieldDesc = (*aIter)->GetActFieldDescr();
1530         if (pFieldDesc && pFieldDesc->GetName().getLength() && bCase(sName,pFieldDesc->GetName()))
1531         { // found a second name of _rName so we need another
1532             sName = _rName + ::rtl::OUString::valueOf(++i);
1533             aIter = m_vRowList.begin(); // and retry
1534         }
1535     }
1536     return sName;
1537 }
1538 // -----------------------------------------------------------------------------
1539 ::rtl::OUString OTableController::getPrivateTitle() const
1540 {
1541     ::rtl::OUString sTitle;
1542     try
1543     {
1544         // get the table
1545         if ( m_sName.getLength() && getConnection().is() )
1546         {
1547             if ( m_xTable.is() )
1548                 sTitle = ::dbtools::composeTableName( getConnection()->getMetaData(), m_xTable, ::dbtools::eInDataManipulation, false, false, false );
1549             else
1550                 sTitle = m_sName;
1551         }
1552         if ( !sTitle.getLength() )
1553         {
1554             String aName = String(ModuleRes(STR_TBL_TITLE));
1555             sTitle = aName.GetToken(0,' ');
1556             sTitle += ::rtl::OUString::valueOf(getCurrentStartNumber());
1557         }
1558     }
1559     catch( const Exception& )
1560     {
1561         DBG_UNHANDLED_EXCEPTION();
1562     }
1563     return sTitle;
1564 }
1565 // -----------------------------------------------------------------------------
1566 void OTableController::reload()
1567 {
1568     loadData();                 // fill the column information form the table
1569     static_cast<OTableDesignView*>(getView())->reSync();    // show the windows and fill with our information
1570     ClearUndoManager();
1571     setModified(sal_False);     // and we are not modified yet
1572     static_cast<OTableDesignView*>(getView())->Invalidate();
1573 }
1574 // -----------------------------------------------------------------------------
1575 sal_Int32 OTableController::getFirstEmptyRowPosition()
1576 {
1577     sal_Int32 nRet = -1;
1578     ::std::vector< ::boost::shared_ptr<OTableRow> >::const_iterator aIter = m_vRowList.begin();
1579     ::std::vector< ::boost::shared_ptr<OTableRow> >::const_iterator aEnd = m_vRowList.end();
1580     for(;aIter != aEnd;++aIter)
1581     {
1582         if ( !*aIter || !(*aIter)->GetActFieldDescr() || !(*aIter)->GetActFieldDescr()->GetName().getLength() )
1583         {
1584             nRet = aIter - m_vRowList.begin();
1585             break;
1586         }
1587     }
1588     if ( nRet == -1 )
1589     {
1590         bool bReadRow = !isAddAllowed();
1591         ::boost::shared_ptr<OTableRow> pTabEdRow(new OTableRow());
1592         pTabEdRow->SetReadOnly(bReadRow);
1593         nRet = m_vRowList.size();
1594         m_vRowList.push_back( pTabEdRow);
1595     }
1596     return nRet;
1597 }
1598 // -----------------------------------------------------------------------------
1599 bool OTableController::isAutoIncrementPrimaryKey() const
1600 {
1601     return getSdbMetaData().isAutoIncrementPrimaryKey();
1602 }
1603 // -----------------------------------------------------------------------------
1604 
1605 /* vim: set noet sw=4 ts=4: */
1606