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