1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
20 #include "TEditControl.hxx"
21 #include <com/sun/star/sdbc/ColumnValue.hpp>
22 #include <com/sun/star/sdbc/SQLException.hpp>
23 #include <com/sun/star/sdbc/XDatabaseMetaData.hpp>
24 #include <com/sun/star/sdbcx/XColumnsSupplier.hpp>
25 #include <com/sun/star/util/XNumberFormatTypes.hpp>
26 #include <core_resource.hxx>
27 #include <strings.hrc>
28 #include <strings.hxx>
30 #include <comphelper/types.hxx>
31 #include <FieldDescControl.hxx>
32 #include <FieldDescriptions.hxx>
33 #include "TableUndo.hxx"
34 #include <TableController.hxx>
35 #include <connectivity/dbmetadata.hxx>
36 #include <connectivity/dbtools.hxx>
37 #include <SqlNameEdit.hxx>
38 #include <TableRowExchange.hxx>
39 #include <o3tl/safeint.hxx>
40 #include <sot/storage.hxx>
41 #include <svx/svxids.hrc>
42 #include <UITools.hxx>
43 #include "TableFieldControl.hxx"
44 #include <dsntypes.hxx>
45 #include <vcl/commandevent.hxx>
46 #include <vcl/svapp.hxx>
48 using namespace ::dbaui
;
49 using namespace ::comphelper
;
50 using namespace ::svt
;
51 using namespace ::com::sun::star::uno
;
52 using namespace ::com::sun::star::io
;
53 using namespace ::com::sun::star::beans
;
54 using namespace ::com::sun::star::util
;
55 using namespace ::com::sun::star::sdbc
;
60 // default field widths
61 #define FIELDNAME_WIDTH 100
62 #define FIELDTYPE_WIDTH 150
63 #define FIELDDESCR_WIDTH 300
65 // Maximum length in description field
66 #define MAX_DESCR_LEN 256
68 OTableEditorCtrl::ClipboardInvalidator::ClipboardInvalidator(OTableEditorCtrl
* _pOwner
)
69 : m_aInvalidateTimer("dbaccess ClipboardInvalidator")
73 m_aInvalidateTimer
.SetTimeout(500);
74 m_aInvalidateTimer
.SetInvokeHandler(LINK(this, OTableEditorCtrl::ClipboardInvalidator
, OnInvalidate
));
75 m_aInvalidateTimer
.Start();
78 OTableEditorCtrl::ClipboardInvalidator::~ClipboardInvalidator()
80 m_aInvalidateTimer
.Stop();
83 void OTableEditorCtrl::ClipboardInvalidator::Stop()
85 m_aInvalidateTimer
.Stop();
88 IMPL_LINK_NOARG(OTableEditorCtrl::ClipboardInvalidator
, OnInvalidate
, Timer
*, void)
90 m_pOwner
->GetView()->getController().InvalidateFeature(SID_CUT
);
91 m_pOwner
->GetView()->getController().InvalidateFeature(SID_COPY
);
92 m_pOwner
->GetView()->getController().InvalidateFeature(SID_PASTE
);
95 void OTableEditorCtrl::Init()
97 OTableRowView::Init();
99 // Should it be opened ReadOnly?
100 bool bRead(GetView()->getController().isReadOnly());
102 SetReadOnly( bRead
);
104 // Insert the columns
105 InsertDataColumn( FIELD_NAME
, DBA_RES(STR_TAB_FIELD_COLUMN_NAME
), FIELDNAME_WIDTH
);
107 InsertDataColumn( FIELD_TYPE
, DBA_RES(STR_TAB_FIELD_COLUMN_DATATYPE
), FIELDTYPE_WIDTH
);
109 ::dbaccess::ODsnTypeCollection
aDsnTypes(GetView()->getController().getORB());
110 bool bShowColumnDescription
= aDsnTypes
.supportsColumnDescription(::comphelper::getString(GetView()->getController().getDataSource()->getPropertyValue(PROPERTY_URL
)));
111 InsertDataColumn( HELP_TEXT
, DBA_RES(STR_TAB_HELP_TEXT
), bShowColumnDescription
? FIELDTYPE_WIDTH
: FIELDDESCR_WIDTH
);
113 if ( bShowColumnDescription
)
115 InsertDataColumn( COLUMN_DESCRIPTION
, DBA_RES(STR_COLUMN_DESCRIPTION
), FIELDTYPE_WIDTH
);
118 InitCellController();
121 RowInserted(0, m_pRowList
->size());
124 OTableEditorCtrl::OTableEditorCtrl(vcl::Window
* pWindow
, OTableDesignView
* pView
)
125 :OTableRowView(pWindow
)
129 ,pHelpTextCell(nullptr)
133 ,nPasteEvent(nullptr)
134 ,nDeleteEvent(nullptr)
135 ,nInsNewRowsEvent(nullptr)
136 ,nInvalidateTypeEvent(nullptr)
142 SetHelpId(HID_TABDESIGN_BACKGROUND
);
143 GetDataWindow().SetHelpId(HID_CTL_TABLEEDIT
);
145 m_pRowList
= &GetView()->getController().getRows();
149 SfxUndoManager
& OTableEditorCtrl::GetUndoManager() const
151 return GetView()->getController().GetUndoManager();
155 void OTableEditorCtrl::SetReadOnly( bool bRead
)
158 if (bRead
== IsReadOnly())
159 // This check is important, as the underlying Def may be unnecessarily locked or unlocked
160 // or worse, this action may not be reversed afterwards
165 // Disable active cells
166 sal_Int32
nRow(GetCurRow());
167 sal_uInt16
nCol(GetCurColumnId());
170 // Select the correct Browsers cursor
171 BrowserMode
nMode(BrowserMode::COLUMNSELECTION
| BrowserMode::MULTISELECTION
| BrowserMode::KEEPHIGHLIGHT
|
172 BrowserMode::HLINES
| BrowserMode::VLINES
|BrowserMode::AUTOSIZE_LASTCOL
);
174 nMode
|= BrowserMode::HIDECURSOR
;
178 ActivateCell( nRow
, nCol
);
181 void OTableEditorCtrl::InitCellController()
184 sal_Int32 nMaxTextLen
= 0;
185 OUString sExtraNameChars
;
186 Reference
<XConnection
> xCon
;
189 xCon
= GetView()->getController().getConnection();
190 Reference
< XDatabaseMetaData
> xMetaData
= xCon
.is() ? xCon
->getMetaData() : Reference
< XDatabaseMetaData
>();
192 // length 0 is treated by Entry::set_max_length as unlimited
193 nMaxTextLen
= xMetaData
.is() ? xMetaData
->getMaxColumnNameLength() : 0;
195 sExtraNameChars
= xMetaData
.is() ? xMetaData
->getExtraNameCharacters() : OUString();
200 OSL_FAIL("getMaxColumnNameLength");
203 pNameCell
= VclPtr
<OSQLNameEditControl
>::Create(&GetDataWindow(), sExtraNameChars
);
204 pNameCell
->get_widget().set_max_length(nMaxTextLen
);
205 pNameCell
->setCheck( isSQL92CheckEnabled(xCon
) );
208 pTypeCell
= VclPtr
<ListBoxControl
>::Create( &GetDataWindow() );
211 pDescrCell
= VclPtr
<EditControl
>::Create(&GetDataWindow());
212 pDescrCell
->get_widget().set_max_length(MAX_DESCR_LEN
);
214 pHelpTextCell
= VclPtr
<EditControl
>::Create(&GetDataWindow());
215 pHelpTextCell
->get_widget().set_max_length(MAX_DESCR_LEN
);
217 pNameCell
->SetHelpId(HID_TABDESIGN_NAMECELL
);
218 pTypeCell
->SetHelpId(HID_TABDESIGN_TYPECELL
);
219 pDescrCell
->SetHelpId(HID_TABDESIGN_COMMENTCELL
);
220 pHelpTextCell
->SetHelpId(HID_TABDESIGN_HELPTEXT
);
223 const Control
* pControls
[] = { pTypeCell
,pDescrCell
,pNameCell
,pHelpTextCell
};
224 for(const Control
* pControl
: pControls
)
226 const Size
aTemp(pControl
->GetOptimalSize());
227 if ( aTemp
.Height() > aHeight
.Height() )
228 aHeight
.setHeight( aTemp
.Height() );
230 SetDataRowHeight(aHeight
.Height());
235 void OTableEditorCtrl::ClearModified()
237 pNameCell
->get_widget().save_value();
238 pDescrCell
->get_widget().save_value();
239 pHelpTextCell
->get_widget().save_value();
240 pTypeCell
->get_widget().save_value();
243 OTableEditorCtrl::~OTableEditorCtrl()
248 void OTableEditorCtrl::dispose()
250 // Reset the Undo-Manager
251 GetUndoManager().Clear();
253 m_aInvalidate
.Stop();
255 // Take possible Events from the queue
257 Application::RemoveUserEvent( nCutEvent
);
259 Application::RemoveUserEvent( nPasteEvent
);
261 Application::RemoveUserEvent( nDeleteEvent
);
262 if( nInsNewRowsEvent
)
263 Application::RemoveUserEvent( nInsNewRowsEvent
);
264 if( nInvalidateTypeEvent
)
265 Application::RemoveUserEvent( nInvalidateTypeEvent
);
267 // Delete the control types
268 pNameCell
.disposeAndClear();
269 pTypeCell
.disposeAndClear();
270 pDescrCell
.disposeAndClear();
271 pHelpTextCell
.disposeAndClear();
274 OTableRowView::dispose();
277 bool OTableEditorCtrl::SetDataPtr( sal_Int32 nRow
)
282 OSL_ENSURE(nRow
< static_cast<tools::Long
>(m_pRowList
->size()),"Row is greater than size!");
283 if(nRow
>= static_cast<tools::Long
>(m_pRowList
->size()))
285 pActRow
= (*m_pRowList
)[nRow
];
286 return pActRow
!= nullptr;
289 bool OTableEditorCtrl::SeekRow(sal_Int32 _nRow
)
291 // Call the Base class to remember which row must be repainted
292 EditBrowseBox::SeekRow(_nRow
);
294 m_nCurrentPos
= _nRow
;
295 return SetDataPtr(_nRow
);
298 void OTableEditorCtrl::PaintCell(OutputDevice
& rDev
, const tools::Rectangle
& rRect
,
299 sal_uInt16 nColumnId
) const
301 const OUString
aText( GetCellText( m_nCurrentPos
, nColumnId
));
303 rDev
.Push( vcl::PushFlags::CLIPREGION
);
304 rDev
.SetClipRegion(vcl::Region(rRect
));
305 rDev
.DrawText( rRect
, aText
, DrawTextFlags::Left
| DrawTextFlags::VCenter
);
309 CellController
* OTableEditorCtrl::GetController(sal_Int32 nRow
, sal_uInt16 nColumnId
)
311 // If EditorCtrl is ReadOnly, editing is forbidden
312 Reference
<XPropertySet
> xTable
= GetView()->getController().getTable();
313 if (IsReadOnly() || ( xTable
.is() &&
314 xTable
->getPropertySetInfo()->hasPropertyByName(PROPERTY_TYPE
) &&
315 ::comphelper::getString(xTable
->getPropertyValue(PROPERTY_TYPE
)) == "VIEW"))
318 // If the row is ReadOnly, editing is forbidden
320 if( pActRow
->IsReadOnly() )
323 OFieldDescription
* pActFieldDescr
= pActRow
->GetActFieldDescr();
327 return new EditCellController( pNameCell
);
329 if (pActFieldDescr
&& !pActFieldDescr
->GetName().isEmpty())
330 return new ListBoxCellController( pTypeCell
);
333 if (pActFieldDescr
&& !pActFieldDescr
->GetName().isEmpty())
334 return new EditCellController( pHelpTextCell
);
337 case COLUMN_DESCRIPTION
:
338 if (pActFieldDescr
&& !pActFieldDescr
->GetName().isEmpty())
339 return new EditCellController( pDescrCell
);
347 void OTableEditorCtrl::InitController(CellControllerRef
&, sal_Int32 nRow
, sal_uInt16 nColumnId
)
349 SeekRow( nRow
== -1 ? GetCurRow() : nRow
);
350 OFieldDescription
* pActFieldDescr
= pActRow
->GetActFieldDescr();
351 OUString aInitString
;
358 aInitString
= pActFieldDescr
->GetName();
360 weld::Entry
& rEntry
= pNameCell
->get_widget();
361 rEntry
.set_text(aInitString
);
367 if ( pActFieldDescr
&& pActFieldDescr
->getTypeInfo() )
368 aInitString
= pActFieldDescr
->getTypeInfo()->aUIName
;
370 // Set the ComboBox contents
371 weld::ComboBox
& rTypeList
= pTypeCell
->get_widget();
373 if( !pActFieldDescr
)
376 const OTypeInfoMap
& rTypeInfo
= GetView()->getController().getTypeInfo();
377 for (auto const& elem
: rTypeInfo
)
378 rTypeList
.append_text(elem
.second
->aUIName
);
379 rTypeList
.set_active_text(aInitString
);
386 aInitString
= pActFieldDescr
->GetHelpText();
387 weld::Entry
& rEntry
= pHelpTextCell
->get_widget();
388 rEntry
.set_text(aInitString
);
392 case COLUMN_DESCRIPTION
:
395 aInitString
= pActFieldDescr
->GetDescription();
396 weld::Entry
& rEntry
= pDescrCell
->get_widget();
397 rEntry
.set_text(aInitString
);
404 EditBrowseBox::RowStatus
OTableEditorCtrl::GetRowStatus(sal_Int32 nRow
) const
406 const_cast<OTableEditorCtrl
*>(this)->SetDataPtr( nRow
);
408 return EditBrowseBox::CLEAN
;
409 if (nRow
>= 0 && nRow
== m_nDataPos
)
411 if( pActRow
->IsPrimaryKey() )
412 return EditBrowseBox::CURRENT_PRIMARYKEY
;
413 return EditBrowseBox::CURRENT
;
417 if( pActRow
->IsPrimaryKey() )
418 return EditBrowseBox::PRIMARYKEY
;
419 return EditBrowseBox::CLEAN
;
423 void OTableEditorCtrl::SaveCurRow()
425 if (GetFieldDescr(GetCurRow()) == nullptr)
426 // there is no data in the current row
431 SetDataPtr(GetCurRow());
432 pDescrWin
->SaveData( pActRow
->GetActFieldDescr() );
435 void OTableEditorCtrl::DisplayData(sal_Int32 nRow
)
437 // go to the correct cell
440 // Disable Edit-Mode temporarily
441 bool bWasEditing
= IsEditing();
445 CellControllerRef aTemp
;
446 InitController(aTemp
, nRow
, FIELD_NAME
);
447 InitController(aTemp
, nRow
, FIELD_TYPE
);
448 InitController(aTemp
, nRow
, COLUMN_DESCRIPTION
);
449 InitController(aTemp
, nRow
, HELP_TEXT
);
452 // Update the Description-Window
453 GetView()->GetDescWin()->DisplayData(GetFieldDescr(nRow
));
457 // and re-enable edit mode
458 ActivateCell(nRow
, GetCurColumnId());
461 void OTableEditorCtrl::CursorMoved()
464 m_nDataPos
= GetCurRow();
465 if( m_nDataPos
!= nOldDataPos
&& m_nDataPos
!= -1)
467 CellControllerRef aTemp
;
468 InitController(aTemp
,m_nDataPos
,FIELD_NAME
);
469 InitController(aTemp
,m_nDataPos
,FIELD_TYPE
);
470 InitController(aTemp
,m_nDataPos
,COLUMN_DESCRIPTION
);
471 InitController(aTemp
,m_nDataPos
,HELP_TEXT
);
474 OTableRowView::CursorMoved();
477 sal_Int32
OTableEditorCtrl::HasFieldName( std::u16string_view rFieldName
)
480 Reference
<XConnection
> xCon
= GetView()->getController().getConnection();
481 Reference
< XDatabaseMetaData
> xMetaData
= xCon
.is() ? xCon
->getMetaData() : Reference
< XDatabaseMetaData
>();
483 ::comphelper::UStringMixEqual
bCase(!xMetaData
.is() || xMetaData
->supportsMixedCaseQuotedIdentifiers());
486 for (auto const& row
: *m_pRowList
)
488 OFieldDescription
* pFieldDescr
= row
->GetActFieldDescr();
489 if( pFieldDescr
&& bCase(rFieldName
,pFieldDescr
->GetName()))
495 void OTableEditorCtrl::SaveData(sal_Int32 nRow
, sal_uInt16 nColId
)
497 // Store the cell content
498 SetDataPtr( nRow
== -1 ? GetCurRow() : nRow
);
499 OFieldDescription
* pActFieldDescr
= pActRow
->GetActFieldDescr();
506 // If there is no name, do nothing
507 weld::Entry
& rEntry
= pNameCell
->get_widget();
508 const OUString
aName(rEntry
.get_text());
510 if( aName
.isEmpty() )
512 // If FieldDescr exists, the field is deleted and the old content restored
515 GetUndoManager().AddUndoAction(std::make_unique
<OTableEditorTypeSelUndoAct
>(this, nRow
, FIELD_TYPE
, pActFieldDescr
->getTypeInfo()));
516 SwitchType(TOTypeInfoSP());
517 pActFieldDescr
= pActRow
->GetActFieldDescr();
523 pActFieldDescr
->SetName( aName
);
529 // Store the field type
536 // if the current field description is NULL, set Default
537 weld::Entry
& rEntry
= pHelpTextCell
->get_widget();
538 if( !pActFieldDescr
)
540 rEntry
.set_text(OUString());
544 pActFieldDescr
->SetHelpText(rEntry
.get_text());
547 case COLUMN_DESCRIPTION
:
549 // Set the default if the field description is null
550 weld::Entry
& rEntry
= pDescrCell
->get_widget();
551 if( !pActFieldDescr
)
553 rEntry
.set_text(OUString());
557 pActFieldDescr
->SetDescription(rEntry
.get_text());
560 case FIELD_PROPERTY_DEFAULT
:
561 case FIELD_PROPERTY_REQUIRED
:
562 case FIELD_PROPERTY_TEXTLEN
:
563 case FIELD_PROPERTY_NUMTYPE
:
564 case FIELD_PROPERTY_AUTOINC
:
565 case FIELD_PROPERTY_LENGTH
:
566 case FIELD_PROPERTY_SCALE
:
567 case FIELD_PROPERTY_BOOL_DEFAULT
:
568 pDescrWin
->SaveData(pActFieldDescr
);
570 if ( FIELD_PROPERTY_AUTOINC
== nColId
&& pActFieldDescr
->IsAutoIncrement() )
572 OTableController
& rController
= GetView()->getController();
573 if ( rController
.isAutoIncrementPrimaryKey() )
575 pActFieldDescr
->SetPrimaryKey( true );
576 InvalidateHandleColumn();
584 bool OTableEditorCtrl::SaveModified()
586 sal_uInt16 nColId
= GetCurColumnId();
601 bool OTableEditorCtrl::CursorMoving(sal_Int32 nNewRow
, sal_uInt16 nNewCol
)
604 if (!EditBrowseBox::CursorMoving(nNewRow
, nNewCol
))
607 // Called after SaveModified(), current row is still the old one
608 m_nDataPos
= nNewRow
;
609 nOldDataPos
= GetCurRow();
612 InvalidateStatusCell( nOldDataPos
);
613 InvalidateStatusCell( m_nDataPos
);
615 // Store the data from the Property window
616 if( SetDataPtr(nOldDataPos
) && pDescrWin
)
617 pDescrWin
->SaveData( pActRow
->GetActFieldDescr() );
619 // Show new data in the Property window
620 if( SetDataPtr(m_nDataPos
) && pDescrWin
)
621 pDescrWin
->DisplayData( pActRow
->GetActFieldDescr() );
626 IMPL_LINK_NOARG( OTableEditorCtrl
, InvalidateFieldType
, void*, void )
628 nInvalidateTypeEvent
= nullptr;
629 Invalidate( GetFieldRectPixel(nOldDataPos
, FIELD_TYPE
) );
632 void OTableEditorCtrl::CellModified( sal_Int32 nRow
, sal_uInt16 nColId
)
635 // If the description is null, use the default
639 OFieldDescription
* pActFieldDescr
= pActRow
->GetActFieldDescr();
641 OUString sActionDescription
;
644 case FIELD_NAME
: sActionDescription
= DBA_RES( STR_CHANGE_COLUMN_NAME
); break;
645 case FIELD_TYPE
: sActionDescription
= DBA_RES( STR_CHANGE_COLUMN_TYPE
); break;
647 case COLUMN_DESCRIPTION
: sActionDescription
= DBA_RES( STR_CHANGE_COLUMN_DESCRIPTION
); break;
648 default: sActionDescription
= DBA_RES( STR_CHANGE_COLUMN_ATTRIBUTE
); break;
651 GetUndoManager().EnterListAction( sActionDescription
, OUString(), 0, ViewShellId(-1) );
654 const OTypeInfoMap
& rTypeInfoMap
= GetView()->getController().getTypeInfo();
655 if ( !rTypeInfoMap
.empty() )
657 OTypeInfoMap::const_iterator aTypeIter
= rTypeInfoMap
.find(DataType::VARCHAR
);
658 if ( aTypeIter
== rTypeInfoMap
.end() )
659 aTypeIter
= rTypeInfoMap
.begin();
660 pActRow
->SetFieldType( aTypeIter
->second
);
663 pActRow
->SetFieldType( GetView()->getController().getTypeInfoFallBack() );
665 nInvalidateTypeEvent
= Application::PostUserEvent( LINK(this, OTableEditorCtrl
, InvalidateFieldType
), nullptr, true );
666 pActFieldDescr
= pActRow
->GetActFieldDescr();
667 pDescrWin
->DisplayData( pActFieldDescr
);
668 GetUndoManager().AddUndoAction( std::make_unique
<OTableEditorTypeSelUndoAct
>(this, nRow
, nColId
+1, TOTypeInfoSP()) );
671 if( nColId
!= FIELD_TYPE
)
672 GetUndoManager().AddUndoAction( std::make_unique
<OTableDesignCellUndoAct
>(this, nRow
, nColId
) );
675 GetUndoManager().AddUndoAction(std::make_unique
<OTableEditorTypeSelUndoAct
>(this, GetCurRow(), nColId
, GetFieldDescr(GetCurRow())->getTypeInfo()));
679 SaveData(nRow
,nColId
);
680 // SaveData could create an undo action as well
681 GetUndoManager().LeaveListAction();
684 // Set the Modify flag
685 GetView()->getController().setModified( true );
686 InvalidateFeatures();
689 void OTableEditorCtrl::resetType()
691 sal_Int32 nPos
= pTypeCell
->get_widget().get_active();
693 SwitchType( GetView()->getController().getTypeInfo(nPos
) );
695 SwitchType(TOTypeInfoSP());
698 void OTableEditorCtrl::CellModified()
700 CellModified( GetCurRow(), GetCurColumnId() );
703 void OTableEditorCtrl::InvalidateFeatures()
705 GetView()->getController().InvalidateFeature(SID_UNDO
);
706 GetView()->getController().InvalidateFeature(SID_REDO
);
707 GetView()->getController().InvalidateFeature(SID_SAVEDOC
);
710 void OTableEditorCtrl::CopyRows()
712 // set to the right row and save it
713 if( SetDataPtr(m_nDataPos
) )
714 pDescrWin
->SaveData( pActRow
->GetActFieldDescr() );
716 // Copy selected rows to the ClipboardList
717 std::shared_ptr
<OTableRow
> pClipboardRow
;
718 std::shared_ptr
<OTableRow
> pRow
;
719 std::vector
< std::shared_ptr
<OTableRow
> > vClipboardList
;
720 vClipboardList
.reserve(GetSelectRowCount());
722 for( tools::Long nIndex
=FirstSelectedRow(); nIndex
!= SFX_ENDOFSELECTION
; nIndex
=NextSelectedRow() )
724 pRow
= (*m_pRowList
)[nIndex
];
725 OSL_ENSURE(pRow
,"OTableEditorCtrl::CopyRows: Row is NULL!");
726 if ( pRow
&& pRow
->GetActFieldDescr() )
728 pClipboardRow
= std::make_shared
<OTableRow
>( *pRow
);
729 vClipboardList
.push_back( pClipboardRow
);
732 if(!vClipboardList
.empty())
734 rtl::Reference
<OTableRowExchange
> pData
= new OTableRowExchange(std::move(vClipboardList
));
735 pData
->CopyToClipboard(GetParent());
739 OUString
OTableEditorCtrl::GenerateName( const OUString
& rName
)
741 // Create a base name for appending numbers to
743 Reference
<XConnection
> xCon
= GetView()->getController().getConnection();
744 Reference
< XDatabaseMetaData
> xMetaData
= xCon
.is() ? xCon
->getMetaData() : Reference
< XDatabaseMetaData
>();
746 sal_Int32
nMaxTextLen(xMetaData
.is() ? xMetaData
->getMaxColumnNameLength() : 0);
748 if( (rName
.getLength()+2) >nMaxTextLen
)
749 aBaseName
= rName
.copy( 0, nMaxTextLen
-2 );
753 // append a sequential number to the base name (up to 99)
754 OUString
aFieldName( rName
);
756 while( HasFieldName(aFieldName
) )
758 aFieldName
= aBaseName
+ OUString::number(i
);
765 void OTableEditorCtrl::InsertRows( sal_Int32 nRow
)
768 std::vector
< std::shared_ptr
<OTableRow
> > vInsertedUndoRedoRows
; // need for undo/redo handling
769 // get rows from clipboard
770 TransferableDataHelper
aTransferData(TransferableDataHelper::CreateFromSystemClipboard(GetParent()));
771 if(aTransferData
.HasFormat(SotClipboardFormatId::SBA_TABED
))
773 std::unique_ptr
<SvStream
> aStreamRef
= aTransferData
.GetSotStorageStream(SotClipboardFormatId::SBA_TABED
);
776 aStreamRef
->Seek(STREAM_SEEK_TO_BEGIN
);
777 aStreamRef
->ResetError();
778 sal_Int32 nInsertRow
= nRow
;
779 std::shared_ptr
<OTableRow
> pRow
;
781 (*aStreamRef
).ReadInt32( nSize
);
782 vInsertedUndoRedoRows
.reserve(nSize
);
783 for(sal_Int32 i
=0;i
< nSize
;++i
)
785 pRow
= std::make_shared
<OTableRow
>();
786 ReadOTableRow( *aStreamRef
, *pRow
);
787 pRow
->SetReadOnly( false );
788 sal_Int32 nType
= pRow
->GetActFieldDescr()->GetType();
789 if ( pRow
->GetActFieldDescr() )
790 pRow
->GetActFieldDescr()->SetType(GetView()->getController().getTypeInfoByType(nType
));
791 // Adjust the field names
792 pRow
->GetActFieldDescr()->SetName( GenerateName( pRow
->GetActFieldDescr()->GetName() ) );
793 pRow
->SetPos(nInsertRow
);
794 m_pRowList
->insert( m_pRowList
->begin()+nInsertRow
,pRow
);
795 vInsertedUndoRedoRows
.push_back(std::make_shared
<OTableRow
>(*pRow
));
800 // RowInserted calls CursorMoved.
801 // The UI data should not be stored here.
802 RowInserted( nRow
,vInsertedUndoRedoRows
.size() );
804 // Create the Undo-Action
805 GetUndoManager().AddUndoAction( std::make_unique
<OTableEditorInsUndoAct
>(this, nRow
, std::move(vInsertedUndoRedoRows
)) );
806 GetView()->getController().setModified( true );
807 InvalidateFeatures();
810 void OTableEditorCtrl::DeleteRows()
812 OSL_ENSURE(GetView()->getController().isDropAllowed(),"Call of DeleteRows not valid here. Please check isDropAllowed!");
813 // Create the Undo-Action
814 GetUndoManager().AddUndoAction( std::make_unique
<OTableEditorDelUndoAct
>(this) );
816 // Delete all marked rows
817 tools::Long nIndex
= FirstSelectedRow();
818 nOldDataPos
= nIndex
;
820 while( nIndex
!= SFX_ENDOFSELECTION
)
823 m_pRowList
->erase( m_pRowList
->begin()+nIndex
);
824 RowRemoved( nIndex
);
826 // Insert the empty row at the end
827 m_pRowList
->push_back( std::make_shared
<OTableRow
>());
828 RowInserted( GetRowCount()-1 );
830 nIndex
= FirstSelectedRow();
833 // Force the current record to be displayed
834 m_nDataPos
= GetCurRow();
835 InvalidateStatusCell( nOldDataPos
);
836 InvalidateStatusCell( m_nDataPos
);
837 SetDataPtr( m_nDataPos
);
839 pDescrWin
->DisplayData( pActRow
->GetActFieldDescr() );
840 GetView()->getController().setModified( true );
841 InvalidateFeatures();
844 void OTableEditorCtrl::InsertNewRows( sal_Int32 nRow
)
846 OSL_ENSURE(GetView()->getController().isAddAllowed(),"Call of InsertNewRows not valid here. Please check isAppendAllowed!");
847 // Create Undo-Action
848 sal_Int32 nInsertRows
= GetSelectRowCount();
851 GetUndoManager().AddUndoAction( std::make_unique
<OTableEditorInsNewUndoAct
>(this, nRow
, nInsertRows
) );
852 // Insert the number of selected rows
853 for( tools::Long i
=nRow
; i
<(nRow
+nInsertRows
); i
++ )
854 m_pRowList
->insert( m_pRowList
->begin()+i
,std::make_shared
<OTableRow
>());
855 RowInserted( nRow
, nInsertRows
);
857 GetView()->getController().setModified( true );
858 InvalidateFeatures();
861 void OTableEditorCtrl::SetControlText( sal_Int32 nRow
, sal_uInt16 nColId
, const OUString
& rText
)
863 // Set the Browser Controls
864 if( nColId
< FIELD_FIRST_VIRTUAL_COLUMN
)
867 GoToColumnId( nColId
);
868 CellControllerRef xController
= Controller();
870 xController
->GetWindow().SetText( rText
);
872 RowModified(nRow
,nColId
);
875 // Set the Tabpage controls
878 pDescrWin
->SetControlText( nColId
, rText
);
882 void OTableEditorCtrl::SetCellData( sal_Int32 nRow
, sal_uInt16 nColId
, const TOTypeInfoSP
& _pTypeInfo
)
884 // Relocate the current pointer
887 OFieldDescription
* pFieldDescr
= GetFieldDescr( nRow
);
888 if( !pFieldDescr
&& nColId
!= FIELD_TYPE
)
891 // Set individual fields
895 SwitchType( _pTypeInfo
);
898 OSL_FAIL("OTableEditorCtrl::SetCellData: invalid column!");
900 SetControlText(nRow
,nColId
,_pTypeInfo
? _pTypeInfo
->aUIName
: OUString());
903 void OTableEditorCtrl::SetCellData( sal_Int32 nRow
, sal_uInt16 nColId
, const css::uno::Any
& _rNewData
)
905 // Relocate the current pointer
908 OFieldDescription
* pFieldDescr
= GetFieldDescr( nRow
);
909 if( !pFieldDescr
&& nColId
!= FIELD_TYPE
)
913 // Set individual fields
917 sValue
= ::comphelper::getString(_rNewData
);
918 pFieldDescr
->SetName( sValue
);
922 OSL_FAIL("OTableEditorCtrl::SetCellData: invalid column!");
925 case COLUMN_DESCRIPTION
:
926 sValue
= ::comphelper::getString(_rNewData
);
927 pFieldDescr
->SetDescription( sValue
);
930 case FIELD_PROPERTY_DEFAULT
:
931 pFieldDescr
->SetControlDefault( _rNewData
);
932 sValue
= GetView()->GetDescWin()->getGenPage()->getControlDefault(pFieldDescr
);
935 case FIELD_PROPERTY_REQUIRED
:
937 sValue
= ::comphelper::getString(_rNewData
);
938 pFieldDescr
->SetIsNullable( sValue
.toInt32() );
942 case FIELD_PROPERTY_TEXTLEN
:
943 case FIELD_PROPERTY_LENGTH
:
945 sValue
= ::comphelper::getString(_rNewData
);
946 pFieldDescr
->SetPrecision( sValue
.toInt32() );
950 case FIELD_PROPERTY_NUMTYPE
:
951 OSL_FAIL("OTableEditorCtrl::SetCellData: invalid column!");
954 case FIELD_PROPERTY_AUTOINC
:
956 sValue
= ::comphelper::getString(_rNewData
);
957 pFieldDescr
->SetAutoIncrement(sValue
== DBA_RES(STR_VALUE_YES
));
960 case FIELD_PROPERTY_SCALE
:
962 sValue
= ::comphelper::getString(_rNewData
);
963 pFieldDescr
->SetScale(sValue
.toInt32());
967 case FIELD_PROPERTY_BOOL_DEFAULT
:
968 sValue
= GetView()->GetDescWin()->BoolStringPersistent(::comphelper::getString(_rNewData
));
969 pFieldDescr
->SetControlDefault(Any(sValue
));
972 case FIELD_PROPERTY_FORMAT
:
974 sValue
= ::comphelper::getString(_rNewData
);
975 pFieldDescr
->SetFormatKey(sValue
.toInt32());
980 SetControlText(nRow
,nColId
,sValue
);
983 Any
OTableEditorCtrl::GetCellData( sal_Int32 nRow
, sal_uInt16 nColId
)
985 OFieldDescription
* pFieldDescr
= GetFieldDescr( nRow
);
989 // Relocate the current pointer
994 static const OUString
strYes(DBA_RES(STR_VALUE_YES
));
995 static const OUString
strNo(DBA_RES(STR_VALUE_NO
));
997 // Read out the fields
1001 sValue
= pFieldDescr
->GetName();
1005 if ( pFieldDescr
->getTypeInfo() )
1006 sValue
= pFieldDescr
->getTypeInfo()->aUIName
;
1009 case COLUMN_DESCRIPTION
:
1010 sValue
= pFieldDescr
->GetDescription();
1013 sValue
= pFieldDescr
->GetHelpText();
1016 case FIELD_PROPERTY_DEFAULT
:
1017 return pFieldDescr
->GetControlDefault();
1019 case FIELD_PROPERTY_REQUIRED
:
1020 sValue
= pFieldDescr
->GetIsNullable() == ColumnValue::NULLABLE
? strYes
: strNo
;
1023 case FIELD_PROPERTY_TEXTLEN
:
1024 case FIELD_PROPERTY_LENGTH
:
1025 sValue
= OUString::number(pFieldDescr
->GetPrecision());
1028 case FIELD_PROPERTY_NUMTYPE
:
1029 OSL_FAIL("OTableEditorCtrl::GetCellData: invalid column!");
1032 case FIELD_PROPERTY_AUTOINC
:
1033 sValue
= pFieldDescr
->IsAutoIncrement() ? strYes
: strNo
;
1036 case FIELD_PROPERTY_SCALE
:
1037 sValue
= OUString::number(pFieldDescr
->GetScale());
1040 case FIELD_PROPERTY_BOOL_DEFAULT
:
1041 sValue
= GetView()->GetDescWin()->BoolStringUI(::comphelper::getString(pFieldDescr
->GetControlDefault()));
1044 case FIELD_PROPERTY_FORMAT
:
1045 sValue
= OUString::number(pFieldDescr
->GetFormatKey());
1052 OUString
OTableEditorCtrl::GetCellText( sal_Int32 nRow
, sal_uInt16 nColId
) const
1055 const_cast< OTableEditorCtrl
* >( this )->GetCellData( nRow
, nColId
) >>= sCellText
;
1059 sal_uInt32
OTableEditorCtrl::GetTotalCellWidth(sal_Int32 nRow
, sal_uInt16 nColId
)
1061 return GetTextWidth(GetCellText(nRow
, nColId
)) + 2 * GetTextWidth(u
"0"_ustr
);
1064 OFieldDescription
* OTableEditorCtrl::GetFieldDescr( sal_Int32 nRow
)
1066 std::vector
< std::shared_ptr
<OTableRow
> >::size_type
nListCount(
1067 m_pRowList
->size());
1068 if( (nRow
<0) || (sal::static_int_cast
< unsigned long >(nRow
)>=nListCount
) )
1070 OSL_FAIL("(nRow<0) || (nRow>=nListCount)");
1073 std::shared_ptr
<OTableRow
> pRow
= (*m_pRowList
)[ nRow
];
1076 return pRow
->GetActFieldDescr();
1079 bool OTableEditorCtrl::IsCutAllowed()
1081 bool bIsCutAllowed
= (GetView()->getController().isAddAllowed() && GetView()->getController().isDropAllowed()) ||
1082 GetView()->getController().isAlterAllowed();
1086 int nStartPos
, nEndPos
;
1087 switch(m_eChildFocus
)
1091 weld::Entry
& rEntry
= pDescrCell
->get_widget();
1092 bIsCutAllowed
= rEntry
.get_selection_bounds(nStartPos
, nEndPos
);
1097 weld::Entry
& rEntry
= pHelpTextCell
->get_widget();
1098 bIsCutAllowed
= rEntry
.get_selection_bounds(nStartPos
, nEndPos
);
1103 weld::Entry
& rEntry
= pNameCell
->get_widget();
1104 bIsCutAllowed
= rEntry
.get_selection_bounds(nStartPos
, nEndPos
);
1108 bIsCutAllowed
= IsCopyAllowed();
1111 bIsCutAllowed
= false;
1116 return bIsCutAllowed
;
1119 bool OTableEditorCtrl::IsCopyAllowed()
1121 bool bIsCopyAllowed
= false;
1122 int nStartPos
, nEndPos
;
1123 if (m_eChildFocus
== DESCRIPTION
)
1125 weld::Entry
& rEntry
= pDescrCell
->get_widget();
1126 bIsCopyAllowed
= rEntry
.get_selection_bounds(nStartPos
, nEndPos
);
1128 else if(HELPTEXT
== m_eChildFocus
)
1130 weld::Entry
& rEntry
= pHelpTextCell
->get_widget();
1131 bIsCopyAllowed
= rEntry
.get_selection_bounds(nStartPos
, nEndPos
);
1133 else if(m_eChildFocus
== NAME
)
1135 weld::Entry
& rEntry
= pNameCell
->get_widget();
1136 bIsCopyAllowed
= rEntry
.get_selection_bounds(nStartPos
, nEndPos
);
1138 else if(m_eChildFocus
== ROW
)
1140 Reference
<XPropertySet
> xTable
= GetView()->getController().getTable();
1141 if( !GetSelectRowCount() || (xTable
.is() && ::comphelper::getString(xTable
->getPropertyValue(PROPERTY_TYPE
)) == "VIEW"))
1144 // If one of the selected rows is empty, Copy is not possible
1145 std::shared_ptr
<OTableRow
> pRow
;
1146 tools::Long nIndex
= FirstSelectedRow();
1147 while( nIndex
!= SFX_ENDOFSELECTION
)
1149 pRow
= (*m_pRowList
)[nIndex
];
1150 if( !pRow
->GetActFieldDescr() )
1153 nIndex
= NextSelectedRow();
1156 bIsCopyAllowed
= true;
1159 return bIsCopyAllowed
;
1162 bool OTableEditorCtrl::IsPasteAllowed() const
1164 bool bAllowed
= GetView()->getController().isAddAllowed();
1167 TransferableDataHelper
aTransferData(TransferableDataHelper::CreateFromSystemClipboard(GetParent()));
1168 bool bRowFormat
= aTransferData
.HasFormat(SotClipboardFormatId::SBA_TABED
);
1169 if ( m_eChildFocus
== ROW
)
1170 bAllowed
= bRowFormat
;
1172 bAllowed
= !bRowFormat
&& aTransferData
.HasFormat(SotClipboardFormatId::STRING
);
1178 void OTableEditorCtrl::cut()
1180 if(m_eChildFocus
== NAME
)
1182 if(GetView()->getController().isAlterAllowed())
1184 SaveData(-1,FIELD_NAME
);
1185 pNameCell
->get_widget().cut_clipboard();
1186 CellModified(-1,FIELD_NAME
);
1189 else if(m_eChildFocus
== DESCRIPTION
)
1191 if(GetView()->getController().isAlterAllowed())
1193 SaveData(-1,COLUMN_DESCRIPTION
);
1194 pDescrCell
->get_widget().cut_clipboard();
1195 CellModified(-1,COLUMN_DESCRIPTION
);
1198 else if(HELPTEXT
== m_eChildFocus
)
1200 if(GetView()->getController().isAlterAllowed())
1202 SaveData(-1,HELP_TEXT
);
1203 pHelpTextCell
->get_widget().cut_clipboard();
1204 CellModified(-1,HELP_TEXT
);
1207 else if(m_eChildFocus
== ROW
)
1210 Application::RemoveUserEvent(nCutEvent
);
1211 nCutEvent
= Application::PostUserEvent(LINK(this, OTableEditorCtrl
, DelayedCut
), nullptr, true);
1215 void OTableEditorCtrl::copy()
1217 if (GetSelectRowCount())
1218 OTableRowView::copy();
1219 else if(m_eChildFocus
== NAME
)
1221 weld::Entry
& rEntry
= pNameCell
->get_widget();
1222 rEntry
.copy_clipboard();
1224 else if(HELPTEXT
== m_eChildFocus
)
1226 weld::Entry
& rEntry
= pHelpTextCell
->get_widget();
1227 rEntry
.copy_clipboard();
1229 else if(m_eChildFocus
== DESCRIPTION
)
1231 weld::Entry
& rEntry
= pDescrCell
->get_widget();
1232 rEntry
.copy_clipboard();
1236 void OTableEditorCtrl::paste()
1238 TransferableDataHelper
aTransferData(TransferableDataHelper::CreateFromSystemClipboard(GetParent()));
1239 if(aTransferData
.HasFormat(SotClipboardFormatId::SBA_TABED
))
1242 Application::RemoveUserEvent( nPasteEvent
);
1243 nPasteEvent
= Application::PostUserEvent( LINK(this, OTableEditorCtrl
, DelayedPaste
), nullptr, true );
1245 else if(m_eChildFocus
== NAME
)
1247 if(GetView()->getController().isAlterAllowed())
1249 pNameCell
->get_widget().paste_clipboard();
1253 else if(HELPTEXT
== m_eChildFocus
)
1255 if(GetView()->getController().isAlterAllowed())
1257 pHelpTextCell
->get_widget().paste_clipboard();
1261 else if(m_eChildFocus
== DESCRIPTION
)
1263 if(GetView()->getController().isAlterAllowed())
1265 pDescrCell
->get_widget().paste_clipboard();
1271 bool OTableEditorCtrl::IsDeleteAllowed()
1274 return GetSelectRowCount() != 0 && GetView()->getController().isDropAllowed();
1277 bool OTableEditorCtrl::IsInsertNewAllowed( sal_Int32 nRow
)
1280 bool bInsertNewAllowed
= GetView()->getController().isAddAllowed();
1281 // If fields can be added, Paste in the new fields
1282 if (bInsertNewAllowed
&& !GetView()->getController().isDropAllowed())
1285 if( GetActRow()->IsReadOnly() )
1289 return bInsertNewAllowed
;
1292 bool OTableEditorCtrl::IsPrimaryKeyAllowed()
1294 if( !GetSelectRowCount() )
1297 OTableController
& rController
= GetView()->getController();
1298 if ( !rController
.getSdbMetaData().supportsPrimaryKeys() )
1301 Reference
<XPropertySet
> xTable
= rController
.getTable();
1302 // Key must not be changed
1303 // This applies only if the table is not new and not a css::sdbcx::View. Otherwise no DROP is executed
1305 if(xTable
.is() && ::comphelper::getString(xTable
->getPropertyValue(PROPERTY_TYPE
)) == "VIEW")
1307 // If there is an empty field, no primary key
1308 // The entry is only permitted if
1309 // - there are no empty entries in the selection
1310 // - No Memo or Image entries
1311 // - DROP is not permitted (see above) and the column is not Required (not null flag is not set).
1312 tools::Long nIndex
= FirstSelectedRow();
1313 std::shared_ptr
<OTableRow
> pRow
;
1314 while( nIndex
!= SFX_ENDOFSELECTION
)
1316 pRow
= (*m_pRowList
)[nIndex
];
1317 OFieldDescription
* pFieldDescr
= pRow
->GetActFieldDescr();
1322 // Memo and Image fields cannot be primary keys
1323 // or if the column cannot be dropped and the Required flag is not set
1324 // or if a css::sdbcx::View is available and the Required flag is not set
1325 const TOTypeInfoSP
& pTypeInfo
= pFieldDescr
->getTypeInfo();
1326 if( pTypeInfo
->nSearchType
== ColumnSearch::NONE
1327 || (pFieldDescr
->IsNullable() && pRow
->IsReadOnly())
1332 nIndex
= NextSelectedRow();
1338 void OTableEditorCtrl::Command(const CommandEvent
& rEvt
)
1340 switch (rEvt
.GetCommand())
1342 case CommandEventId::ContextMenu
:
1344 Point
aMenuPos( rEvt
.GetMousePosPixel() );
1345 if (!rEvt
.IsMouseEvent())
1347 if ( 1 == GetSelectColumnCount() )
1349 sal_uInt16 nSelId
= GetColumnId(
1350 sal::static_int_cast
< sal_uInt16
>(
1351 FirstSelectedColumn() ) );
1352 ::tools::Rectangle
aColRect( GetFieldRectPixel( 0, nSelId
, false ) );
1354 aMenuPos
= aColRect
.TopCenter();
1356 else if ( GetSelectRowCount() > 0 )
1358 ::tools::Rectangle
aColRect( GetFieldRectPixel( FirstSelectedRow(), HANDLE_ID
) );
1360 aMenuPos
= aColRect
.TopCenter();
1364 OTableRowView::Command(rEvt
);
1369 // Show the Context menu
1372 sal_uInt16 nColId
= GetColumnId(GetColumnAtXPosPixel(aMenuPos
.X()));
1373 sal_Int32 nRow
= GetRowAtYPosPixel(aMenuPos
.Y());
1375 if ( HANDLE_ID
!= nColId
)
1377 if ( nRow
< 0 && nColId
!= BROWSER_INVALIDID
)
1380 { // 3 would mean the last column, and this last column is auto-sized
1381 if ( !IsColumnSelected( nColId
) )
1382 SelectColumnId( nColId
);
1384 ::tools::Rectangle
aRect(aMenuPos
, Size(1, 1));
1385 weld::Window
* pPopupParent
= weld::GetPopupParent(*this, aRect
);
1386 std::unique_ptr
<weld::Builder
> xBuilder(Application::CreateBuilder(pPopupParent
, u
"dbaccess/ui/querycolmenu.ui"_ustr
));
1387 std::unique_ptr
<weld::Menu
> xContextMenu(xBuilder
->weld_menu(u
"menu"_ustr
));
1388 xContextMenu
->remove(u
"delete"_ustr
);
1389 xContextMenu
->remove(u
"separator"_ustr
);
1390 if (xContextMenu
->popup_at_rect(pPopupParent
, aRect
) == "width")
1391 adjustBrowseBoxColumnWidth( this, nColId
);
1397 ::tools::Rectangle
aRect(aMenuPos
, Size(1, 1));
1398 weld::Window
* pPopupParent
= weld::GetPopupParent(*this, aRect
);
1399 std::unique_ptr
<weld::Builder
> xBuilder(Application::CreateBuilder(pPopupParent
, u
"dbaccess/ui/tabledesignrowmenu.ui"_ustr
));
1400 std::unique_ptr
<weld::Menu
> xContextMenu(xBuilder
->weld_menu(u
"menu"_ustr
));
1402 if (!IsCutAllowed())
1403 xContextMenu
->remove(u
"cut"_ustr
);
1404 if (!IsCopyAllowed())
1405 xContextMenu
->remove(u
"copy"_ustr
);
1406 if (!IsPasteAllowed())
1407 xContextMenu
->remove(u
"paste"_ustr
);
1408 if (!IsDeleteAllowed())
1409 xContextMenu
->remove(u
"delete"_ustr
);
1410 // tdf#71224: WORKAROUND for the moment, we don't implement insert field at specific position
1411 // It's not SQL standard and each database has made its choice (some use "BEFORE", other "FIRST" and "AFTER")
1412 // and some, like Postgresql, don't allow this.
1413 // So for the moment, test if the table already exists (and so it's an edition), in this case only
1414 // we remove "Insert Fields" entry. Indeed, in case of new table, there's no pb.
1416 // The real fix is to implement the insert for each database + error message for those which don't support this
1417 //if (!IsInsertNewAllowed(nRow))
1418 if ( GetView()->getController().getTable().is() )
1419 xContextMenu
->remove(u
"insert"_ustr
);
1421 if (IsPrimaryKeyAllowed())
1423 xContextMenu
->set_active(u
"primarykey"_ustr
, IsRowSelected(GetCurRow()) && IsPrimaryKey());
1427 xContextMenu
->remove(u
"primarykey"_ustr
);
1430 if( SetDataPtr(m_nDataPos
) )
1431 pDescrWin
->SaveData( pActRow
->GetActFieldDescr() );
1433 // All actions which change the number of rows must be run asynchronously
1434 // otherwise there may be problems between the Context menu and the Browser
1435 m_nDataPos
= GetCurRow();
1436 OUString sIdent
= xContextMenu
->popup_at_rect(pPopupParent
, aRect
);
1437 if (sIdent
== "cut")
1439 else if (sIdent
== "copy")
1441 else if (sIdent
== "paste")
1443 else if (sIdent
== "delete")
1446 Application::RemoveUserEvent( nDeleteEvent
);
1447 nDeleteEvent
= Application::PostUserEvent( LINK(this, OTableEditorCtrl
, DelayedDelete
), nullptr, true );
1449 else if (sIdent
== "insert")
1451 if( nInsNewRowsEvent
)
1452 Application::RemoveUserEvent( nInsNewRowsEvent
);
1453 nInsNewRowsEvent
= Application::PostUserEvent( LINK(this, OTableEditorCtrl
, DelayedInsNewRows
), nullptr, true );
1455 else if (sIdent
== "primarykey")
1457 SetPrimaryKey( !IsPrimaryKey() );
1464 OTableRowView::Command(rEvt
);
1469 IMPL_LINK_NOARG( OTableEditorCtrl
, DelayedCut
, void*, void )
1471 nCutEvent
= nullptr;
1472 OTableRowView::cut();
1475 IMPL_LINK_NOARG( OTableEditorCtrl
, DelayedPaste
, void*, void )
1477 nPasteEvent
= nullptr;
1479 sal_Int32 nPastePosition
= GetView()->getController().getFirstEmptyRowPosition();
1480 if ( !GetView()->getController().getTable().is() )
1481 nPastePosition
= GetSelectRowCount() ? FirstSelectedRow() : GetCurRow();
1483 if (!IsInsertNewAllowed(nPastePosition
))
1484 { // Insertion is not allowed, only appending, so test if there are full cells after the PastePosition
1486 auto aIter
= std::find_if(m_pRowList
->rbegin(), m_pRowList
->rend(), [](const std::shared_ptr
<OTableRow
>& rxRow
) {
1487 return rxRow
&& rxRow
->GetActFieldDescr() && !rxRow
->GetActFieldDescr()->GetName().isEmpty(); });
1488 auto nFreeFromPos
= static_cast<sal_Int32
>(std::distance(aIter
, m_pRowList
->rend())); // from here on there are only empty rows
1489 if (nPastePosition
< nFreeFromPos
) // if at least one PastePosition is full, go right to the end
1490 nPastePosition
= nFreeFromPos
;
1493 OTableRowView::Paste( nPastePosition
);
1495 GoToRow( nPastePosition
);
1498 IMPL_LINK_NOARG( OTableEditorCtrl
, DelayedDelete
, void*, void )
1500 nDeleteEvent
= nullptr;
1504 IMPL_LINK_NOARG( OTableEditorCtrl
, DelayedInsNewRows
, void*, void )
1506 nInsNewRowsEvent
= nullptr;
1507 sal_Int32 nPastePosition
= GetView()->getController().getFirstEmptyRowPosition();
1508 if ( !GetView()->getController().getTable().is() )
1509 nPastePosition
= GetSelectRowCount() ? FirstSelectedRow() : m_nDataPos
;
1511 InsertNewRows( nPastePosition
);
1513 GoToRow( nPastePosition
);
1516 void OTableEditorCtrl::AdjustFieldDescription(OFieldDescription
* _pFieldDesc
,
1517 MultiSelection
& _rMultiSel
,
1522 _pFieldDesc
->SetPrimaryKey( _bPrimaryKey
);
1523 if(!_bSet
&& _pFieldDesc
->getTypeInfo()->bNullable
)
1525 _pFieldDesc
->SetIsNullable(ColumnValue::NO_NULLS
);
1526 _pFieldDesc
->SetControlDefault(Any());
1528 if ( _pFieldDesc
->IsAutoIncrement() && !_bPrimaryKey
)
1530 OTableController
& rController
= GetView()->getController();
1531 if ( rController
.isAutoIncrementPrimaryKey() )
1533 _pFieldDesc
->SetAutoIncrement(false);
1536 // update field description
1537 pDescrWin
->DisplayData(_pFieldDesc
);
1539 _rMultiSel
.Insert( _nPos
);
1540 _rMultiSel
.Select( _nPos
);
1543 void OTableEditorCtrl::SetPrimaryKey( bool bSet
)
1545 // Delete any existing Primary Keys
1546 MultiSelection aDeletedPrimKeys
;
1547 aDeletedPrimKeys
.SetTotalRange( Range(0,GetRowCount()) );
1550 for (auto const& row
: *m_pRowList
)
1552 OFieldDescription
* pFieldDescr
= row
->GetActFieldDescr();
1553 if( pFieldDescr
&& row
->IsPrimaryKey() && (!bSet
|| !IsRowSelected(nRow
)) )
1555 AdjustFieldDescription(pFieldDescr
,aDeletedPrimKeys
,nRow
,bSet
,false);
1560 // Set the primary keys of the marked rows
1561 MultiSelection aInsertedPrimKeys
;
1562 aInsertedPrimKeys
.SetTotalRange( Range(0,GetRowCount()) );
1565 tools::Long nIndex
= FirstSelectedRow();
1566 while( nIndex
!= SFX_ENDOFSELECTION
)
1569 std::shared_ptr
<OTableRow
> pRow
= (*m_pRowList
)[nIndex
];
1570 OFieldDescription
* pFieldDescr
= pRow
->GetActFieldDescr();
1572 AdjustFieldDescription(pFieldDescr
,aInsertedPrimKeys
,nIndex
,false,true);
1574 nIndex
= NextSelectedRow();
1578 GetUndoManager().AddUndoAction( std::make_unique
<OPrimKeyUndoAct
>(this, aDeletedPrimKeys
, aInsertedPrimKeys
) );
1580 // Invalidate the handle-columns
1581 InvalidateHandleColumn();
1583 // Set the TableDocSh's ModifyFlag
1584 GetView()->getController().setModified( true );
1585 InvalidateFeatures();
1588 bool OTableEditorCtrl::IsPrimaryKey()
1590 // Are all marked fields part of the Primary Key ?
1591 tools::Long nPrimaryKeys
= 0;
1593 for (auto const& row
: *m_pRowList
)
1595 if( IsRowSelected(nRow
) && !row
->IsPrimaryKey() )
1597 if( row
->IsPrimaryKey() )
1602 // Are there any unselected fields that are part of the Key ?
1603 return GetSelectRowCount() == nPrimaryKeys
;
1606 void OTableEditorCtrl::SwitchType( const TOTypeInfoSP
& _pType
)
1608 // if there is no assigned field name
1609 sal_Int32
nRow(GetCurRow());
1610 OFieldDescription
* pActFieldDescr
= GetFieldDescr( nRow
);
1611 if( pActFieldDescr
)
1612 // Store the old description
1613 pDescrWin
->SaveData( pActFieldDescr
);
1615 if ( nRow
< 0 || o3tl::make_unsigned(nRow
) > m_pRowList
->size() )
1617 // Show the new description
1618 std::shared_ptr
<OTableRow
> pRow
= (*m_pRowList
)[nRow
];
1619 pRow
->SetFieldType( _pType
, true );
1622 weld::ComboBox
& rTypeList
= pTypeCell
->get_widget();
1623 const sal_Int32 nCurrentlySelected
= rTypeList
.get_active();
1625 if ( ( nCurrentlySelected
== -1 )
1626 || ( GetView()->getController().getTypeInfo( nCurrentlySelected
) != _pType
)
1629 sal_Int32 nEntryPos
= 0;
1630 const OTypeInfoMap
& rTypeInfo
= GetView()->getController().getTypeInfo();
1631 for (auto const& elem
: rTypeInfo
)
1633 if(elem
.second
== _pType
)
1637 if (nEntryPos
< rTypeList
.get_count())
1638 rTypeList
.set_active(nEntryPos
);
1642 pActFieldDescr
= pRow
->GetActFieldDescr();
1643 if (pActFieldDescr
!= nullptr && !pActFieldDescr
->GetFormatKey())
1645 sal_Int32 nFormatKey
= ::dbtools::getDefaultNumberFormat( pActFieldDescr
->GetType(),
1646 pActFieldDescr
->GetScale(),
1647 pActFieldDescr
->IsCurrency(),
1648 Reference
< XNumberFormatTypes
>(GetView()->getController().getNumberFormatter()->getNumberFormatsSupplier()->getNumberFormats(),UNO_QUERY
),
1649 GetView()->getLocale());
1651 pActFieldDescr
->SetFormatKey(nFormatKey
);
1654 pDescrWin
->DisplayData( pActFieldDescr
);
1657 OTableDesignView
* OTableEditorCtrl::GetView() const
1662 void OTableEditorCtrl::DeactivateCell(bool bUpdate
)
1664 OTableRowView::DeactivateCell(bUpdate
);
1665 // now we have to deactivate the field description
1666 sal_Int32
nRow(GetCurRow());
1668 pDescrWin
->SetReadOnly(bReadOnly
|| !SetDataPtr(nRow
) || GetActRow()->IsReadOnly());
1671 bool OTableEditorCtrl::PreNotify( NotifyEvent
& rNEvt
)
1673 if (rNEvt
.GetType() == NotifyEventType::GETFOCUS
)
1675 if( pHelpTextCell
&& pHelpTextCell
->HasChildPathFocus() )
1676 m_eChildFocus
= HELPTEXT
;
1677 else if( pDescrCell
&& pDescrCell
->HasChildPathFocus() )
1678 m_eChildFocus
= DESCRIPTION
;
1679 else if(pNameCell
&& pNameCell
->HasChildPathFocus() )
1680 m_eChildFocus
= NAME
;
1682 m_eChildFocus
= ROW
;
1685 return OTableRowView::PreNotify(rNEvt
);
1688 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */