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