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