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