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