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