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::container
;
53 using namespace ::com::sun::star::io
;
54 using namespace ::com::sun::star::beans
;
55 using namespace ::com::sun::star::util
;
56 using namespace ::com::sun::star::lang
;
57 using namespace ::com::sun::star::sdbc
;
58 using namespace ::com::sun::star::sdbcx
;
59 using namespace ::com::sun::star::sdb
;
64 // default field widths
65 #define FIELDNAME_WIDTH 100
66 #define FIELDTYPE_WIDTH 150
67 #define FIELDDESCR_WIDTH 300
69 // Maximum length in description field
70 #define MAX_DESCR_LEN 256
72 OTableEditorCtrl::ClipboardInvalidator::ClipboardInvalidator(OTableEditorCtrl
* _pOwner
)
73 : m_aInvalidateTimer("dbaccess ClipboardInvalidator")
77 m_aInvalidateTimer
.SetTimeout(500);
78 m_aInvalidateTimer
.SetInvokeHandler(LINK(this, OTableEditorCtrl::ClipboardInvalidator
, OnInvalidate
));
79 m_aInvalidateTimer
.Start();
82 OTableEditorCtrl::ClipboardInvalidator::~ClipboardInvalidator()
84 m_aInvalidateTimer
.Stop();
87 void OTableEditorCtrl::ClipboardInvalidator::Stop()
89 m_aInvalidateTimer
.Stop();
92 IMPL_LINK_NOARG(OTableEditorCtrl::ClipboardInvalidator
, OnInvalidate
, Timer
*, void)
94 m_pOwner
->GetView()->getController().InvalidateFeature(SID_CUT
);
95 m_pOwner
->GetView()->getController().InvalidateFeature(SID_COPY
);
96 m_pOwner
->GetView()->getController().InvalidateFeature(SID_PASTE
);
99 void OTableEditorCtrl::Init()
101 OTableRowView::Init();
103 // Should it be opened ReadOnly?
104 bool bRead(GetView()->getController().isReadOnly());
106 SetReadOnly( bRead
);
108 // Insert the columns
109 InsertDataColumn( FIELD_NAME
, DBA_RES(STR_TAB_FIELD_COLUMN_NAME
), FIELDNAME_WIDTH
);
111 InsertDataColumn( FIELD_TYPE
, DBA_RES(STR_TAB_FIELD_COLUMN_DATATYPE
), FIELDTYPE_WIDTH
);
113 ::dbaccess::ODsnTypeCollection
aDsnTypes(GetView()->getController().getORB());
114 bool bShowColumnDescription
= aDsnTypes
.supportsColumnDescription(::comphelper::getString(GetView()->getController().getDataSource()->getPropertyValue(PROPERTY_URL
)));
115 InsertDataColumn( HELP_TEXT
, DBA_RES(STR_TAB_HELP_TEXT
), bShowColumnDescription
? FIELDTYPE_WIDTH
: FIELDDESCR_WIDTH
);
117 if ( bShowColumnDescription
)
119 InsertDataColumn( COLUMN_DESCRIPTION
, DBA_RES(STR_COLUMN_DESCRIPTION
), FIELDTYPE_WIDTH
);
122 InitCellController();
125 RowInserted(0, m_pRowList
->size());
128 OTableEditorCtrl::OTableEditorCtrl(vcl::Window
* pWindow
, OTableDesignView
* pView
)
129 :OTableRowView(pWindow
)
133 ,pHelpTextCell(nullptr)
137 ,nPasteEvent(nullptr)
138 ,nDeleteEvent(nullptr)
139 ,nInsNewRowsEvent(nullptr)
140 ,nInvalidateTypeEvent(nullptr)
146 SetHelpId(HID_TABDESIGN_BACKGROUND
);
147 GetDataWindow().SetHelpId(HID_CTL_TABLEEDIT
);
149 m_pRowList
= &GetView()->getController().getRows();
153 SfxUndoManager
& OTableEditorCtrl::GetUndoManager() const
155 return GetView()->getController().GetUndoManager();
159 void OTableEditorCtrl::SetReadOnly( bool bRead
)
162 if (bRead
== IsReadOnly())
163 // This check is important, as the underlying Def may be unnecessarily locked or unlocked
164 // or worse, this action may not be reversed afterwards
169 // Disable active cells
170 sal_Int32
nRow(GetCurRow());
171 sal_uInt16
nCol(GetCurColumnId());
174 // Select the correct Browsers cursor
175 BrowserMode
nMode(BrowserMode::COLUMNSELECTION
| BrowserMode::MULTISELECTION
| BrowserMode::KEEPHIGHLIGHT
|
176 BrowserMode::HLINES
| BrowserMode::VLINES
|BrowserMode::AUTOSIZE_LASTCOL
);
178 nMode
|= BrowserMode::HIDECURSOR
;
182 ActivateCell( nRow
, nCol
);
185 void OTableEditorCtrl::InitCellController()
188 sal_Int32 nMaxTextLen
= 0;
189 OUString sExtraNameChars
;
190 Reference
<XConnection
> xCon
;
193 xCon
= GetView()->getController().getConnection();
194 Reference
< XDatabaseMetaData
> xMetaData
= xCon
.is() ? xCon
->getMetaData() : Reference
< XDatabaseMetaData
>();
196 // length 0 is treated by Entry::set_max_length as unlimited
197 nMaxTextLen
= xMetaData
.is() ? xMetaData
->getMaxColumnNameLength() : 0;
199 sExtraNameChars
= xMetaData
.is() ? xMetaData
->getExtraNameCharacters() : OUString();
204 OSL_FAIL("getMaxColumnNameLength");
207 pNameCell
= VclPtr
<OSQLNameEditControl
>::Create(&GetDataWindow(), sExtraNameChars
);
208 pNameCell
->get_widget().set_max_length(nMaxTextLen
);
209 pNameCell
->setCheck( isSQL92CheckEnabled(xCon
) );
212 pTypeCell
= VclPtr
<ListBoxControl
>::Create( &GetDataWindow() );
215 pDescrCell
= VclPtr
<EditControl
>::Create(&GetDataWindow());
216 pDescrCell
->get_widget().set_max_length(MAX_DESCR_LEN
);
218 pHelpTextCell
= VclPtr
<EditControl
>::Create(&GetDataWindow());
219 pHelpTextCell
->get_widget().set_max_length(MAX_DESCR_LEN
);
221 pNameCell
->SetHelpId(HID_TABDESIGN_NAMECELL
);
222 pTypeCell
->SetHelpId(HID_TABDESIGN_TYPECELL
);
223 pDescrCell
->SetHelpId(HID_TABDESIGN_COMMENTCELL
);
224 pHelpTextCell
->SetHelpId(HID_TABDESIGN_HELPTEXT
);
227 const Control
* pControls
[] = { pTypeCell
,pDescrCell
,pNameCell
,pHelpTextCell
};
228 for(const Control
* pControl
: pControls
)
230 const Size
aTemp(pControl
->GetOptimalSize());
231 if ( aTemp
.Height() > aHeight
.Height() )
232 aHeight
.setHeight( aTemp
.Height() );
234 SetDataRowHeight(aHeight
.Height());
239 void OTableEditorCtrl::ClearModified()
241 pNameCell
->get_widget().save_value();
242 pDescrCell
->get_widget().save_value();
243 pHelpTextCell
->get_widget().save_value();
244 pTypeCell
->get_widget().save_value();
247 OTableEditorCtrl::~OTableEditorCtrl()
252 void OTableEditorCtrl::dispose()
254 // Reset the Undo-Manager
255 GetUndoManager().Clear();
257 m_aInvalidate
.Stop();
259 // Take possible Events from the queue
261 Application::RemoveUserEvent( nCutEvent
);
263 Application::RemoveUserEvent( nPasteEvent
);
265 Application::RemoveUserEvent( nDeleteEvent
);
266 if( nInsNewRowsEvent
)
267 Application::RemoveUserEvent( nInsNewRowsEvent
);
268 if( nInvalidateTypeEvent
)
269 Application::RemoveUserEvent( nInvalidateTypeEvent
);
271 // Delete the control types
272 pNameCell
.disposeAndClear();
273 pTypeCell
.disposeAndClear();
274 pDescrCell
.disposeAndClear();
275 pHelpTextCell
.disposeAndClear();
278 OTableRowView::dispose();
281 bool OTableEditorCtrl::SetDataPtr( sal_Int32 nRow
)
286 OSL_ENSURE(nRow
< static_cast<tools::Long
>(m_pRowList
->size()),"Row is greater than size!");
287 if(nRow
>= static_cast<tools::Long
>(m_pRowList
->size()))
289 pActRow
= (*m_pRowList
)[nRow
];
290 return pActRow
!= nullptr;
293 bool OTableEditorCtrl::SeekRow(sal_Int32 _nRow
)
295 // Call the Base class to remember which row must be repainted
296 EditBrowseBox::SeekRow(_nRow
);
298 m_nCurrentPos
= _nRow
;
299 return SetDataPtr(_nRow
);
302 void OTableEditorCtrl::PaintCell(OutputDevice
& rDev
, const tools::Rectangle
& rRect
,
303 sal_uInt16 nColumnId
) const
305 const OUString
aText( GetCellText( m_nCurrentPos
, nColumnId
));
307 rDev
.Push( vcl::PushFlags::CLIPREGION
);
308 rDev
.SetClipRegion(vcl::Region(rRect
));
309 rDev
.DrawText( rRect
, aText
, DrawTextFlags::Left
| DrawTextFlags::VCenter
);
313 CellController
* OTableEditorCtrl::GetController(sal_Int32 nRow
, sal_uInt16 nColumnId
)
315 // If EditorCtrl is ReadOnly, editing is forbidden
316 Reference
<XPropertySet
> xTable
= GetView()->getController().getTable();
317 if (IsReadOnly() || ( xTable
.is() &&
318 xTable
->getPropertySetInfo()->hasPropertyByName(PROPERTY_TYPE
) &&
319 ::comphelper::getString(xTable
->getPropertyValue(PROPERTY_TYPE
)) == "VIEW"))
322 // If the row is ReadOnly, editing is forbidden
324 if( pActRow
->IsReadOnly() )
327 OFieldDescription
* pActFieldDescr
= pActRow
->GetActFieldDescr();
331 return new EditCellController( pNameCell
);
333 if (pActFieldDescr
&& !pActFieldDescr
->GetName().isEmpty())
334 return new ListBoxCellController( pTypeCell
);
337 if (pActFieldDescr
&& !pActFieldDescr
->GetName().isEmpty())
338 return new EditCellController( pHelpTextCell
);
341 case COLUMN_DESCRIPTION
:
342 if (pActFieldDescr
&& !pActFieldDescr
->GetName().isEmpty())
343 return new EditCellController( pDescrCell
);
351 void OTableEditorCtrl::InitController(CellControllerRef
&, sal_Int32 nRow
, sal_uInt16 nColumnId
)
353 SeekRow( nRow
== -1 ? GetCurRow() : nRow
);
354 OFieldDescription
* pActFieldDescr
= pActRow
->GetActFieldDescr();
355 OUString aInitString
;
362 aInitString
= pActFieldDescr
->GetName();
364 weld::Entry
& rEntry
= pNameCell
->get_widget();
365 rEntry
.set_text(aInitString
);
371 if ( pActFieldDescr
&& pActFieldDescr
->getTypeInfo() )
372 aInitString
= pActFieldDescr
->getTypeInfo()->aUIName
;
374 // Set the ComboBox contents
375 weld::ComboBox
& rTypeList
= pTypeCell
->get_widget();
377 if( !pActFieldDescr
)
380 const OTypeInfoMap
& rTypeInfo
= GetView()->getController().getTypeInfo();
381 for (auto const& elem
: rTypeInfo
)
382 rTypeList
.append_text(elem
.second
->aUIName
);
383 rTypeList
.set_active_text(aInitString
);
390 aInitString
= pActFieldDescr
->GetHelpText();
391 weld::Entry
& rEntry
= pHelpTextCell
->get_widget();
392 rEntry
.set_text(aInitString
);
396 case COLUMN_DESCRIPTION
:
399 aInitString
= pActFieldDescr
->GetDescription();
400 weld::Entry
& rEntry
= pDescrCell
->get_widget();
401 rEntry
.set_text(aInitString
);
408 EditBrowseBox::RowStatus
OTableEditorCtrl::GetRowStatus(sal_Int32 nRow
) const
410 const_cast<OTableEditorCtrl
*>(this)->SetDataPtr( nRow
);
412 return EditBrowseBox::CLEAN
;
413 if (nRow
>= 0 && nRow
== m_nDataPos
)
415 if( pActRow
->IsPrimaryKey() )
416 return EditBrowseBox::CURRENT_PRIMARYKEY
;
417 return EditBrowseBox::CURRENT
;
421 if( pActRow
->IsPrimaryKey() )
422 return EditBrowseBox::PRIMARYKEY
;
423 return EditBrowseBox::CLEAN
;
427 void OTableEditorCtrl::SaveCurRow()
429 if (GetFieldDescr(GetCurRow()) == nullptr)
430 // there is no data in the current row
435 SetDataPtr(GetCurRow());
436 pDescrWin
->SaveData( pActRow
->GetActFieldDescr() );
439 void OTableEditorCtrl::DisplayData(sal_Int32 nRow
)
441 // go to the correct cell
444 // Disable Edit-Mode temporarily
445 bool bWasEditing
= IsEditing();
449 CellControllerRef aTemp
;
450 InitController(aTemp
, nRow
, FIELD_NAME
);
451 InitController(aTemp
, nRow
, FIELD_TYPE
);
452 InitController(aTemp
, nRow
, COLUMN_DESCRIPTION
);
453 InitController(aTemp
, nRow
, HELP_TEXT
);
456 // Update the Description-Window
457 GetView()->GetDescWin()->DisplayData(GetFieldDescr(nRow
));
461 // and re-enable edit mode
462 ActivateCell(nRow
, GetCurColumnId());
465 void OTableEditorCtrl::CursorMoved()
468 m_nDataPos
= GetCurRow();
469 if( m_nDataPos
!= nOldDataPos
&& m_nDataPos
!= -1)
471 CellControllerRef aTemp
;
472 InitController(aTemp
,m_nDataPos
,FIELD_NAME
);
473 InitController(aTemp
,m_nDataPos
,FIELD_TYPE
);
474 InitController(aTemp
,m_nDataPos
,COLUMN_DESCRIPTION
);
475 InitController(aTemp
,m_nDataPos
,HELP_TEXT
);
478 OTableRowView::CursorMoved();
481 sal_Int32
OTableEditorCtrl::HasFieldName( std::u16string_view rFieldName
)
484 Reference
<XConnection
> xCon
= GetView()->getController().getConnection();
485 Reference
< XDatabaseMetaData
> xMetaData
= xCon
.is() ? xCon
->getMetaData() : Reference
< XDatabaseMetaData
>();
487 ::comphelper::UStringMixEqual
bCase(!xMetaData
.is() || xMetaData
->supportsMixedCaseQuotedIdentifiers());
490 for (auto const& row
: *m_pRowList
)
492 OFieldDescription
* pFieldDescr
= row
->GetActFieldDescr();
493 if( pFieldDescr
&& bCase(rFieldName
,pFieldDescr
->GetName()))
499 void OTableEditorCtrl::SaveData(sal_Int32 nRow
, sal_uInt16 nColId
)
501 // Store the cell content
502 SetDataPtr( nRow
== -1 ? GetCurRow() : nRow
);
503 OFieldDescription
* pActFieldDescr
= pActRow
->GetActFieldDescr();
510 // If there is no name, do nothing
511 weld::Entry
& rEntry
= pNameCell
->get_widget();
512 const OUString
aName(rEntry
.get_text());
514 if( aName
.isEmpty() )
516 // If FieldDescr exists, the field is deleted and the old content restored
519 GetUndoManager().AddUndoAction(std::make_unique
<OTableEditorTypeSelUndoAct
>(this, nRow
, FIELD_TYPE
, pActFieldDescr
->getTypeInfo()));
520 SwitchType(TOTypeInfoSP());
521 pActFieldDescr
= pActRow
->GetActFieldDescr();
527 pActFieldDescr
->SetName( aName
);
533 // Store the field type
540 // if the current field description is NULL, set Default
541 weld::Entry
& rEntry
= pHelpTextCell
->get_widget();
542 if( !pActFieldDescr
)
544 rEntry
.set_text(OUString());
548 pActFieldDescr
->SetHelpText(rEntry
.get_text());
551 case COLUMN_DESCRIPTION
:
553 // Set the default if the field description is null
554 weld::Entry
& rEntry
= pDescrCell
->get_widget();
555 if( !pActFieldDescr
)
557 rEntry
.set_text(OUString());
561 pActFieldDescr
->SetDescription(rEntry
.get_text());
564 case FIELD_PROPERTY_DEFAULT
:
565 case FIELD_PROPERTY_REQUIRED
:
566 case FIELD_PROPERTY_TEXTLEN
:
567 case FIELD_PROPERTY_NUMTYPE
:
568 case FIELD_PROPERTY_AUTOINC
:
569 case FIELD_PROPERTY_LENGTH
:
570 case FIELD_PROPERTY_SCALE
:
571 case FIELD_PROPERTY_BOOL_DEFAULT
:
572 pDescrWin
->SaveData(pActFieldDescr
);
574 if ( FIELD_PROPERTY_AUTOINC
== nColId
&& pActFieldDescr
->IsAutoIncrement() )
576 OTableController
& rController
= GetView()->getController();
577 if ( rController
.isAutoIncrementPrimaryKey() )
579 pActFieldDescr
->SetPrimaryKey( true );
580 InvalidateHandleColumn();
588 bool OTableEditorCtrl::SaveModified()
590 sal_uInt16 nColId
= GetCurColumnId();
605 bool OTableEditorCtrl::CursorMoving(sal_Int32 nNewRow
, sal_uInt16 nNewCol
)
608 if (!EditBrowseBox::CursorMoving(nNewRow
, nNewCol
))
611 // Called after SaveModified(), current row is still the old one
612 m_nDataPos
= nNewRow
;
613 nOldDataPos
= GetCurRow();
616 InvalidateStatusCell( nOldDataPos
);
617 InvalidateStatusCell( m_nDataPos
);
619 // Store the data from the Property window
620 if( SetDataPtr(nOldDataPos
) && pDescrWin
)
621 pDescrWin
->SaveData( pActRow
->GetActFieldDescr() );
623 // Show new data in the Property window
624 if( SetDataPtr(m_nDataPos
) && pDescrWin
)
625 pDescrWin
->DisplayData( pActRow
->GetActFieldDescr() );
630 IMPL_LINK_NOARG( OTableEditorCtrl
, InvalidateFieldType
, void*, void )
632 nInvalidateTypeEvent
= nullptr;
633 Invalidate( GetFieldRectPixel(nOldDataPos
, FIELD_TYPE
) );
636 void OTableEditorCtrl::CellModified( sal_Int32 nRow
, sal_uInt16 nColId
)
639 // If the description is null, use the default
643 OFieldDescription
* pActFieldDescr
= pActRow
->GetActFieldDescr();
645 OUString sActionDescription
;
648 case FIELD_NAME
: sActionDescription
= DBA_RES( STR_CHANGE_COLUMN_NAME
); break;
649 case FIELD_TYPE
: sActionDescription
= DBA_RES( STR_CHANGE_COLUMN_TYPE
); break;
651 case COLUMN_DESCRIPTION
: sActionDescription
= DBA_RES( STR_CHANGE_COLUMN_DESCRIPTION
); break;
652 default: sActionDescription
= DBA_RES( STR_CHANGE_COLUMN_ATTRIBUTE
); break;
655 GetUndoManager().EnterListAction( sActionDescription
, OUString(), 0, ViewShellId(-1) );
658 const OTypeInfoMap
& rTypeInfoMap
= GetView()->getController().getTypeInfo();
659 if ( !rTypeInfoMap
.empty() )
661 OTypeInfoMap::const_iterator aTypeIter
= rTypeInfoMap
.find(DataType::VARCHAR
);
662 if ( aTypeIter
== rTypeInfoMap
.end() )
663 aTypeIter
= rTypeInfoMap
.begin();
664 pActRow
->SetFieldType( aTypeIter
->second
);
667 pActRow
->SetFieldType( GetView()->getController().getTypeInfoFallBack() );
669 nInvalidateTypeEvent
= Application::PostUserEvent( LINK(this, OTableEditorCtrl
, InvalidateFieldType
), nullptr, true );
670 pActFieldDescr
= pActRow
->GetActFieldDescr();
671 pDescrWin
->DisplayData( pActFieldDescr
);
672 GetUndoManager().AddUndoAction( std::make_unique
<OTableEditorTypeSelUndoAct
>(this, nRow
, nColId
+1, TOTypeInfoSP()) );
675 if( nColId
!= FIELD_TYPE
)
676 GetUndoManager().AddUndoAction( std::make_unique
<OTableDesignCellUndoAct
>(this, nRow
, nColId
) );
679 GetUndoManager().AddUndoAction(std::make_unique
<OTableEditorTypeSelUndoAct
>(this, GetCurRow(), nColId
, GetFieldDescr(GetCurRow())->getTypeInfo()));
683 SaveData(nRow
,nColId
);
684 // SaveData could create an undo action as well
685 GetUndoManager().LeaveListAction();
688 // Set the Modify flag
689 GetView()->getController().setModified( true );
690 InvalidateFeatures();
693 void OTableEditorCtrl::resetType()
695 sal_Int32 nPos
= pTypeCell
->get_widget().get_active();
697 SwitchType( GetView()->getController().getTypeInfo(nPos
) );
699 SwitchType(TOTypeInfoSP());
702 void OTableEditorCtrl::CellModified()
704 CellModified( GetCurRow(), GetCurColumnId() );
707 void OTableEditorCtrl::InvalidateFeatures()
709 GetView()->getController().InvalidateFeature(SID_UNDO
);
710 GetView()->getController().InvalidateFeature(SID_REDO
);
711 GetView()->getController().InvalidateFeature(SID_SAVEDOC
);
714 void OTableEditorCtrl::CopyRows()
716 // set to the right row and save it
717 if( SetDataPtr(m_nDataPos
) )
718 pDescrWin
->SaveData( pActRow
->GetActFieldDescr() );
720 // Copy selected rows to the ClipboardList
721 std::shared_ptr
<OTableRow
> pClipboardRow
;
722 std::shared_ptr
<OTableRow
> pRow
;
723 std::vector
< std::shared_ptr
<OTableRow
> > vClipboardList
;
724 vClipboardList
.reserve(GetSelectRowCount());
726 for( tools::Long nIndex
=FirstSelectedRow(); nIndex
!= SFX_ENDOFSELECTION
; nIndex
=NextSelectedRow() )
728 pRow
= (*m_pRowList
)[nIndex
];
729 OSL_ENSURE(pRow
,"OTableEditorCtrl::CopyRows: Row is NULL!");
730 if ( pRow
&& pRow
->GetActFieldDescr() )
732 pClipboardRow
= std::make_shared
<OTableRow
>( *pRow
);
733 vClipboardList
.push_back( pClipboardRow
);
736 if(!vClipboardList
.empty())
738 rtl::Reference
<OTableRowExchange
> pData
= new OTableRowExchange(std::move(vClipboardList
));
739 pData
->CopyToClipboard(GetParent());
743 OUString
OTableEditorCtrl::GenerateName( const OUString
& rName
)
745 // Create a base name for appending numbers to
747 Reference
<XConnection
> xCon
= GetView()->getController().getConnection();
748 Reference
< XDatabaseMetaData
> xMetaData
= xCon
.is() ? xCon
->getMetaData() : Reference
< XDatabaseMetaData
>();
750 sal_Int32
nMaxTextLen(xMetaData
.is() ? xMetaData
->getMaxColumnNameLength() : 0);
752 if( (rName
.getLength()+2) >nMaxTextLen
)
753 aBaseName
= rName
.copy( 0, nMaxTextLen
-2 );
757 // append a sequential number to the base name (up to 99)
758 OUString
aFieldName( rName
);
760 while( HasFieldName(aFieldName
) )
762 aFieldName
= aBaseName
+ OUString::number(i
);
769 void OTableEditorCtrl::InsertRows( sal_Int32 nRow
)
772 std::vector
< std::shared_ptr
<OTableRow
> > vInsertedUndoRedoRows
; // need for undo/redo handling
773 // get rows from clipboard
774 TransferableDataHelper
aTransferData(TransferableDataHelper::CreateFromSystemClipboard(GetParent()));
775 if(aTransferData
.HasFormat(SotClipboardFormatId::SBA_TABED
))
777 ::tools::SvRef
<SotTempStream
> aStreamRef
;
778 bool bOk
= aTransferData
.GetSotStorageStream(SotClipboardFormatId::SBA_TABED
,aStreamRef
);
779 if (bOk
&& aStreamRef
.is())
781 aStreamRef
->Seek(STREAM_SEEK_TO_BEGIN
);
782 aStreamRef
->ResetError();
783 sal_Int32 nInsertRow
= nRow
;
784 std::shared_ptr
<OTableRow
> pRow
;
786 (*aStreamRef
).ReadInt32( nSize
);
787 vInsertedUndoRedoRows
.reserve(nSize
);
788 for(sal_Int32 i
=0;i
< nSize
;++i
)
790 pRow
= std::make_shared
<OTableRow
>();
791 ReadOTableRow( *aStreamRef
, *pRow
);
792 pRow
->SetReadOnly( false );
793 sal_Int32 nType
= pRow
->GetActFieldDescr()->GetType();
794 if ( pRow
->GetActFieldDescr() )
795 pRow
->GetActFieldDescr()->SetType(GetView()->getController().getTypeInfoByType(nType
));
796 // Adjust the field names
797 pRow
->GetActFieldDescr()->SetName( GenerateName( pRow
->GetActFieldDescr()->GetName() ) );
798 pRow
->SetPos(nInsertRow
);
799 m_pRowList
->insert( m_pRowList
->begin()+nInsertRow
,pRow
);
800 vInsertedUndoRedoRows
.push_back(std::make_shared
<OTableRow
>(*pRow
));
805 // RowInserted calls CursorMoved.
806 // The UI data should not be stored here.
807 RowInserted( nRow
,vInsertedUndoRedoRows
.size() );
809 // Create the Undo-Action
810 GetUndoManager().AddUndoAction( std::make_unique
<OTableEditorInsUndoAct
>(this, nRow
, std::move(vInsertedUndoRedoRows
)) );
811 GetView()->getController().setModified( true );
812 InvalidateFeatures();
815 void OTableEditorCtrl::DeleteRows()
817 OSL_ENSURE(GetView()->getController().isDropAllowed(),"Call of DeleteRows not valid here. Please check isDropAllowed!");
818 // Create the Undo-Action
819 GetUndoManager().AddUndoAction( std::make_unique
<OTableEditorDelUndoAct
>(this) );
821 // Delete all marked rows
822 tools::Long nIndex
= FirstSelectedRow();
823 nOldDataPos
= nIndex
;
825 while( nIndex
!= SFX_ENDOFSELECTION
)
828 m_pRowList
->erase( m_pRowList
->begin()+nIndex
);
829 RowRemoved( nIndex
);
831 // Insert the empty row at the end
832 m_pRowList
->push_back( std::make_shared
<OTableRow
>());
833 RowInserted( GetRowCount()-1 );
835 nIndex
= FirstSelectedRow();
838 // Force the current record to be displayed
839 m_nDataPos
= GetCurRow();
840 InvalidateStatusCell( nOldDataPos
);
841 InvalidateStatusCell( m_nDataPos
);
842 SetDataPtr( m_nDataPos
);
844 pDescrWin
->DisplayData( pActRow
->GetActFieldDescr() );
845 GetView()->getController().setModified( true );
846 InvalidateFeatures();
849 void OTableEditorCtrl::InsertNewRows( sal_Int32 nRow
)
851 OSL_ENSURE(GetView()->getController().isAddAllowed(),"Call of InsertNewRows not valid here. Please check isAppendAllowed!");
852 // Create Undo-Action
853 sal_Int32 nInsertRows
= GetSelectRowCount();
856 GetUndoManager().AddUndoAction( std::make_unique
<OTableEditorInsNewUndoAct
>(this, nRow
, nInsertRows
) );
857 // Insert the number of selected rows
858 for( tools::Long i
=nRow
; i
<(nRow
+nInsertRows
); i
++ )
859 m_pRowList
->insert( m_pRowList
->begin()+i
,std::make_shared
<OTableRow
>());
860 RowInserted( nRow
, nInsertRows
);
862 GetView()->getController().setModified( true );
863 InvalidateFeatures();
866 void OTableEditorCtrl::SetControlText( sal_Int32 nRow
, sal_uInt16 nColId
, const OUString
& rText
)
868 // Set the Browser Controls
869 if( nColId
< FIELD_FIRST_VIRTUAL_COLUMN
)
872 GoToColumnId( nColId
);
873 CellControllerRef xController
= Controller();
875 xController
->GetWindow().SetText( rText
);
877 RowModified(nRow
,nColId
);
880 // Set the Tabpage controls
883 pDescrWin
->SetControlText( nColId
, rText
);
887 void OTableEditorCtrl::SetCellData( sal_Int32 nRow
, sal_uInt16 nColId
, const TOTypeInfoSP
& _pTypeInfo
)
889 // Relocate the current pointer
892 OFieldDescription
* pFieldDescr
= GetFieldDescr( nRow
);
893 if( !pFieldDescr
&& nColId
!= FIELD_TYPE
)
896 // Set individual fields
900 SwitchType( _pTypeInfo
);
903 OSL_FAIL("OTableEditorCtrl::SetCellData: invalid column!");
905 SetControlText(nRow
,nColId
,_pTypeInfo
? _pTypeInfo
->aUIName
: OUString());
908 void OTableEditorCtrl::SetCellData( sal_Int32 nRow
, sal_uInt16 nColId
, const css::uno::Any
& _rNewData
)
910 // Relocate the current pointer
913 OFieldDescription
* pFieldDescr
= GetFieldDescr( nRow
);
914 if( !pFieldDescr
&& nColId
!= FIELD_TYPE
)
918 // Set individual fields
922 sValue
= ::comphelper::getString(_rNewData
);
923 pFieldDescr
->SetName( sValue
);
927 OSL_FAIL("OTableEditorCtrl::SetCellData: invalid column!");
930 case COLUMN_DESCRIPTION
:
931 sValue
= ::comphelper::getString(_rNewData
);
932 pFieldDescr
->SetDescription( sValue
);
935 case FIELD_PROPERTY_DEFAULT
:
936 pFieldDescr
->SetControlDefault( _rNewData
);
937 sValue
= GetView()->GetDescWin()->getGenPage()->getControlDefault(pFieldDescr
);
940 case FIELD_PROPERTY_REQUIRED
:
942 sValue
= ::comphelper::getString(_rNewData
);
943 pFieldDescr
->SetIsNullable( sValue
.toInt32() );
947 case FIELD_PROPERTY_TEXTLEN
:
948 case FIELD_PROPERTY_LENGTH
:
950 sValue
= ::comphelper::getString(_rNewData
);
951 pFieldDescr
->SetPrecision( sValue
.toInt32() );
955 case FIELD_PROPERTY_NUMTYPE
:
956 OSL_FAIL("OTableEditorCtrl::SetCellData: invalid column!");
959 case FIELD_PROPERTY_AUTOINC
:
961 sValue
= ::comphelper::getString(_rNewData
);
962 pFieldDescr
->SetAutoIncrement(sValue
== DBA_RES(STR_VALUE_YES
));
965 case FIELD_PROPERTY_SCALE
:
967 sValue
= ::comphelper::getString(_rNewData
);
968 pFieldDescr
->SetScale(sValue
.toInt32());
972 case FIELD_PROPERTY_BOOL_DEFAULT
:
973 sValue
= GetView()->GetDescWin()->BoolStringPersistent(::comphelper::getString(_rNewData
));
974 pFieldDescr
->SetControlDefault(Any(sValue
));
977 case FIELD_PROPERTY_FORMAT
:
979 sValue
= ::comphelper::getString(_rNewData
);
980 pFieldDescr
->SetFormatKey(sValue
.toInt32());
985 SetControlText(nRow
,nColId
,sValue
);
988 Any
OTableEditorCtrl::GetCellData( sal_Int32 nRow
, sal_uInt16 nColId
)
990 OFieldDescription
* pFieldDescr
= GetFieldDescr( nRow
);
994 // Relocate the current pointer
999 static const OUString
strYes(DBA_RES(STR_VALUE_YES
));
1000 static const OUString
strNo(DBA_RES(STR_VALUE_NO
));
1002 // Read out the fields
1006 sValue
= pFieldDescr
->GetName();
1010 if ( pFieldDescr
->getTypeInfo() )
1011 sValue
= pFieldDescr
->getTypeInfo()->aUIName
;
1014 case COLUMN_DESCRIPTION
:
1015 sValue
= pFieldDescr
->GetDescription();
1018 sValue
= pFieldDescr
->GetHelpText();
1021 case FIELD_PROPERTY_DEFAULT
:
1022 return pFieldDescr
->GetControlDefault();
1024 case FIELD_PROPERTY_REQUIRED
:
1025 sValue
= pFieldDescr
->GetIsNullable() == ColumnValue::NULLABLE
? strYes
: strNo
;
1028 case FIELD_PROPERTY_TEXTLEN
:
1029 case FIELD_PROPERTY_LENGTH
:
1030 sValue
= OUString::number(pFieldDescr
->GetPrecision());
1033 case FIELD_PROPERTY_NUMTYPE
:
1034 OSL_FAIL("OTableEditorCtrl::GetCellData: invalid column!");
1037 case FIELD_PROPERTY_AUTOINC
:
1038 sValue
= pFieldDescr
->IsAutoIncrement() ? strYes
: strNo
;
1041 case FIELD_PROPERTY_SCALE
:
1042 sValue
= OUString::number(pFieldDescr
->GetScale());
1045 case FIELD_PROPERTY_BOOL_DEFAULT
:
1046 sValue
= GetView()->GetDescWin()->BoolStringUI(::comphelper::getString(pFieldDescr
->GetControlDefault()));
1049 case FIELD_PROPERTY_FORMAT
:
1050 sValue
= OUString::number(pFieldDescr
->GetFormatKey());
1057 OUString
OTableEditorCtrl::GetCellText( sal_Int32 nRow
, sal_uInt16 nColId
) const
1060 const_cast< OTableEditorCtrl
* >( this )->GetCellData( nRow
, nColId
) >>= sCellText
;
1064 sal_uInt32
OTableEditorCtrl::GetTotalCellWidth(sal_Int32 nRow
, sal_uInt16 nColId
)
1066 return GetTextWidth(GetCellText(nRow
, nColId
)) + 2 * GetTextWidth("0");
1069 OFieldDescription
* OTableEditorCtrl::GetFieldDescr( sal_Int32 nRow
)
1071 std::vector
< std::shared_ptr
<OTableRow
> >::size_type
nListCount(
1072 m_pRowList
->size());
1073 if( (nRow
<0) || (sal::static_int_cast
< unsigned long >(nRow
)>=nListCount
) )
1075 OSL_FAIL("(nRow<0) || (nRow>=nListCount)");
1078 std::shared_ptr
<OTableRow
> pRow
= (*m_pRowList
)[ nRow
];
1081 return pRow
->GetActFieldDescr();
1084 bool OTableEditorCtrl::IsCutAllowed()
1086 bool bIsCutAllowed
= (GetView()->getController().isAddAllowed() && GetView()->getController().isDropAllowed()) ||
1087 GetView()->getController().isAlterAllowed();
1091 int nStartPos
, nEndPos
;
1092 switch(m_eChildFocus
)
1096 weld::Entry
& rEntry
= pDescrCell
->get_widget();
1097 bIsCutAllowed
= rEntry
.get_selection_bounds(nStartPos
, nEndPos
);
1102 weld::Entry
& rEntry
= pHelpTextCell
->get_widget();
1103 bIsCutAllowed
= rEntry
.get_selection_bounds(nStartPos
, nEndPos
);
1108 weld::Entry
& rEntry
= pNameCell
->get_widget();
1109 bIsCutAllowed
= rEntry
.get_selection_bounds(nStartPos
, nEndPos
);
1113 bIsCutAllowed
= IsCopyAllowed();
1116 bIsCutAllowed
= false;
1121 return bIsCutAllowed
;
1124 bool OTableEditorCtrl::IsCopyAllowed()
1126 bool bIsCopyAllowed
= false;
1127 int nStartPos
, nEndPos
;
1128 if (m_eChildFocus
== DESCRIPTION
)
1130 weld::Entry
& rEntry
= pDescrCell
->get_widget();
1131 bIsCopyAllowed
= rEntry
.get_selection_bounds(nStartPos
, nEndPos
);
1133 else if(HELPTEXT
== m_eChildFocus
)
1135 weld::Entry
& rEntry
= pHelpTextCell
->get_widget();
1136 bIsCopyAllowed
= rEntry
.get_selection_bounds(nStartPos
, nEndPos
);
1138 else if(m_eChildFocus
== NAME
)
1140 weld::Entry
& rEntry
= pNameCell
->get_widget();
1141 bIsCopyAllowed
= rEntry
.get_selection_bounds(nStartPos
, nEndPos
);
1143 else if(m_eChildFocus
== ROW
)
1145 Reference
<XPropertySet
> xTable
= GetView()->getController().getTable();
1146 if( !GetSelectRowCount() || (xTable
.is() && ::comphelper::getString(xTable
->getPropertyValue(PROPERTY_TYPE
)) == "VIEW"))
1149 // If one of the selected rows is empty, Copy is not possible
1150 std::shared_ptr
<OTableRow
> pRow
;
1151 tools::Long nIndex
= FirstSelectedRow();
1152 while( nIndex
!= SFX_ENDOFSELECTION
)
1154 pRow
= (*m_pRowList
)[nIndex
];
1155 if( !pRow
->GetActFieldDescr() )
1158 nIndex
= NextSelectedRow();
1161 bIsCopyAllowed
= true;
1164 return bIsCopyAllowed
;
1167 bool OTableEditorCtrl::IsPasteAllowed() const
1169 bool bAllowed
= GetView()->getController().isAddAllowed();
1172 TransferableDataHelper
aTransferData(TransferableDataHelper::CreateFromSystemClipboard(GetParent()));
1173 bool bRowFormat
= aTransferData
.HasFormat(SotClipboardFormatId::SBA_TABED
);
1174 if ( m_eChildFocus
== ROW
)
1175 bAllowed
= bRowFormat
;
1177 bAllowed
= !bRowFormat
&& aTransferData
.HasFormat(SotClipboardFormatId::STRING
);
1183 void OTableEditorCtrl::cut()
1185 if(m_eChildFocus
== NAME
)
1187 if(GetView()->getController().isAlterAllowed())
1189 SaveData(-1,FIELD_NAME
);
1190 pNameCell
->get_widget().cut_clipboard();
1191 CellModified(-1,FIELD_NAME
);
1194 else if(m_eChildFocus
== DESCRIPTION
)
1196 if(GetView()->getController().isAlterAllowed())
1198 SaveData(-1,COLUMN_DESCRIPTION
);
1199 pDescrCell
->get_widget().cut_clipboard();
1200 CellModified(-1,COLUMN_DESCRIPTION
);
1203 else if(HELPTEXT
== m_eChildFocus
)
1205 if(GetView()->getController().isAlterAllowed())
1207 SaveData(-1,HELP_TEXT
);
1208 pHelpTextCell
->get_widget().cut_clipboard();
1209 CellModified(-1,HELP_TEXT
);
1212 else if(m_eChildFocus
== ROW
)
1215 Application::RemoveUserEvent(nCutEvent
);
1216 nCutEvent
= Application::PostUserEvent(LINK(this, OTableEditorCtrl
, DelayedCut
), nullptr, true);
1220 void OTableEditorCtrl::copy()
1222 if (GetSelectRowCount())
1223 OTableRowView::copy();
1224 else if(m_eChildFocus
== NAME
)
1226 weld::Entry
& rEntry
= pNameCell
->get_widget();
1227 rEntry
.copy_clipboard();
1229 else if(HELPTEXT
== m_eChildFocus
)
1231 weld::Entry
& rEntry
= pHelpTextCell
->get_widget();
1232 rEntry
.copy_clipboard();
1234 else if(m_eChildFocus
== DESCRIPTION
)
1236 weld::Entry
& rEntry
= pDescrCell
->get_widget();
1237 rEntry
.copy_clipboard();
1241 void OTableEditorCtrl::paste()
1243 TransferableDataHelper
aTransferData(TransferableDataHelper::CreateFromSystemClipboard(GetParent()));
1244 if(aTransferData
.HasFormat(SotClipboardFormatId::SBA_TABED
))
1247 Application::RemoveUserEvent( nPasteEvent
);
1248 nPasteEvent
= Application::PostUserEvent( LINK(this, OTableEditorCtrl
, DelayedPaste
), nullptr, true );
1250 else if(m_eChildFocus
== NAME
)
1252 if(GetView()->getController().isAlterAllowed())
1254 pNameCell
->get_widget().paste_clipboard();
1258 else if(HELPTEXT
== m_eChildFocus
)
1260 if(GetView()->getController().isAlterAllowed())
1262 pHelpTextCell
->get_widget().paste_clipboard();
1266 else if(m_eChildFocus
== DESCRIPTION
)
1268 if(GetView()->getController().isAlterAllowed())
1270 pDescrCell
->get_widget().paste_clipboard();
1276 bool OTableEditorCtrl::IsDeleteAllowed()
1279 return GetSelectRowCount() != 0 && GetView()->getController().isDropAllowed();
1282 bool OTableEditorCtrl::IsInsertNewAllowed( sal_Int32 nRow
)
1285 bool bInsertNewAllowed
= GetView()->getController().isAddAllowed();
1286 // If fields can be added, Paste in the new fields
1287 if (bInsertNewAllowed
&& !GetView()->getController().isDropAllowed())
1290 if( GetActRow()->IsReadOnly() )
1294 return bInsertNewAllowed
;
1297 bool OTableEditorCtrl::IsPrimaryKeyAllowed()
1299 if( !GetSelectRowCount() )
1302 OTableController
& rController
= GetView()->getController();
1303 if ( !rController
.getSdbMetaData().supportsPrimaryKeys() )
1306 Reference
<XPropertySet
> xTable
= rController
.getTable();
1307 // Key must not be changed
1308 // This applies only if the table is not new and not a css::sdbcx::View. Otherwise no DROP is executed
1310 if(xTable
.is() && ::comphelper::getString(xTable
->getPropertyValue(PROPERTY_TYPE
)) == "VIEW")
1312 // If there is an empty field, no primary key
1313 // The entry is only permitted if
1314 // - there are no empty entries in the selection
1315 // - No Memo or Image entries
1316 // - DROP is not permitted (see above) and the column is not Required (not null flag is not set).
1317 tools::Long nIndex
= FirstSelectedRow();
1318 std::shared_ptr
<OTableRow
> pRow
;
1319 while( nIndex
!= SFX_ENDOFSELECTION
)
1321 pRow
= (*m_pRowList
)[nIndex
];
1322 OFieldDescription
* pFieldDescr
= pRow
->GetActFieldDescr();
1327 // Memo and Image fields cannot be primary keys
1328 // or if the column cannot be dropped and the Required flag is not set
1329 // or if a css::sdbcx::View is available and the Required flag is not set
1330 const TOTypeInfoSP
& pTypeInfo
= pFieldDescr
->getTypeInfo();
1331 if( pTypeInfo
->nSearchType
== ColumnSearch::NONE
1332 || (pFieldDescr
->IsNullable() && pRow
->IsReadOnly())
1337 nIndex
= NextSelectedRow();
1343 void OTableEditorCtrl::Command(const CommandEvent
& rEvt
)
1345 switch (rEvt
.GetCommand())
1347 case CommandEventId::ContextMenu
:
1349 Point
aMenuPos( rEvt
.GetMousePosPixel() );
1350 if (!rEvt
.IsMouseEvent())
1352 if ( 1 == GetSelectColumnCount() )
1354 sal_uInt16 nSelId
= GetColumnId(
1355 sal::static_int_cast
< sal_uInt16
>(
1356 FirstSelectedColumn() ) );
1357 ::tools::Rectangle
aColRect( GetFieldRectPixel( 0, nSelId
, false ) );
1359 aMenuPos
= aColRect
.TopCenter();
1361 else if ( GetSelectRowCount() > 0 )
1363 ::tools::Rectangle
aColRect( GetFieldRectPixel( FirstSelectedRow(), HANDLE_ID
) );
1365 aMenuPos
= aColRect
.TopCenter();
1369 OTableRowView::Command(rEvt
);
1374 // Show the Context menu
1377 sal_uInt16 nColId
= GetColumnId(GetColumnAtXPosPixel(aMenuPos
.X()));
1378 sal_Int32 nRow
= GetRowAtYPosPixel(aMenuPos
.Y());
1380 if ( HANDLE_ID
!= nColId
)
1382 if ( nRow
< 0 && nColId
!= BROWSER_INVALIDID
)
1385 { // 3 would mean the last column, and this last column is auto-sized
1386 if ( !IsColumnSelected( nColId
) )
1387 SelectColumnId( nColId
);
1389 ::tools::Rectangle
aRect(aMenuPos
, Size(1, 1));
1390 weld::Window
* pPopupParent
= weld::GetPopupParent(*this, aRect
);
1391 std::unique_ptr
<weld::Builder
> xBuilder(Application::CreateBuilder(pPopupParent
, "dbaccess/ui/querycolmenu.ui"));
1392 std::unique_ptr
<weld::Menu
> xContextMenu(xBuilder
->weld_menu("menu"));
1393 xContextMenu
->remove("delete");
1394 xContextMenu
->remove("separator");
1395 if (xContextMenu
->popup_at_rect(pPopupParent
, aRect
) == "width")
1396 adjustBrowseBoxColumnWidth( this, nColId
);
1402 ::tools::Rectangle
aRect(aMenuPos
, Size(1, 1));
1403 weld::Window
* pPopupParent
= weld::GetPopupParent(*this, aRect
);
1404 std::unique_ptr
<weld::Builder
> xBuilder(Application::CreateBuilder(pPopupParent
, "dbaccess/ui/tabledesignrowmenu.ui"));
1405 std::unique_ptr
<weld::Menu
> xContextMenu(xBuilder
->weld_menu("menu"));
1407 if (!IsCutAllowed())
1408 xContextMenu
->remove("cut");
1409 if (!IsCopyAllowed())
1410 xContextMenu
->remove("copy");
1411 if (!IsPasteAllowed())
1412 xContextMenu
->remove("paste");
1413 if (!IsDeleteAllowed())
1414 xContextMenu
->remove("delete");
1415 if (!IsPrimaryKeyAllowed())
1416 xContextMenu
->remove("primarykey");
1417 if (!IsInsertNewAllowed(nRow
))
1418 xContextMenu
->remove("insert");
1419 xContextMenu
->set_active("primarykey", IsRowSelected(GetCurRow()) && IsPrimaryKey());
1421 if( SetDataPtr(m_nDataPos
) )
1422 pDescrWin
->SaveData( pActRow
->GetActFieldDescr() );
1424 // All actions which change the number of rows must be run asynchronously
1425 // otherwise there may be problems between the Context menu and the Browser
1426 m_nDataPos
= GetCurRow();
1427 OUString sIdent
= xContextMenu
->popup_at_rect(pPopupParent
, aRect
);
1428 if (sIdent
== "cut")
1430 else if (sIdent
== "copy")
1432 else if (sIdent
== "paste")
1434 else if (sIdent
== "delete")
1437 Application::RemoveUserEvent( nDeleteEvent
);
1438 nDeleteEvent
= Application::PostUserEvent( LINK(this, OTableEditorCtrl
, DelayedDelete
), nullptr, true );
1440 else if (sIdent
== "insert")
1442 if( nInsNewRowsEvent
)
1443 Application::RemoveUserEvent( nInsNewRowsEvent
);
1444 nInsNewRowsEvent
= Application::PostUserEvent( LINK(this, OTableEditorCtrl
, DelayedInsNewRows
), nullptr, true );
1446 else if (sIdent
== "primarykey")
1448 SetPrimaryKey( !IsPrimaryKey() );
1455 OTableRowView::Command(rEvt
);
1460 IMPL_LINK_NOARG( OTableEditorCtrl
, DelayedCut
, void*, void )
1462 nCutEvent
= nullptr;
1463 OTableRowView::cut();
1466 IMPL_LINK_NOARG( OTableEditorCtrl
, DelayedPaste
, void*, void )
1468 nPasteEvent
= nullptr;
1470 sal_Int32 nPastePosition
= GetView()->getController().getFirstEmptyRowPosition();
1471 if ( !GetView()->getController().getTable().is() )
1472 nPastePosition
= GetSelectRowCount() ? FirstSelectedRow() : GetCurRow();
1474 if (!IsInsertNewAllowed(nPastePosition
))
1475 { // Insertion is not allowed, only appending, so test if there are full cells after the PastePosition
1477 auto aIter
= std::find_if(m_pRowList
->rbegin(), m_pRowList
->rend(), [](const std::shared_ptr
<OTableRow
>& rxRow
) {
1478 return rxRow
&& rxRow
->GetActFieldDescr() && !rxRow
->GetActFieldDescr()->GetName().isEmpty(); });
1479 auto nFreeFromPos
= static_cast<sal_Int32
>(std::distance(aIter
, m_pRowList
->rend())); // from here on there are only empty rows
1480 if (nPastePosition
< nFreeFromPos
) // if at least one PastePosition is full, go right to the end
1481 nPastePosition
= nFreeFromPos
;
1484 OTableRowView::Paste( nPastePosition
);
1486 GoToRow( nPastePosition
);
1489 IMPL_LINK_NOARG( OTableEditorCtrl
, DelayedDelete
, void*, void )
1491 nDeleteEvent
= nullptr;
1495 IMPL_LINK_NOARG( OTableEditorCtrl
, DelayedInsNewRows
, void*, void )
1497 nInsNewRowsEvent
= nullptr;
1498 sal_Int32 nPastePosition
= GetView()->getController().getFirstEmptyRowPosition();
1499 if ( !GetView()->getController().getTable().is() )
1500 nPastePosition
= GetSelectRowCount() ? FirstSelectedRow() : m_nDataPos
;
1502 InsertNewRows( nPastePosition
);
1504 GoToRow( nPastePosition
);
1507 void OTableEditorCtrl::AdjustFieldDescription(OFieldDescription
* _pFieldDesc
,
1508 MultiSelection
& _rMultiSel
,
1513 _pFieldDesc
->SetPrimaryKey( _bPrimaryKey
);
1514 if(!_bSet
&& _pFieldDesc
->getTypeInfo()->bNullable
)
1516 _pFieldDesc
->SetIsNullable(ColumnValue::NO_NULLS
);
1517 _pFieldDesc
->SetControlDefault(Any());
1519 if ( _pFieldDesc
->IsAutoIncrement() && !_bPrimaryKey
)
1521 OTableController
& rController
= GetView()->getController();
1522 if ( rController
.isAutoIncrementPrimaryKey() )
1524 _pFieldDesc
->SetAutoIncrement(false);
1527 // update field description
1528 pDescrWin
->DisplayData(_pFieldDesc
);
1530 _rMultiSel
.Insert( _nPos
);
1531 _rMultiSel
.Select( _nPos
);
1534 void OTableEditorCtrl::SetPrimaryKey( bool bSet
)
1536 // Delete any existing Primary Keys
1537 MultiSelection aDeletedPrimKeys
;
1538 aDeletedPrimKeys
.SetTotalRange( Range(0,GetRowCount()) );
1541 for (auto const& row
: *m_pRowList
)
1543 OFieldDescription
* pFieldDescr
= row
->GetActFieldDescr();
1544 if( pFieldDescr
&& row
->IsPrimaryKey() && (!bSet
|| !IsRowSelected(nRow
)) )
1546 AdjustFieldDescription(pFieldDescr
,aDeletedPrimKeys
,nRow
,bSet
,false);
1551 // Set the primary keys of the marked rows
1552 MultiSelection aInsertedPrimKeys
;
1553 aInsertedPrimKeys
.SetTotalRange( Range(0,GetRowCount()) );
1556 tools::Long nIndex
= FirstSelectedRow();
1557 while( nIndex
!= SFX_ENDOFSELECTION
)
1560 std::shared_ptr
<OTableRow
> pRow
= (*m_pRowList
)[nIndex
];
1561 OFieldDescription
* pFieldDescr
= pRow
->GetActFieldDescr();
1563 AdjustFieldDescription(pFieldDescr
,aInsertedPrimKeys
,nIndex
,false,true);
1565 nIndex
= NextSelectedRow();
1569 GetUndoManager().AddUndoAction( std::make_unique
<OPrimKeyUndoAct
>(this, aDeletedPrimKeys
, aInsertedPrimKeys
) );
1571 // Invalidate the handle-columns
1572 InvalidateHandleColumn();
1574 // Set the TableDocSh's ModifyFlag
1575 GetView()->getController().setModified( true );
1576 InvalidateFeatures();
1579 bool OTableEditorCtrl::IsPrimaryKey()
1581 // Are all marked fields part of the Primary Key ?
1582 tools::Long nPrimaryKeys
= 0;
1584 for (auto const& row
: *m_pRowList
)
1586 if( IsRowSelected(nRow
) && !row
->IsPrimaryKey() )
1588 if( row
->IsPrimaryKey() )
1593 // Are there any unselected fields that are part of the Key ?
1594 return GetSelectRowCount() == nPrimaryKeys
;
1597 void OTableEditorCtrl::SwitchType( const TOTypeInfoSP
& _pType
)
1599 // if there is no assigned field name
1600 sal_Int32
nRow(GetCurRow());
1601 OFieldDescription
* pActFieldDescr
= GetFieldDescr( nRow
);
1602 if( pActFieldDescr
)
1603 // Store the old description
1604 pDescrWin
->SaveData( pActFieldDescr
);
1606 if ( nRow
< 0 || o3tl::make_unsigned(nRow
) > m_pRowList
->size() )
1608 // Show the new description
1609 std::shared_ptr
<OTableRow
> pRow
= (*m_pRowList
)[nRow
];
1610 pRow
->SetFieldType( _pType
, true );
1613 weld::ComboBox
& rTypeList
= pTypeCell
->get_widget();
1614 const sal_Int32 nCurrentlySelected
= rTypeList
.get_active();
1616 if ( ( nCurrentlySelected
== -1 )
1617 || ( GetView()->getController().getTypeInfo( nCurrentlySelected
) != _pType
)
1620 sal_Int32 nEntryPos
= 0;
1621 const OTypeInfoMap
& rTypeInfo
= GetView()->getController().getTypeInfo();
1622 for (auto const& elem
: rTypeInfo
)
1624 if(elem
.second
== _pType
)
1628 if (nEntryPos
< rTypeList
.get_count())
1629 rTypeList
.set_active(nEntryPos
);
1633 pActFieldDescr
= pRow
->GetActFieldDescr();
1634 if (pActFieldDescr
!= nullptr && !pActFieldDescr
->GetFormatKey())
1636 sal_Int32 nFormatKey
= ::dbtools::getDefaultNumberFormat( pActFieldDescr
->GetType(),
1637 pActFieldDescr
->GetScale(),
1638 pActFieldDescr
->IsCurrency(),
1639 Reference
< XNumberFormatTypes
>(GetView()->getController().getNumberFormatter()->getNumberFormatsSupplier()->getNumberFormats(),UNO_QUERY
),
1640 GetView()->getLocale());
1642 pActFieldDescr
->SetFormatKey(nFormatKey
);
1645 pDescrWin
->DisplayData( pActFieldDescr
);
1648 OTableDesignView
* OTableEditorCtrl::GetView() const
1653 void OTableEditorCtrl::DeactivateCell(bool bUpdate
)
1655 OTableRowView::DeactivateCell(bUpdate
);
1656 // now we have to deactivate the field description
1657 sal_Int32
nRow(GetCurRow());
1659 pDescrWin
->SetReadOnly(bReadOnly
|| !SetDataPtr(nRow
) || GetActRow()->IsReadOnly());
1662 bool OTableEditorCtrl::PreNotify( NotifyEvent
& rNEvt
)
1664 if (rNEvt
.GetType() == NotifyEventType::GETFOCUS
)
1666 if( pHelpTextCell
&& pHelpTextCell
->HasChildPathFocus() )
1667 m_eChildFocus
= HELPTEXT
;
1668 else if( pDescrCell
&& pDescrCell
->HasChildPathFocus() )
1669 m_eChildFocus
= DESCRIPTION
;
1670 else if(pNameCell
&& pNameCell
->HasChildPathFocus() )
1671 m_eChildFocus
= NAME
;
1673 m_eChildFocus
= ROW
;
1676 return OTableRowView::PreNotify(rNEvt
);
1679 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */