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 "RelationTableView.hxx" 28 29 30 #include "JoinExchange.hxx" 31 32 33 #include <comphelper/extract.hxx> 34 35 36 #include "browserids.hxx" 37 38 39 #include <com/sun/star/sdbcx/XTablesSupplier.hpp> 40 41 42 #include <com/sun/star/sdbc/XConnection.hpp> 43 44 45 #include <com/sun/star/sdbcx/XKeysSupplier.hpp> 46 47 48 #include <com/sun/star/sdbcx/XColumnsSupplier.hpp> 49 50 51 #include <com/sun/star/sdbcx/KeyType.hpp> 52 53 #include <com/sun/star/container/XIndexAccess.hpp> 54 #include <com/sun/star/container/XNameAccess.hpp> 55 #include <com/sun/star/beans/XPropertySet.hpp> 56 #include "dbustrings.hrc" 57 #include <connectivity/dbtools.hxx> 58 #include <comphelper/sequence.hxx> 59 #include <tools/debug.hxx> 60 #include "dbaccess_helpid.hrc" 61 #include "RelationDesignView.hxx" 62 #include "JoinController.hxx" 63 #include "TableWindow.hxx" 64 #include "TableWindowData.hxx" 65 #include "RTableConnection.hxx" 66 #include "RTableConnectionData.hxx" 67 #include "RelationDlg.hxx" 68 #include "sqlmessage.hxx" 69 #include "dbu_rel.hrc" 70 #include "UITools.hxx" 71 #include <connectivity/dbexception.hxx> 72 #include "RTableWindow.hxx" 73 #include "JAccess.hxx" 74 #include <svl/undo.hxx> 75 #include <com/sun/star/accessibility/AccessibleEventId.hpp> 76 77 using namespace dbaui; 78 using namespace ::dbtools; 79 using namespace ::com::sun::star; 80 using namespace ::com::sun::star::uno; 81 using namespace ::com::sun::star::sdbc; 82 using namespace ::com::sun::star::sdbcx; 83 using namespace ::com::sun::star::beans; 84 using namespace ::com::sun::star::container; 85 using namespace ::com::sun::star::accessibility; 86 87 //================================================================== 88 // class ORelationTableView 89 //================================================================== 90 DBG_NAME(ORelationTableView) 91 //------------------------------------------------------------------------ 92 ORelationTableView::ORelationTableView( Window* pParent, ORelationDesignView* pView ) 93 :OJoinTableView( pParent, pView ) 94 , ::comphelper::OContainerListener(m_aMutex) 95 ,m_pExistingConnection(NULL) 96 ,m_bInRemove(false) 97 98 { 99 DBG_CTOR(ORelationTableView,NULL); 100 SetHelpId(HID_CTL_RELATIONTAB); 101 } 102 103 //------------------------------------------------------------------------ 104 ORelationTableView::~ORelationTableView() 105 { 106 DBG_DTOR(ORelationTableView,NULL); 107 if ( m_pContainerListener.is() ) 108 m_pContainerListener->dispose(); 109 } 110 111 //------------------------------------------------------------------------ 112 void ORelationTableView::ReSync() 113 { 114 DBG_CHKTHIS(ORelationTableView,NULL); 115 if ( !m_pContainerListener.is() ) 116 { 117 Reference< XConnection> xConnection = m_pView->getController().getConnection(); 118 Reference< XTablesSupplier > xTableSupp( xConnection, UNO_QUERY_THROW ); 119 Reference< XNameAccess > xTables = xTableSupp->getTables(); 120 Reference< XContainer> xContainer(xTables,uno::UNO_QUERY); 121 if ( xContainer.is() ) 122 m_pContainerListener = new ::comphelper::OContainerListenerAdapter(this,xContainer); 123 } 124 // Es kann sein, dass in der DB Tabellen ausgeblendet wurden, die eigentlich Bestandteil einer Relation sind. Oder eine Tabelle 125 // befand sich im Layout (durchaus ohne Relation), existiert aber nicht mehr. In beiden Faellen wird das Anlegen des TabWins schief 126 // gehen, und alle solchen TabWinDatas oder darauf bezogenen ConnDatas muss ich dann loeschen. 127 ::std::vector< ::rtl::OUString> arrInvalidTables; 128 129 ////////////////////////////////////////////////////////////////////// 130 // create and insert windows 131 TTableWindowData* pTabWinDataList = m_pView->getController().getTableWindowData(); 132 TTableWindowData::reverse_iterator aIter = pTabWinDataList->rbegin(); 133 for(;aIter != pTabWinDataList->rend();++aIter) 134 { 135 TTableWindowData::value_type pData = *aIter; 136 OTableWindow* pTabWin = createWindow(pData); 137 138 if (!pTabWin->Init()) 139 { 140 // das Initialisieren ging schief, dass heisst, dieses TabWin steht nicht zur Verfuegung, also muss ich es inklusive 141 // seiner Daten am Dokument aufraeumen 142 pTabWin->clearListBox(); 143 delete pTabWin; 144 arrInvalidTables.push_back(pData->GetTableName()); 145 146 pTabWinDataList->erase( ::std::remove(pTabWinDataList->begin(),pTabWinDataList->end(),*aIter) ,pTabWinDataList->end()); 147 continue; 148 } 149 150 (*GetTabWinMap())[pData->GetComposedName()] = pTabWin; // am Anfang einfuegen, da ich die DataList ja rueckwaerts durchlaufe 151 // wenn in den Daten keine Position oder Groesse steht -> Default 152 if (!pData->HasPosition() && !pData->HasSize()) 153 SetDefaultTabWinPosSize(pTabWin); 154 155 pTabWin->Show(); 156 } 157 158 // Verbindungen einfuegen 159 TTableConnectionData* pTabConnDataList = m_pView->getController().getTableConnectionData(); 160 TTableConnectionData::reverse_iterator aConIter = pTabConnDataList->rbegin(); 161 162 for(;aConIter != pTabConnDataList->rend();++aConIter) 163 { 164 ORelationTableConnectionData* pTabConnData = static_cast<ORelationTableConnectionData*>(aConIter->get()); 165 if ( !arrInvalidTables.empty() ) 166 { 167 // gibt es die beiden Tabellen zur Connection ? 168 ::rtl::OUString strTabExistenceTest = pTabConnData->getReferencingTable()->GetTableName(); 169 sal_Bool bInvalid = ::std::find(arrInvalidTables.begin(),arrInvalidTables.end(),strTabExistenceTest) != arrInvalidTables.end(); 170 strTabExistenceTest = pTabConnData->getReferencedTable()->GetTableName(); 171 bInvalid = bInvalid || ::std::find(arrInvalidTables.begin(),arrInvalidTables.end(),strTabExistenceTest) != arrInvalidTables.end(); 172 173 if (bInvalid) 174 { // nein -> Pech gehabt, die Connection faellt weg 175 pTabConnDataList->erase( ::std::remove(pTabConnDataList->begin(),pTabConnDataList->end(),*aConIter),pTabConnDataList->end() ); 176 continue; 177 } 178 } // if ( !arrInvalidTables.empty() ) 179 180 addConnection( new ORelationTableConnection(this, *aConIter), sal_False ); // don't add the data again 181 } 182 183 if ( !GetTabWinMap()->empty() ) 184 GetTabWinMap()->begin()->second->GrabFocus(); 185 } 186 //------------------------------------------------------------------------------ 187 sal_Bool ORelationTableView::IsAddAllowed() 188 { 189 DBG_CHKTHIS(ORelationTableView,NULL); 190 191 return !m_pView->getController().isReadOnly(); 192 } 193 //------------------------------------------------------------------------ 194 void ORelationTableView::AddConnection(const OJoinExchangeData& jxdSource, const OJoinExchangeData& jxdDest) 195 { 196 DBG_CHKTHIS(ORelationTableView,NULL); 197 // Aus selektierten Feldnamen LineDataObject setzen 198 // check if relation already exists 199 OTableWindow* pSourceWin = jxdSource.pListBox->GetTabWin(); 200 OTableWindow* pDestWin = jxdDest.pListBox->GetTabWin(); 201 202 ::std::vector<OTableConnection*>::const_iterator aIter = getTableConnections()->begin(); 203 ::std::vector<OTableConnection*>::const_iterator aEnd = getTableConnections()->end(); 204 for(;aIter != aEnd;++aIter) 205 { 206 OTableConnection* pFirst = *aIter; 207 if((pFirst->GetSourceWin() == pSourceWin && pFirst->GetDestWin() == pDestWin) || 208 (pFirst->GetSourceWin() == pDestWin && pFirst->GetDestWin() == pSourceWin)) 209 { 210 m_pExistingConnection = pFirst; 211 break; 212 } 213 } 214 // insert table connection into view 215 216 TTableConnectionData::value_type pTabConnData(new ORelationTableConnectionData(pSourceWin->GetData(), 217 pDestWin->GetData())); 218 219 // die Namen der betroffenen Felder 220 ::rtl::OUString sSourceFieldName = jxdSource.pListBox->GetEntryText(jxdSource.pEntry); 221 ::rtl::OUString sDestFieldName = jxdDest.pListBox->GetEntryText(jxdDest.pEntry); 222 223 // die Anzahl der PKey-Felder in der Quelle 224 const Reference< XNameAccess> xPrimaryKeyColumns = getPrimaryKeyColumns_throw(pSourceWin->GetData()->getTable()); 225 bool bAskUser = xPrimaryKeyColumns.is() && Reference< XIndexAccess>(xPrimaryKeyColumns,UNO_QUERY)->getCount() > 1; 226 227 pTabConnData->SetConnLine( 0, sSourceFieldName, sDestFieldName ); 228 229 if ( bAskUser || m_pExistingConnection ) 230 m_pCurrentlyTabConnData = pTabConnData; // this implies that we ask the user what to do 231 else 232 { 233 try 234 { 235 ////////////////////////////////////////////////////////////////////// 236 // Daten der Datenbank uebergeben 237 if( pTabConnData->Update() ) 238 { 239 ////////////////////////////////////////////////////////////////////// 240 // UI-Object in ConnListe eintragen 241 addConnection( new ORelationTableConnection( this, pTabConnData ) ); 242 } 243 } 244 catch(const SQLException&) 245 { 246 throw; 247 } 248 catch(const Exception&) 249 { 250 OSL_ENSURE(0,"ORelationTableView::AddConnection: Exception oocured!"); 251 } 252 } 253 } 254 255 256 //------------------------------------------------------------------------ 257 void ORelationTableView::ConnDoubleClicked( OTableConnection* pConnection ) 258 { 259 DBG_CHKTHIS(ORelationTableView,NULL); 260 ORelationDialog aRelDlg( this, pConnection->GetData() ); 261 switch (aRelDlg.Execute()) 262 { 263 case RET_OK: 264 // successfully updated 265 pConnection->UpdateLineList(); 266 // The connection references 1 ConnData and n ConnLines, each ConnData references n LineDatas, each Line exactly 1 LineData 267 // As the Dialog and the ConnData->Update may have changed the LineDatas we have to restore the consistent state 268 break; 269 270 case RET_NO: 271 // tried at least one update, but did not succeed -> the original connection is lost 272 RemoveConnection( pConnection ,sal_True); 273 break; 274 275 case RET_CANCEL: 276 // no break, as nothing happened and we don't need the code below 277 return; 278 279 } 280 281 Invalidate(INVALIDATE_NOCHILDREN); 282 } 283 284 //------------------------------------------------------------------------------ 285 void ORelationTableView::AddNewRelation() 286 { 287 DBG_CHKTHIS(ORelationTableView,NULL); 288 289 TTableConnectionData::value_type pNewConnData( new ORelationTableConnectionData() ); 290 ORelationDialog aRelDlg(this, pNewConnData, sal_True); 291 292 sal_Bool bSuccess = (aRelDlg.Execute() == RET_OK); 293 if (bSuccess) 294 { 295 // already updated by the dialog 296 // dem Dokument bekanntgeben 297 addConnection( new ORelationTableConnection(this, pNewConnData) ); 298 } 299 } 300 301 //------------------------------------------------------------------------------ 302 bool ORelationTableView::RemoveConnection( OTableConnection* pConn ,sal_Bool /*_bDelete*/) 303 { 304 DBG_CHKTHIS(ORelationTableView,NULL); 305 ORelationTableConnectionData* pTabConnData = (ORelationTableConnectionData*)pConn->GetData().get(); 306 try 307 { 308 if ( m_bInRemove || pTabConnData->DropRelation()) 309 return OJoinTableView::RemoveConnection( pConn ,sal_True); 310 } 311 catch(SQLException& e) 312 { 313 getDesignView()->getController().showError(SQLExceptionInfo(e)); 314 } 315 catch(Exception&) 316 { 317 OSL_ENSURE(0,"ORelationTableView::RemoveConnection: Something other than SQLException occured!"); 318 } 319 return false; 320 } 321 322 //------------------------------------------------------------------------------ 323 void ORelationTableView::AddTabWin(const ::rtl::OUString& _rComposedName, const ::rtl::OUString& rWinName, sal_Bool /*bNewTable*/) 324 { 325 DBG_CHKTHIS(ORelationTableView,NULL); 326 OSL_ENSURE(_rComposedName.getLength(),"There must be a table name supplied!"); 327 OJoinTableView::OTableWindowMap::iterator aIter = GetTabWinMap()->find(_rComposedName); 328 329 if(aIter != GetTabWinMap()->end()) 330 { 331 aIter->second->SetZOrder(NULL, WINDOW_ZORDER_FIRST); 332 aIter->second->GrabFocus(); 333 EnsureVisible(aIter->second); 334 // no new one 335 return; 336 } 337 338 ////////////////////////////////////////////////////////////////// 339 // Neue Datenstruktur in DocShell eintragen 340 TTableWindowData::value_type pNewTabWinData(createTableWindowData( _rComposedName, rWinName,rWinName )); 341 pNewTabWinData->ShowAll(sal_False); 342 343 ////////////////////////////////////////////////////////////////// 344 // Neues Fenster in Fensterliste eintragen 345 OTableWindow* pNewTabWin = createWindow( pNewTabWinData ); 346 if(pNewTabWin->Init()) 347 { 348 m_pView->getController().getTableWindowData()->push_back( pNewTabWinData); 349 // when we already have a table with this name insert the full qualified one instead 350 (*GetTabWinMap())[_rComposedName] = pNewTabWin; 351 352 SetDefaultTabWinPosSize( pNewTabWin ); 353 pNewTabWin->Show(); 354 355 modified(); 356 357 if ( m_pAccessible ) 358 m_pAccessible->notifyAccessibleEvent( AccessibleEventId::CHILD, 359 Any(), 360 makeAny(pNewTabWin->GetAccessible())); 361 } 362 else 363 { 364 pNewTabWin->clearListBox(); 365 delete pNewTabWin; 366 } 367 } 368 // ----------------------------------------------------------------------------- 369 void ORelationTableView::RemoveTabWin( OTableWindow* pTabWin ) 370 { 371 OSQLWarningBox aDlg( this, ModuleRes( STR_QUERY_REL_DELETE_WINDOW ), WB_YES_NO | WB_DEF_YES ); 372 if ( m_bInRemove || aDlg.Execute() == RET_YES ) 373 { 374 m_pView->getController().ClearUndoManager(); 375 OJoinTableView::RemoveTabWin( pTabWin ); 376 377 m_pView->getController().InvalidateFeature(SID_RELATION_ADD_RELATION); 378 m_pView->getController().InvalidateFeature(ID_BROWSER_UNDO); 379 m_pView->getController().InvalidateFeature(ID_BROWSER_REDO); 380 } 381 } 382 383 // ----------------------------------------------------------------------------- 384 void ORelationTableView::lookForUiActivities() 385 { 386 if(m_pExistingConnection) 387 { 388 String sTitle(ModuleRes(STR_RELATIONDESIGN)); 389 sTitle.Erase(0,3); 390 OSQLMessageBox aDlg(this,ModuleRes(STR_QUERY_REL_EDIT_RELATION),String(),0); 391 aDlg.SetText(sTitle); 392 aDlg.RemoveButton(aDlg.GetButtonId(0)); 393 aDlg.AddButton( ModuleRes(STR_QUERY_REL_EDIT), BUTTONID_OK, BUTTONDIALOG_DEFBUTTON | BUTTONDIALOG_FOCUSBUTTON); 394 aDlg.AddButton( ModuleRes(STR_QUERY_REL_CREATE), BUTTONID_YES, 0); 395 aDlg.AddButton(BUTTON_CANCEL,BUTTONID_CANCEL,0); 396 sal_uInt16 nRet = aDlg.Execute(); 397 if( nRet == RET_CANCEL) 398 { 399 m_pCurrentlyTabConnData.reset(); 400 } 401 else if ( nRet == RET_OK ) // EDIT 402 { 403 ConnDoubleClicked(m_pExistingConnection); 404 m_pCurrentlyTabConnData.reset(); 405 } 406 m_pExistingConnection = NULL; 407 } 408 if(m_pCurrentlyTabConnData) 409 { 410 ORelationDialog aRelDlg( this, m_pCurrentlyTabConnData ); 411 if (aRelDlg.Execute() == RET_OK) 412 { 413 // already updated by the dialog 414 addConnection( new ORelationTableConnection( this, m_pCurrentlyTabConnData ) ); 415 } 416 m_pCurrentlyTabConnData.reset(); 417 } 418 } 419 420 // ----------------------------------------------------------------------------- 421 OTableWindow* ORelationTableView::createWindow(const TTableWindowData::value_type& _pData) 422 { 423 return new ORelationTableWindow(this,_pData); 424 } 425 // ----------------------------------------------------------------------------- 426 bool ORelationTableView::allowQueries() const 427 { 428 return false; 429 } 430 // ----------------------------------------------------------------------------- 431 void ORelationTableView::_elementInserted( const container::ContainerEvent& /*_rEvent*/ ) throw(::com::sun::star::uno::RuntimeException) 432 { 433 434 } 435 // ----------------------------------------------------------------------------- 436 void ORelationTableView::_elementRemoved( const container::ContainerEvent& _rEvent ) throw(::com::sun::star::uno::RuntimeException) 437 { 438 m_bInRemove = true; 439 ::rtl::OUString sName; 440 if ( _rEvent.Accessor >>= sName ) 441 { 442 OTableWindow* pTableWindow = GetTabWindow(sName); 443 if ( pTableWindow ) 444 { 445 m_pView->getController().ClearUndoManager(); 446 OJoinTableView::RemoveTabWin( pTableWindow ); 447 448 m_pView->getController().InvalidateFeature(SID_RELATION_ADD_RELATION); 449 m_pView->getController().InvalidateFeature(ID_BROWSER_UNDO); 450 m_pView->getController().InvalidateFeature(ID_BROWSER_REDO); 451 } 452 } // if ( _rEvent.Accessor >>= sName ) 453 m_bInRemove = false; 454 } 455 // ----------------------------------------------------------------------------- 456 void ORelationTableView::_elementReplaced( const container::ContainerEvent& /*_rEvent*/ ) throw(::com::sun::star::uno::RuntimeException) 457 { 458 } 459 460