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
createRegistryInfo_OTableControl()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 {
dropTable(const Reference<XNameAccess> & _rxTable,const::rtl::OUString & _sTableName)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 {
operator ()__anon7e30dee80111::OTableRowCompare123 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 //------------------------------------------------------------------------------
getImplementationName()133 ::rtl::OUString SAL_CALL OTableController::getImplementationName() throw( RuntimeException )
134 {
135 return getImplementationName_Static();
136 }
137
138 //------------------------------------------------------------------------------
getImplementationName_Static()139 ::rtl::OUString OTableController::getImplementationName_Static() throw( RuntimeException )
140 {
141 return ::rtl::OUString::createFromAscii("org.openoffice.comp.dbu.OTableDesign");
142 }
143 //------------------------------------------------------------------------------
getSupportedServiceNames_Static(void)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 //-------------------------------------------------------------------------
getSupportedServiceNames()151 Sequence< ::rtl::OUString> SAL_CALL OTableController::getSupportedServiceNames() throw(RuntimeException)
152 {
153 return getSupportedServiceNames_Static();
154 }
155 // -------------------------------------------------------------------------
Create(const Reference<XMultiServiceFactory> & _rxFactory)156 Reference< XInterface > SAL_CALL OTableController::Create(const Reference<XMultiServiceFactory >& _rxFactory)
157 {
158 return *(new OTableController(_rxFactory));
159 }
160
DBG_NAME(OTableController)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 // -----------------------------------------------------------------------------
~OTableController()176 OTableController::~OTableController()
177 {
178 m_aTypeInfoIndex.clear();
179 m_aTypeInfo.clear();
180
181 DBG_DTOR(OTableController,NULL);
182 }
183
184 // -----------------------------------------------------------------------------
startTableListening()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 // -----------------------------------------------------------------------------
stopTableListening()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 // -----------------------------------------------------------------------------
disposing()201 void OTableController::disposing()
202 {
203 OTableController_BASE::disposing();
204 clearView();
205
206 m_vRowList.clear();
207 }
208 // -----------------------------------------------------------------------------
GetState(sal_uInt16 _nId) const209 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 // -----------------------------------------------------------------------------
Execute(sal_uInt16 _nId,const Sequence<PropertyValue> & aArgs)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 // -----------------------------------------------------------------------------
doSaveDoc(sal_Bool _bSaveAs)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 // -----------------------------------------------------------------------------
doEditIndexes()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 // -----------------------------------------------------------------------------
impl_initialize()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 // -----------------------------------------------------------------------------
Construct(Window * pParent)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 // -----------------------------------------------------------------------------
suspend(sal_Bool)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 // -----------------------------------------------------------------------------
describeSupportedFeatures()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 // -----------------------------------------------------------------------------
impl_onModifyChanged()663 void OTableController::impl_onModifyChanged()
664 {
665 OSingleDocumentController::impl_onModifyChanged();
666 InvalidateFeature( SID_INDEXDESIGN );
667 }
668 // -----------------------------------------------------------------------------
disposing(const EventObject & _rSource)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 // -----------------------------------------------------------------------------
Save(const Reference<XObjectOutputStream> & _rxOut)682 void OTableController::Save(const Reference< XObjectOutputStream>& _rxOut)
683 {
684 OStreamSection aSection(_rxOut.get());
685
686 }
687 // -----------------------------------------------------------------------------
Load(const Reference<XObjectInputStream> & _rxIn)688 void OTableController::Load(const Reference< XObjectInputStream>& _rxIn)
689 {
690 OStreamSection aSection(_rxIn.get());
691 }
692
693 // -----------------------------------------------------------------------------
losingConnection()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 // -----------------------------------------------------------------------------
getTypeInfoByType(sal_Int32 _nDataType) const717 TOTypeInfoSP OTableController::getTypeInfoByType(sal_Int32 _nDataType) const
718 {
719 return queryTypeInfoByType(_nDataType,m_aTypeInfo);
720 }
721 // -----------------------------------------------------------------------------
appendColumns(Reference<XColumnsSupplier> & _rxColSup,sal_Bool _bNew,sal_Bool _bKeyColumns)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 // -----------------------------------------------------------------------------
appendPrimaryKey(Reference<XKeysSupplier> & _rxSup,sal_Bool _bNew)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 // -----------------------------------------------------------------------------
loadData()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 // -----------------------------------------------------------------------------
getKeyColumns() const961 Reference<XNameAccess> OTableController::getKeyColumns() const
962 {
963 return getPrimaryKeyColumns_throw(m_xTable);
964 }
965 // -----------------------------------------------------------------------------
checkColumns(sal_Bool _bNew)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 // -----------------------------------------------------------------------------
alterColumns()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 // -----------------------------------------------------------------------------
dropPrimaryKey()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 // -----------------------------------------------------------------------------
assignTable()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 // -----------------------------------------------------------------------------
isAddAllowed() const1453 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 // -----------------------------------------------------------------------------
isDropAllowed() const1474 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 // -----------------------------------------------------------------------------
isAlterAllowed() const1490 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 // -----------------------------------------------------------------------------
reSyncRows()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 // -----------------------------------------------------------------------------
createUniqueName(const::rtl::OUString & _rName)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 // -----------------------------------------------------------------------------
getPrivateTitle() const1539 ::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 // -----------------------------------------------------------------------------
reload()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 // -----------------------------------------------------------------------------
getFirstEmptyRowPosition()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 // -----------------------------------------------------------------------------
isAutoIncrementPrimaryKey() const1599 bool OTableController::isAutoIncrementPrimaryKey() const
1600 {
1601 return getSdbMetaData().isAutoIncrementPrimaryKey();
1602 }
1603 // -----------------------------------------------------------------------------
1604
1605 /* vim: set noet sw=4 ts=4: */
1606