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