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