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