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