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 "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>
29 #include <helpids.h>
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 <sot/storage.hxx>
40 #include <svx/svxids.hrc>
41 #include <UITools.hxx>
42 #include "TableFieldControl.hxx"
43 #include <dsntypes.hxx>
44 #include <vcl/commandevent.hxx>
45 #include <vcl/svapp.hxx>
46
47 using namespace ::dbaui;
48 using namespace ::comphelper;
49 using namespace ::svt;
50 using namespace ::com::sun::star::uno;
51 using namespace ::com::sun::star::container;
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::lang;
56 using namespace ::com::sun::star::sdbc;
57 using namespace ::com::sun::star::sdbcx;
58 using namespace ::com::sun::star::sdb;
59
60
61 #define HANDLE_ID 0
62
63 // default field widths
64 #define FIELDNAME_WIDTH 100
65 #define FIELDTYPE_WIDTH 150
66 #define FIELDDESCR_WIDTH 300
67
68 // Maximum length in description field
69 #define MAX_DESCR_LEN 256
70
ClipboardInvalidator(OTableEditorCtrl * _pOwner)71 OTableEditorCtrl::ClipboardInvalidator::ClipboardInvalidator(OTableEditorCtrl* _pOwner)
72 : m_pOwner(_pOwner)
73 {
74
75 m_aInvalidateTimer.SetTimeout(500);
76 m_aInvalidateTimer.SetInvokeHandler(LINK(this, OTableEditorCtrl::ClipboardInvalidator, OnInvalidate));
77 m_aInvalidateTimer.Start();
78 }
79
~ClipboardInvalidator()80 OTableEditorCtrl::ClipboardInvalidator::~ClipboardInvalidator()
81 {
82 m_aInvalidateTimer.Stop();
83 }
84
Stop()85 void OTableEditorCtrl::ClipboardInvalidator::Stop()
86 {
87 m_aInvalidateTimer.Stop();
88 }
89
IMPL_LINK_NOARG(OTableEditorCtrl::ClipboardInvalidator,OnInvalidate,Timer *,void)90 IMPL_LINK_NOARG(OTableEditorCtrl::ClipboardInvalidator, OnInvalidate, Timer *, void)
91 {
92 m_pOwner->GetView()->getController().InvalidateFeature(SID_CUT);
93 m_pOwner->GetView()->getController().InvalidateFeature(SID_COPY);
94 m_pOwner->GetView()->getController().InvalidateFeature(SID_PASTE);
95 }
96
Init()97 void OTableEditorCtrl::Init()
98 {
99 OTableRowView::Init();
100
101 // Should it be opened ReadOnly?
102 bool bRead(GetView()->getController().isReadOnly());
103
104 SetReadOnly( bRead );
105
106 // Insert the columns
107 InsertDataColumn( FIELD_NAME, DBA_RES(STR_TAB_FIELD_COLUMN_NAME), FIELDNAME_WIDTH );
108
109 InsertDataColumn( FIELD_TYPE, DBA_RES(STR_TAB_FIELD_COLUMN_DATATYPE), FIELDTYPE_WIDTH );
110
111 ::dbaccess::ODsnTypeCollection aDsnTypes(GetView()->getController().getORB());
112 bool bShowColumnDescription = aDsnTypes.supportsColumnDescription(::comphelper::getString(GetView()->getController().getDataSource()->getPropertyValue(PROPERTY_URL)));
113 InsertDataColumn( HELP_TEXT, DBA_RES(STR_TAB_HELP_TEXT), bShowColumnDescription ? FIELDTYPE_WIDTH : FIELDDESCR_WIDTH );
114
115 if ( bShowColumnDescription )
116 {
117 InsertDataColumn( COLUMN_DESCRIPTION, DBA_RES(STR_COLUMN_DESCRIPTION), FIELDTYPE_WIDTH );
118 }
119
120 InitCellController();
121
122 // Insert the rows
123 RowInserted(0, m_pRowList->size());
124 }
125
OTableEditorCtrl(vcl::Window * pWindow,OTableDesignView * pView)126 OTableEditorCtrl::OTableEditorCtrl(vcl::Window* pWindow, OTableDesignView* pView)
127 :OTableRowView(pWindow)
128 ,m_pView(pView)
129 ,pNameCell(nullptr)
130 ,pTypeCell(nullptr)
131 ,pHelpTextCell(nullptr)
132 ,pDescrCell(nullptr)
133 ,pDescrWin(nullptr)
134 ,nCutEvent(nullptr)
135 ,nPasteEvent(nullptr)
136 ,nDeleteEvent(nullptr)
137 ,nInsNewRowsEvent(nullptr)
138 ,nInvalidateTypeEvent(nullptr)
139 ,m_eChildFocus(NONE)
140 ,nOldDataPos(-1)
141 ,bReadOnly(true)
142 ,m_aInvalidate(this)
143 {
144 SetHelpId(HID_TABDESIGN_BACKGROUND);
145 GetDataWindow().SetHelpId(HID_CTL_TABLEEDIT);
146
147 m_pRowList = &GetView()->getController().getRows();
148 m_nDataPos = 0;
149 }
150
GetUndoManager() const151 SfxUndoManager& OTableEditorCtrl::GetUndoManager() const
152 {
153 return GetView()->getController().GetUndoManager();
154 }
155
156
SetReadOnly(bool bRead)157 void OTableEditorCtrl::SetReadOnly( bool bRead )
158 {
159 // nothing to do?
160 if (bRead == IsReadOnly())
161 // This check is important, as the underlying Def may be unnecessarily locked or unlocked
162 // or worse, this action may not be reversed afterwards
163 return;
164
165 bReadOnly = bRead;
166
167 // Disable active cells
168 sal_Int32 nRow(GetCurRow());
169 sal_uInt16 nCol(GetCurColumnId());
170 DeactivateCell();
171
172 // Select the correct Browsers cursor
173 BrowserMode nMode(BrowserMode::COLUMNSELECTION | BrowserMode::MULTISELECTION | BrowserMode::KEEPHIGHLIGHT |
174 BrowserMode::HLINES | BrowserMode::VLINES|BrowserMode::AUTOSIZE_LASTCOL);
175 if( !bReadOnly )
176 nMode |= BrowserMode::HIDECURSOR;
177 SetMode(nMode);
178
179 if( !bReadOnly )
180 ActivateCell( nRow, nCol );
181 }
182
InitCellController()183 void OTableEditorCtrl::InitCellController()
184 {
185 // Cell Field name
186 sal_Int32 nMaxTextLen = 0;
187 OUString sExtraNameChars;
188 Reference<XConnection> xCon;
189 try
190 {
191 xCon = GetView()->getController().getConnection();
192 Reference< XDatabaseMetaData> xMetaData = xCon.is() ? xCon->getMetaData() : Reference< XDatabaseMetaData>();
193
194 // length 0 is treated by Entry::set_max_length as unlimited
195 nMaxTextLen = xMetaData.is() ? xMetaData->getMaxColumnNameLength() : 0;
196
197 sExtraNameChars = xMetaData.is() ? xMetaData->getExtraNameCharacters() : OUString();
198
199 }
200 catch(SQLException&)
201 {
202 OSL_FAIL("getMaxColumnNameLength");
203 }
204
205 pNameCell = VclPtr<OSQLNameEditControl>::Create(&GetDataWindow(), sExtraNameChars);
206 pNameCell->get_widget().set_max_length(nMaxTextLen);
207 pNameCell->setCheck( isSQL92CheckEnabled(xCon) );
208
209 // Cell type
210 pTypeCell = VclPtr<ListBoxControl>::Create( &GetDataWindow() );
211
212 // Cell description
213 pDescrCell = VclPtr<EditControl>::Create(&GetDataWindow());
214 pDescrCell->get_widget().set_max_length(MAX_DESCR_LEN);
215
216 pHelpTextCell = VclPtr<EditControl>::Create(&GetDataWindow());
217 pHelpTextCell->get_widget().set_max_length(MAX_DESCR_LEN);
218
219 pNameCell->SetHelpId(HID_TABDESIGN_NAMECELL);
220 pTypeCell->SetHelpId(HID_TABDESIGN_TYPECELL);
221 pDescrCell->SetHelpId(HID_TABDESIGN_COMMENTCELL);
222 pHelpTextCell->SetHelpId(HID_TABDESIGN_HELPTEXT);
223
224 Size aHeight;
225 const Control* pControls[] = { pTypeCell,pDescrCell,pNameCell,pHelpTextCell};
226 for(const Control* pControl : pControls)
227 {
228 const Size aTemp(pControl->GetOptimalSize());
229 if ( aTemp.Height() > aHeight.Height() )
230 aHeight.setHeight( aTemp.Height() );
231 }
232 SetDataRowHeight(aHeight.Height());
233
234 ClearModified();
235 }
236
ClearModified()237 void OTableEditorCtrl::ClearModified()
238 {
239 pNameCell->get_widget().save_value();
240 pDescrCell->get_widget().save_value();
241 pHelpTextCell->get_widget().save_value();
242 pTypeCell->get_widget().save_value();
243 }
244
~OTableEditorCtrl()245 OTableEditorCtrl::~OTableEditorCtrl()
246 {
247 disposeOnce();
248 }
249
dispose()250 void OTableEditorCtrl::dispose()
251 {
252 // Reset the Undo-Manager
253 GetUndoManager().Clear();
254
255 m_aInvalidate.Stop();
256
257 // Take possible Events from the queue
258 if( nCutEvent )
259 Application::RemoveUserEvent( nCutEvent );
260 if( nPasteEvent )
261 Application::RemoveUserEvent( nPasteEvent );
262 if( nDeleteEvent )
263 Application::RemoveUserEvent( nDeleteEvent );
264 if( nInsNewRowsEvent )
265 Application::RemoveUserEvent( nInsNewRowsEvent );
266 if( nInvalidateTypeEvent )
267 Application::RemoveUserEvent( nInvalidateTypeEvent );
268
269 // Delete the control types
270 pNameCell.disposeAndClear();
271 pTypeCell.disposeAndClear();
272 pDescrCell.disposeAndClear();
273 pHelpTextCell.disposeAndClear();
274 pDescrWin = nullptr;
275 m_pView.clear();
276 OTableRowView::dispose();
277 }
278
SetDataPtr(sal_Int32 nRow)279 bool OTableEditorCtrl::SetDataPtr( sal_Int32 nRow )
280 {
281 if(nRow == -1)
282 return false;
283
284 OSL_ENSURE(nRow < static_cast<tools::Long>(m_pRowList->size()),"Row is greater than size!");
285 if(nRow >= static_cast<tools::Long>(m_pRowList->size()))
286 return false;
287 pActRow = (*m_pRowList)[nRow];
288 return pActRow != nullptr;
289 }
290
SeekRow(sal_Int32 _nRow)291 bool OTableEditorCtrl::SeekRow(sal_Int32 _nRow)
292 {
293 // Call the Base class to remember which row must be repainted
294 EditBrowseBox::SeekRow(_nRow);
295
296 m_nCurrentPos = _nRow;
297 return SetDataPtr(_nRow);
298 }
299
PaintCell(OutputDevice & rDev,const tools::Rectangle & rRect,sal_uInt16 nColumnId) const300 void OTableEditorCtrl::PaintCell(OutputDevice& rDev, const tools::Rectangle& rRect,
301 sal_uInt16 nColumnId ) const
302 {
303 const OUString aText( GetCellText( m_nCurrentPos, nColumnId ));
304
305 rDev.Push( PushFlags::CLIPREGION );
306 rDev.SetClipRegion(vcl::Region(rRect));
307 rDev.DrawText( rRect, aText, DrawTextFlags::Left | DrawTextFlags::VCenter );
308 rDev.Pop();
309 }
310
GetController(sal_Int32 nRow,sal_uInt16 nColumnId)311 CellController* OTableEditorCtrl::GetController(sal_Int32 nRow, sal_uInt16 nColumnId)
312 {
313 // If EditorCtrl is ReadOnly, editing is forbidden
314 Reference<XPropertySet> xTable = GetView()->getController().getTable();
315 if (IsReadOnly() || ( xTable.is() &&
316 xTable->getPropertySetInfo()->hasPropertyByName(PROPERTY_TYPE) &&
317 ::comphelper::getString(xTable->getPropertyValue(PROPERTY_TYPE)) == "VIEW"))
318 return nullptr;
319
320 // If the row is ReadOnly, editing is forbidden
321 SetDataPtr( nRow );
322 if( pActRow->IsReadOnly() )
323 return nullptr;
324
325 OFieldDescription* pActFieldDescr = pActRow->GetActFieldDescr();
326 switch (nColumnId)
327 {
328 case FIELD_NAME:
329 return new EditCellController( pNameCell );
330 case FIELD_TYPE:
331 if (pActFieldDescr && !pActFieldDescr->GetName().isEmpty())
332 return new ListBoxCellController( pTypeCell );
333 else return nullptr;
334 case HELP_TEXT:
335 if (pActFieldDescr && !pActFieldDescr->GetName().isEmpty())
336 return new EditCellController( pHelpTextCell );
337 else
338 return nullptr;
339 case COLUMN_DESCRIPTION:
340 if (pActFieldDescr && !pActFieldDescr->GetName().isEmpty())
341 return new EditCellController( pDescrCell );
342 else
343 return nullptr;
344 default:
345 return nullptr;
346 }
347 }
348
InitController(CellControllerRef &,sal_Int32 nRow,sal_uInt16 nColumnId)349 void OTableEditorCtrl::InitController(CellControllerRef&, sal_Int32 nRow, sal_uInt16 nColumnId)
350 {
351 SeekRow( nRow == -1 ? GetCurRow() : nRow);
352 OFieldDescription* pActFieldDescr = pActRow->GetActFieldDescr();
353 OUString aInitString;
354
355 switch (nColumnId)
356 {
357 case FIELD_NAME:
358 {
359 if( pActFieldDescr )
360 aInitString = pActFieldDescr->GetName();
361
362 weld::Entry& rEntry = pNameCell->get_widget();
363 rEntry.set_text(aInitString);
364 rEntry.save_value();
365 break;
366 }
367 case FIELD_TYPE:
368 {
369 if ( pActFieldDescr && pActFieldDescr->getTypeInfo() )
370 aInitString = pActFieldDescr->getTypeInfo()->aUIName;
371
372 // Set the ComboBox contents
373 weld::ComboBox& rTypeList = pTypeCell->get_widget();
374 rTypeList.clear();
375 if( !pActFieldDescr )
376 break;
377
378 const OTypeInfoMap& rTypeInfo = GetView()->getController().getTypeInfo();
379 for (auto const& elem : rTypeInfo)
380 rTypeList.append_text(elem.second->aUIName);
381 rTypeList.set_active_text(aInitString);
382 }
383
384 break;
385 case HELP_TEXT:
386 {
387 if( pActFieldDescr )
388 aInitString = pActFieldDescr->GetHelpText();
389 weld::Entry& rEntry = pHelpTextCell->get_widget();
390 rEntry.set_text(aInitString);
391 rEntry.save_value();
392 break;
393 }
394 case COLUMN_DESCRIPTION:
395 {
396 if( pActFieldDescr )
397 aInitString = pActFieldDescr->GetDescription();
398 weld::Entry& rEntry = pDescrCell->get_widget();
399 rEntry.set_text(aInitString);
400 rEntry.save_value();
401 break;
402 }
403 }
404 }
405
GetRowStatus(sal_Int32 nRow) const406 EditBrowseBox::RowStatus OTableEditorCtrl::GetRowStatus(sal_Int32 nRow) const
407 {
408 const_cast<OTableEditorCtrl*>(this)->SetDataPtr( nRow );
409 if( !pActRow )
410 return EditBrowseBox::CLEAN;
411 if (nRow >= 0 && nRow == m_nDataPos)
412 {
413 if( pActRow->IsPrimaryKey() )
414 return EditBrowseBox::CURRENT_PRIMARYKEY;
415 return EditBrowseBox::CURRENT;
416 }
417 else
418 {
419 if( pActRow->IsPrimaryKey() )
420 return EditBrowseBox::PRIMARYKEY;
421 return EditBrowseBox::CLEAN;
422 }
423 }
424
SaveCurRow()425 void OTableEditorCtrl::SaveCurRow()
426 {
427 if (GetFieldDescr(GetCurRow()) == nullptr)
428 // there is no data in the current row
429 return;
430 if (!SaveModified())
431 return;
432
433 SetDataPtr(GetCurRow());
434 pDescrWin->SaveData( pActRow->GetActFieldDescr() );
435 }
436
DisplayData(sal_Int32 nRow)437 void OTableEditorCtrl::DisplayData(sal_Int32 nRow)
438 {
439 // go to the correct cell
440 SetDataPtr(nRow);
441
442 // Disable Edit-Mode temporarily
443 bool bWasEditing = IsEditing();
444 if (bWasEditing)
445 DeactivateCell();
446
447 CellControllerRef aTemp;
448 InitController(aTemp, nRow, FIELD_NAME);
449 InitController(aTemp, nRow, FIELD_TYPE);
450 InitController(aTemp, nRow, COLUMN_DESCRIPTION);
451 InitController(aTemp, nRow, HELP_TEXT);
452
453 GoToRow(nRow);
454 // Update the Description-Window
455 GetView()->GetDescWin()->DisplayData(GetFieldDescr(nRow));
456 // redraw the row
457 RowModified(nRow);
458
459 // and re-enable edit mode
460 ActivateCell(nRow, GetCurColumnId());
461 }
462
CursorMoved()463 void OTableEditorCtrl::CursorMoved()
464 {
465 // New line?
466 m_nDataPos = GetCurRow();
467 if( m_nDataPos != nOldDataPos && m_nDataPos != -1)
468 {
469 CellControllerRef aTemp;
470 InitController(aTemp,m_nDataPos,FIELD_NAME);
471 InitController(aTemp,m_nDataPos,FIELD_TYPE);
472 InitController(aTemp,m_nDataPos,COLUMN_DESCRIPTION);
473 InitController(aTemp,m_nDataPos,HELP_TEXT);
474 }
475
476 OTableRowView::CursorMoved();
477 }
478
HasFieldName(const OUString & rFieldName)479 sal_Int32 OTableEditorCtrl::HasFieldName( const OUString& rFieldName )
480 {
481
482 Reference<XConnection> xCon = GetView()->getController().getConnection();
483 Reference< XDatabaseMetaData> xMetaData = xCon.is() ? xCon->getMetaData() : Reference< XDatabaseMetaData>();
484
485 ::comphelper::UStringMixEqual bCase(!xMetaData.is() || xMetaData->supportsMixedCaseQuotedIdentifiers());
486
487 sal_Int32 nCount(0);
488 for (auto const& row : *m_pRowList)
489 {
490 OFieldDescription* pFieldDescr = row->GetActFieldDescr();
491 if( pFieldDescr && bCase(rFieldName,pFieldDescr->GetName()))
492 nCount++;
493 }
494 return nCount;
495 }
496
SaveData(sal_Int32 nRow,sal_uInt16 nColId)497 void OTableEditorCtrl::SaveData(sal_Int32 nRow, sal_uInt16 nColId)
498 {
499 // Store the cell content
500 SetDataPtr( nRow == -1 ? GetCurRow() : nRow);
501 OFieldDescription* pActFieldDescr = pActRow->GetActFieldDescr();
502
503 switch( nColId)
504 {
505 // Store NameCell
506 case FIELD_NAME:
507 {
508 // If there is no name, do nothing
509 weld::Entry& rEntry = pNameCell->get_widget();
510 const OUString aName(rEntry.get_text());
511
512 if( aName.isEmpty() )
513 {
514 // If FieldDescr exists, the field is deleted and the old content restored
515 if (pActFieldDescr)
516 {
517 GetUndoManager().AddUndoAction(std::make_unique<OTableEditorTypeSelUndoAct>(this, nRow, FIELD_TYPE, pActFieldDescr->getTypeInfo()));
518 SwitchType(TOTypeInfoSP());
519 pActFieldDescr = pActRow->GetActFieldDescr();
520 }
521 else
522 return;
523 }
524 if(pActFieldDescr)
525 pActFieldDescr->SetName( aName );
526 rEntry.save_value();
527
528 break;
529 }
530
531 // Store the field type
532 case FIELD_TYPE:
533 break;
534
535 // Store DescrCell
536 case HELP_TEXT:
537 {
538 // if the current field description is NULL, set Default
539 weld::Entry& rEntry = pHelpTextCell->get_widget();
540 if( !pActFieldDescr )
541 {
542 rEntry.set_text(OUString());
543 rEntry.save_value();
544 }
545 else
546 pActFieldDescr->SetHelpText(rEntry.get_text());
547 break;
548 }
549 case COLUMN_DESCRIPTION:
550 {
551 // Set the default if the field description is null
552 weld::Entry& rEntry = pDescrCell->get_widget();
553 if( !pActFieldDescr )
554 {
555 rEntry.set_text(OUString());
556 rEntry.save_value();
557 }
558 else
559 pActFieldDescr->SetDescription(rEntry.get_text());
560 break;
561 }
562 case FIELD_PROPERTY_DEFAULT:
563 case FIELD_PROPERTY_REQUIRED:
564 case FIELD_PROPERTY_TEXTLEN:
565 case FIELD_PROPERTY_NUMTYPE:
566 case FIELD_PROPERTY_AUTOINC:
567 case FIELD_PROPERTY_LENGTH:
568 case FIELD_PROPERTY_SCALE:
569 case FIELD_PROPERTY_BOOL_DEFAULT:
570 pDescrWin->SaveData(pActFieldDescr);
571
572 if ( FIELD_PROPERTY_AUTOINC == nColId && pActFieldDescr->IsAutoIncrement() )
573 {
574 OTableController& rController = GetView()->getController();
575 if ( rController.isAutoIncrementPrimaryKey() )
576 {
577 pActFieldDescr->SetPrimaryKey( true );
578 InvalidateHandleColumn();
579 Invalidate();
580 }
581 }
582 break;
583 }
584 }
585
SaveModified()586 bool OTableEditorCtrl::SaveModified()
587 {
588 sal_uInt16 nColId = GetCurColumnId();
589
590 switch( nColId )
591 {
592 // Field type
593 case FIELD_TYPE:
594 {
595 // Reset the type
596 resetType();
597 } break;
598 }
599
600 return true;
601 }
602
CursorMoving(sal_Int32 nNewRow,sal_uInt16 nNewCol)603 bool OTableEditorCtrl::CursorMoving(sal_Int32 nNewRow, sal_uInt16 nNewCol)
604 {
605
606 if (!EditBrowseBox::CursorMoving(nNewRow, nNewCol))
607 return false;
608
609 // Called after SaveModified(), current row is still the old one
610 m_nDataPos = nNewRow;
611 nOldDataPos = GetCurRow();
612
613 // Reset the markers
614 InvalidateStatusCell( nOldDataPos );
615 InvalidateStatusCell( m_nDataPos );
616
617 // Store the data from the Property window
618 if( SetDataPtr(nOldDataPos) && pDescrWin)
619 pDescrWin->SaveData( pActRow->GetActFieldDescr() );
620
621 // Show new data in the Property window
622 if( SetDataPtr(m_nDataPos) && pDescrWin)
623 pDescrWin->DisplayData( pActRow->GetActFieldDescr() );
624
625 return true;
626 }
627
IMPL_LINK_NOARG(OTableEditorCtrl,InvalidateFieldType,void *,void)628 IMPL_LINK_NOARG( OTableEditorCtrl, InvalidateFieldType, void*, void )
629 {
630 nInvalidateTypeEvent = nullptr;
631 Invalidate( GetFieldRectPixel(nOldDataPos, FIELD_TYPE) );
632 }
633
CellModified(sal_Int32 nRow,sal_uInt16 nColId)634 void OTableEditorCtrl::CellModified( sal_Int32 nRow, sal_uInt16 nColId )
635 {
636
637 // If the description is null, use the default
638 if(nRow == -1)
639 nRow = GetCurRow();
640 SetDataPtr( nRow );
641 OFieldDescription* pActFieldDescr = pActRow->GetActFieldDescr();
642
643 OUString sActionDescription;
644 switch ( nColId )
645 {
646 case FIELD_NAME: sActionDescription = DBA_RES( STR_CHANGE_COLUMN_NAME ); break;
647 case FIELD_TYPE: sActionDescription = DBA_RES( STR_CHANGE_COLUMN_TYPE ); break;
648 case HELP_TEXT:
649 case COLUMN_DESCRIPTION: sActionDescription = DBA_RES( STR_CHANGE_COLUMN_DESCRIPTION ); break;
650 default: sActionDescription = DBA_RES( STR_CHANGE_COLUMN_ATTRIBUTE ); break;
651 }
652
653 GetUndoManager().EnterListAction( sActionDescription, OUString(), 0, ViewShellId(-1) );
654 if (!pActFieldDescr)
655 {
656 const OTypeInfoMap& rTypeInfoMap = GetView()->getController().getTypeInfo();
657 if ( !rTypeInfoMap.empty() )
658 {
659 OTypeInfoMap::const_iterator aTypeIter = rTypeInfoMap.find(DataType::VARCHAR);
660 if ( aTypeIter == rTypeInfoMap.end() )
661 aTypeIter = rTypeInfoMap.begin();
662 pActRow->SetFieldType( aTypeIter->second );
663 }
664 else
665 pActRow->SetFieldType( GetView()->getController().getTypeInfoFallBack() );
666
667 nInvalidateTypeEvent = Application::PostUserEvent( LINK(this, OTableEditorCtrl, InvalidateFieldType), nullptr, true );
668 pActFieldDescr = pActRow->GetActFieldDescr();
669 pDescrWin->DisplayData( pActFieldDescr );
670 GetUndoManager().AddUndoAction( std::make_unique<OTableEditorTypeSelUndoAct>(this, nRow, nColId+1, TOTypeInfoSP()) );
671 }
672
673 if( nColId != FIELD_TYPE )
674 GetUndoManager().AddUndoAction( std::make_unique<OTableDesignCellUndoAct>(this, nRow, nColId) );
675 else
676 {
677 GetUndoManager().AddUndoAction(std::make_unique<OTableEditorTypeSelUndoAct>(this, GetCurRow(), nColId, GetFieldDescr(GetCurRow())->getTypeInfo()));
678 resetType();
679 }
680
681 SaveData(nRow,nColId);
682 // SaveData could create an undo action as well
683 GetUndoManager().LeaveListAction();
684 RowModified(nRow);
685
686 // Set the Modify flag
687 GetView()->getController().setModified( true );
688 InvalidateFeatures();
689 }
690
resetType()691 void OTableEditorCtrl::resetType()
692 {
693 sal_Int32 nPos = pTypeCell->get_widget().get_active();
694 if(nPos != -1)
695 SwitchType( GetView()->getController().getTypeInfo(nPos) );
696 else
697 SwitchType(TOTypeInfoSP());
698 }
699
CellModified()700 void OTableEditorCtrl::CellModified()
701 {
702 CellModified( GetCurRow(), GetCurColumnId() );
703 }
704
InvalidateFeatures()705 void OTableEditorCtrl::InvalidateFeatures()
706 {
707 GetView()->getController().InvalidateFeature(SID_UNDO);
708 GetView()->getController().InvalidateFeature(SID_REDO);
709 GetView()->getController().InvalidateFeature(SID_SAVEDOC);
710 }
711
CopyRows()712 void OTableEditorCtrl::CopyRows()
713 {
714 // set to the right row and save it
715 if( SetDataPtr(m_nDataPos) )
716 pDescrWin->SaveData( pActRow->GetActFieldDescr() );
717
718 // Copy selected rows to the ClipboardList
719 std::shared_ptr<OTableRow> pClipboardRow;
720 std::shared_ptr<OTableRow> pRow;
721 std::vector< std::shared_ptr<OTableRow> > vClipboardList;
722 vClipboardList.reserve(GetSelectRowCount());
723
724 for( tools::Long nIndex=FirstSelectedRow(); nIndex != SFX_ENDOFSELECTION; nIndex=NextSelectedRow() )
725 {
726 pRow = (*m_pRowList)[nIndex];
727 OSL_ENSURE(pRow,"OTableEditorCtrl::CopyRows: Row is NULL!");
728 if ( pRow && pRow->GetActFieldDescr() )
729 {
730 pClipboardRow = std::make_shared<OTableRow>( *pRow );
731 vClipboardList.push_back( pClipboardRow);
732 }
733 }
734 if(!vClipboardList.empty())
735 {
736 rtl::Reference<OTableRowExchange> pData = new OTableRowExchange(vClipboardList);
737 pData->CopyToClipboard(GetParent());
738 }
739 }
740
GenerateName(const OUString & rName)741 OUString OTableEditorCtrl::GenerateName( const OUString& rName )
742 {
743 // Create a base name for appending numbers to
744 OUString aBaseName;
745 Reference<XConnection> xCon = GetView()->getController().getConnection();
746 Reference< XDatabaseMetaData> xMetaData = xCon.is() ? xCon->getMetaData() : Reference< XDatabaseMetaData>();
747
748 sal_Int32 nMaxTextLen(xMetaData.is() ? xMetaData->getMaxColumnNameLength() : 0);
749
750 if( (rName.getLength()+2) >nMaxTextLen )
751 aBaseName = rName.copy( 0, nMaxTextLen-2 );
752 else
753 aBaseName = rName;
754
755 // append a sequential number to the base name (up to 99)
756 OUString aFieldName( rName);
757 sal_Int32 i=1;
758 while( HasFieldName(aFieldName) )
759 {
760 aFieldName = aBaseName + OUString::number(i);
761 i++;
762 }
763
764 return aFieldName;
765 }
766
InsertRows(sal_Int32 nRow)767 void OTableEditorCtrl::InsertRows( sal_Int32 nRow )
768 {
769
770 std::vector< std::shared_ptr<OTableRow> > vInsertedUndoRedoRows; // need for undo/redo handling
771 // get rows from clipboard
772 TransferableDataHelper aTransferData(TransferableDataHelper::CreateFromSystemClipboard(GetParent()));
773 if(aTransferData.HasFormat(SotClipboardFormatId::SBA_TABED))
774 {
775 ::tools::SvRef<SotTempStream> aStreamRef;
776 bool bOk = aTransferData.GetSotStorageStream(SotClipboardFormatId::SBA_TABED,aStreamRef);
777 if (bOk && aStreamRef.is())
778 {
779 aStreamRef->Seek(STREAM_SEEK_TO_BEGIN);
780 aStreamRef->ResetError();
781 sal_Int32 nInsertRow = nRow;
782 std::shared_ptr<OTableRow> pRow;
783 sal_Int32 nSize = 0;
784 (*aStreamRef).ReadInt32( nSize );
785 vInsertedUndoRedoRows.reserve(nSize);
786 for(sal_Int32 i=0;i < nSize;++i)
787 {
788 pRow = std::make_shared<OTableRow>();
789 ReadOTableRow( *aStreamRef, *pRow );
790 pRow->SetReadOnly( false );
791 sal_Int32 nType = pRow->GetActFieldDescr()->GetType();
792 if ( pRow->GetActFieldDescr() )
793 pRow->GetActFieldDescr()->SetType(GetView()->getController().getTypeInfoByType(nType));
794 // Adjust the field names
795 pRow->GetActFieldDescr()->SetName( GenerateName( pRow->GetActFieldDescr()->GetName() ) );
796 pRow->SetPos(nInsertRow);
797 m_pRowList->insert( m_pRowList->begin()+nInsertRow,pRow );
798 vInsertedUndoRedoRows.push_back(std::make_shared<OTableRow>(*pRow));
799 nInsertRow++;
800 }
801 }
802 }
803 // RowInserted calls CursorMoved.
804 // The UI data should not be stored here.
805 RowInserted( nRow,vInsertedUndoRedoRows.size() );
806
807 // Create the Undo-Action
808 GetUndoManager().AddUndoAction( std::make_unique<OTableEditorInsUndoAct>(this, nRow,vInsertedUndoRedoRows) );
809 GetView()->getController().setModified( true );
810 InvalidateFeatures();
811 }
812
DeleteRows()813 void OTableEditorCtrl::DeleteRows()
814 {
815 OSL_ENSURE(GetView()->getController().isDropAllowed(),"Call of DeleteRows not valid here. Please check isDropAllowed!");
816 // Create the Undo-Action
817 GetUndoManager().AddUndoAction( std::make_unique<OTableEditorDelUndoAct>(this) );
818
819 // Delete all marked rows
820 tools::Long nIndex = FirstSelectedRow();
821 nOldDataPos = nIndex;
822
823 while( nIndex != SFX_ENDOFSELECTION )
824 {
825 // Remove rows
826 m_pRowList->erase( m_pRowList->begin()+nIndex );
827 RowRemoved( nIndex );
828
829 // Insert the empty row at the end
830 m_pRowList->push_back( std::make_shared<OTableRow>());
831 RowInserted( GetRowCount()-1 );
832
833 nIndex = FirstSelectedRow();
834 }
835
836 // Force the current record to be displayed
837 m_nDataPos = GetCurRow();
838 InvalidateStatusCell( nOldDataPos );
839 InvalidateStatusCell( m_nDataPos );
840 SetDataPtr( m_nDataPos );
841 ActivateCell();
842 pDescrWin->DisplayData( pActRow->GetActFieldDescr() );
843 GetView()->getController().setModified( true );
844 InvalidateFeatures();
845 }
846
InsertNewRows(sal_Int32 nRow)847 void OTableEditorCtrl::InsertNewRows( sal_Int32 nRow )
848 {
849 OSL_ENSURE(GetView()->getController().isAddAllowed(),"Call of InsertNewRows not valid here. Please check isAppendAllowed!");
850 // Create Undo-Action
851 sal_Int32 nInsertRows = GetSelectRowCount();
852 if( !nInsertRows )
853 nInsertRows = 1;
854 GetUndoManager().AddUndoAction( std::make_unique<OTableEditorInsNewUndoAct>(this, nRow, nInsertRows) );
855 // Insert the number of selected rows
856 for( tools::Long i=nRow; i<(nRow+nInsertRows); i++ )
857 m_pRowList->insert( m_pRowList->begin()+i ,std::make_shared<OTableRow>());
858 RowInserted( nRow, nInsertRows );
859
860 GetView()->getController().setModified( true );
861 InvalidateFeatures();
862 }
863
SetControlText(sal_Int32 nRow,sal_uInt16 nColId,const OUString & rText)864 void OTableEditorCtrl::SetControlText( sal_Int32 nRow, sal_uInt16 nColId, const OUString& rText )
865 {
866 // Set the Browser Controls
867 if( nColId < FIELD_FIRST_VIRTUAL_COLUMN )
868 {
869 GoToRow( nRow );
870 GoToColumnId( nColId );
871 CellControllerRef xController = Controller();
872 if(xController.is())
873 xController->GetWindow().SetText( rText );
874 else
875 RowModified(nRow,nColId);
876 }
877
878 // Set the Tabpage controls
879 else
880 {
881 pDescrWin->SetControlText( nColId, rText );
882 }
883 }
884
SetCellData(sal_Int32 nRow,sal_uInt16 nColId,const TOTypeInfoSP & _pTypeInfo)885 void OTableEditorCtrl::SetCellData( sal_Int32 nRow, sal_uInt16 nColId, const TOTypeInfoSP& _pTypeInfo )
886 {
887 // Relocate the current pointer
888 if( nRow == -1 )
889 nRow = GetCurRow();
890 OFieldDescription* pFieldDescr = GetFieldDescr( nRow );
891 if( !pFieldDescr && nColId != FIELD_TYPE)
892 return;
893
894 // Set individual fields
895 switch( nColId )
896 {
897 case FIELD_TYPE:
898 SwitchType( _pTypeInfo );
899 break;
900 default:
901 OSL_FAIL("OTableEditorCtrl::SetCellData: invalid column!");
902 }
903 SetControlText(nRow,nColId,_pTypeInfo ? _pTypeInfo->aUIName : OUString());
904 }
905
SetCellData(sal_Int32 nRow,sal_uInt16 nColId,const css::uno::Any & _rNewData)906 void OTableEditorCtrl::SetCellData( sal_Int32 nRow, sal_uInt16 nColId, const css::uno::Any& _rNewData )
907 {
908 // Relocate the current pointer
909 if( nRow == -1 )
910 nRow = GetCurRow();
911 OFieldDescription* pFieldDescr = GetFieldDescr( nRow );
912 if( !pFieldDescr && nColId != FIELD_TYPE)
913 return;
914
915 OUString sValue;
916 // Set individual fields
917 switch( nColId )
918 {
919 case FIELD_NAME:
920 sValue = ::comphelper::getString(_rNewData);
921 pFieldDescr->SetName( sValue );
922 break;
923
924 case FIELD_TYPE:
925 OSL_FAIL("OTableEditorCtrl::SetCellData: invalid column!");
926 break;
927
928 case COLUMN_DESCRIPTION:
929 sValue = ::comphelper::getString(_rNewData);
930 pFieldDescr->SetDescription( sValue );
931 break;
932
933 case FIELD_PROPERTY_DEFAULT:
934 pFieldDescr->SetControlDefault( _rNewData );
935 sValue = GetView()->GetDescWin()->getGenPage()->getControlDefault(pFieldDescr);
936 break;
937
938 case FIELD_PROPERTY_REQUIRED:
939 {
940 sValue = ::comphelper::getString(_rNewData);
941 pFieldDescr->SetIsNullable( sValue.toInt32() );
942 }
943 break;
944
945 case FIELD_PROPERTY_TEXTLEN:
946 case FIELD_PROPERTY_LENGTH:
947 {
948 sValue = ::comphelper::getString(_rNewData);
949 pFieldDescr->SetPrecision( sValue.toInt32() );
950 }
951 break;
952
953 case FIELD_PROPERTY_NUMTYPE:
954 OSL_FAIL("OTableEditorCtrl::SetCellData: invalid column!");
955 break;
956
957 case FIELD_PROPERTY_AUTOINC:
958 {
959 sValue = ::comphelper::getString(_rNewData);
960 pFieldDescr->SetAutoIncrement(sValue == DBA_RES(STR_VALUE_YES));
961 }
962 break;
963 case FIELD_PROPERTY_SCALE:
964 {
965 sValue = ::comphelper::getString(_rNewData);
966 pFieldDescr->SetScale(sValue.toInt32());
967 }
968 break;
969
970 case FIELD_PROPERTY_BOOL_DEFAULT:
971 sValue = GetView()->GetDescWin()->BoolStringPersistent(::comphelper::getString(_rNewData));
972 pFieldDescr->SetControlDefault(makeAny(sValue));
973 break;
974
975 case FIELD_PROPERTY_FORMAT:
976 {
977 sValue = ::comphelper::getString(_rNewData);
978 pFieldDescr->SetFormatKey(sValue.toInt32());
979 }
980 break;
981 }
982
983 SetControlText(nRow,nColId,sValue);
984 }
985
GetCellData(sal_Int32 nRow,sal_uInt16 nColId)986 Any OTableEditorCtrl::GetCellData( sal_Int32 nRow, sal_uInt16 nColId )
987 {
988 OFieldDescription* pFieldDescr = GetFieldDescr( nRow );
989 if( !pFieldDescr )
990 return Any();
991
992 // Relocate the current pointer
993 if( nRow==-1 )
994 nRow = GetCurRow();
995 SetDataPtr( nRow );
996
997 static const OUString strYes(DBA_RES(STR_VALUE_YES));
998 static const OUString strNo(DBA_RES(STR_VALUE_NO));
999 OUString sValue;
1000 // Read out the fields
1001 switch( nColId )
1002 {
1003 case FIELD_NAME:
1004 sValue = pFieldDescr->GetName();
1005 break;
1006
1007 case FIELD_TYPE:
1008 if ( pFieldDescr->getTypeInfo() )
1009 sValue = pFieldDescr->getTypeInfo()->aUIName;
1010 break;
1011
1012 case COLUMN_DESCRIPTION:
1013 sValue = pFieldDescr->GetDescription();
1014 break;
1015 case HELP_TEXT:
1016 sValue = pFieldDescr->GetHelpText();
1017 break;
1018
1019 case FIELD_PROPERTY_DEFAULT:
1020 return pFieldDescr->GetControlDefault();
1021
1022 case FIELD_PROPERTY_REQUIRED:
1023 sValue = pFieldDescr->GetIsNullable() == ColumnValue::NULLABLE ? strYes : strNo;
1024 break;
1025
1026 case FIELD_PROPERTY_TEXTLEN:
1027 case FIELD_PROPERTY_LENGTH:
1028 sValue = OUString::number(pFieldDescr->GetPrecision());
1029 break;
1030
1031 case FIELD_PROPERTY_NUMTYPE:
1032 OSL_FAIL("OTableEditorCtrl::GetCellData: invalid column!");
1033 break;
1034
1035 case FIELD_PROPERTY_AUTOINC:
1036 sValue = pFieldDescr->IsAutoIncrement() ? strYes : strNo;
1037 break;
1038
1039 case FIELD_PROPERTY_SCALE:
1040 sValue = OUString::number(pFieldDescr->GetScale());
1041 break;
1042
1043 case FIELD_PROPERTY_BOOL_DEFAULT:
1044 sValue = GetView()->GetDescWin()->BoolStringUI(::comphelper::getString(pFieldDescr->GetControlDefault()));
1045 break;
1046
1047 case FIELD_PROPERTY_FORMAT:
1048 sValue = OUString::number(pFieldDescr->GetFormatKey());
1049 break;
1050 }
1051
1052 return makeAny(sValue);
1053 }
1054
GetCellText(sal_Int32 nRow,sal_uInt16 nColId) const1055 OUString OTableEditorCtrl::GetCellText( sal_Int32 nRow, sal_uInt16 nColId ) const
1056 {
1057 OUString sCellText;
1058 const_cast< OTableEditorCtrl* >( this )->GetCellData( nRow, nColId ) >>= sCellText;
1059 return sCellText;
1060 }
1061
GetTotalCellWidth(sal_Int32 nRow,sal_uInt16 nColId)1062 sal_uInt32 OTableEditorCtrl::GetTotalCellWidth(sal_Int32 nRow, sal_uInt16 nColId)
1063 {
1064 return GetTextWidth(GetCellText(nRow, nColId)) + 2 * GetTextWidth("0");
1065 }
1066
GetFieldDescr(sal_Int32 nRow)1067 OFieldDescription* OTableEditorCtrl::GetFieldDescr( sal_Int32 nRow )
1068 {
1069 std::vector< std::shared_ptr<OTableRow> >::size_type nListCount(
1070 m_pRowList->size());
1071 if( (nRow<0) || (sal::static_int_cast< unsigned long >(nRow)>=nListCount) )
1072 {
1073 OSL_FAIL("(nRow<0) || (nRow>=nListCount)");
1074 return nullptr;
1075 }
1076 std::shared_ptr<OTableRow> pRow = (*m_pRowList)[ nRow ];
1077 if( !pRow )
1078 return nullptr;
1079 return pRow->GetActFieldDescr();
1080 }
1081
IsCutAllowed()1082 bool OTableEditorCtrl::IsCutAllowed()
1083 {
1084 bool bIsCutAllowed = (GetView()->getController().isAddAllowed() && GetView()->getController().isDropAllowed()) ||
1085 GetView()->getController().isAlterAllowed();
1086
1087 if (bIsCutAllowed)
1088 {
1089 int nStartPos, nEndPos;
1090 switch(m_eChildFocus)
1091 {
1092 case DESCRIPTION:
1093 {
1094 weld::Entry& rEntry = pDescrCell->get_widget();
1095 bIsCutAllowed = rEntry.get_selection_bounds(nStartPos, nEndPos);
1096 break;
1097 }
1098 case HELPTEXT:
1099 {
1100 weld::Entry& rEntry = pHelpTextCell->get_widget();
1101 bIsCutAllowed = rEntry.get_selection_bounds(nStartPos, nEndPos);
1102 break;
1103 }
1104 case NAME:
1105 {
1106 weld::Entry& rEntry = pNameCell->get_widget();
1107 bIsCutAllowed = rEntry.get_selection_bounds(nStartPos, nEndPos);
1108 break;
1109 }
1110 case ROW:
1111 bIsCutAllowed = IsCopyAllowed();
1112 break;
1113 default:
1114 bIsCutAllowed = false;
1115 break;
1116 }
1117 }
1118
1119 return bIsCutAllowed;
1120 }
1121
IsCopyAllowed()1122 bool OTableEditorCtrl::IsCopyAllowed()
1123 {
1124 bool bIsCopyAllowed = false;
1125 int nStartPos, nEndPos;
1126 if (m_eChildFocus == DESCRIPTION )
1127 {
1128 weld::Entry& rEntry = pDescrCell->get_widget();
1129 bIsCopyAllowed = rEntry.get_selection_bounds(nStartPos, nEndPos);
1130 }
1131 else if(HELPTEXT == m_eChildFocus )
1132 {
1133 weld::Entry& rEntry = pHelpTextCell->get_widget();
1134 bIsCopyAllowed = rEntry.get_selection_bounds(nStartPos, nEndPos);
1135 }
1136 else if(m_eChildFocus == NAME)
1137 {
1138 weld::Entry& rEntry = pNameCell->get_widget();
1139 bIsCopyAllowed = rEntry.get_selection_bounds(nStartPos, nEndPos);
1140 }
1141 else if(m_eChildFocus == ROW)
1142 {
1143 Reference<XPropertySet> xTable = GetView()->getController().getTable();
1144 if( !GetSelectRowCount() || (xTable.is() && ::comphelper::getString(xTable->getPropertyValue(PROPERTY_TYPE)) == "VIEW"))
1145 return false;
1146
1147 // If one of the selected rows is empty, Copy is not possible
1148 std::shared_ptr<OTableRow> pRow;
1149 tools::Long nIndex = FirstSelectedRow();
1150 while( nIndex != SFX_ENDOFSELECTION )
1151 {
1152 pRow = (*m_pRowList)[nIndex];
1153 if( !pRow->GetActFieldDescr() )
1154 return false;
1155
1156 nIndex = NextSelectedRow();
1157 }
1158
1159 bIsCopyAllowed = true;
1160 }
1161
1162 return bIsCopyAllowed;
1163 }
1164
IsPasteAllowed() const1165 bool OTableEditorCtrl::IsPasteAllowed() const
1166 {
1167 bool bAllowed = GetView()->getController().isAddAllowed();
1168 if ( bAllowed )
1169 {
1170 TransferableDataHelper aTransferData(TransferableDataHelper::CreateFromSystemClipboard(GetParent()));
1171 bool bRowFormat = aTransferData.HasFormat(SotClipboardFormatId::SBA_TABED);
1172 if ( m_eChildFocus == ROW )
1173 bAllowed = bRowFormat;
1174 else
1175 bAllowed = !bRowFormat && aTransferData.HasFormat(SotClipboardFormatId::STRING);
1176 }
1177
1178 return bAllowed;
1179 }
1180
cut()1181 void OTableEditorCtrl::cut()
1182 {
1183 if(m_eChildFocus == NAME)
1184 {
1185 if(GetView()->getController().isAlterAllowed())
1186 {
1187 SaveData(-1,FIELD_NAME);
1188 pNameCell->get_widget().cut_clipboard();
1189 CellModified(-1,FIELD_NAME);
1190 }
1191 }
1192 else if(m_eChildFocus == DESCRIPTION)
1193 {
1194 if(GetView()->getController().isAlterAllowed())
1195 {
1196 SaveData(-1,COLUMN_DESCRIPTION);
1197 pDescrCell->get_widget().cut_clipboard();
1198 CellModified(-1,COLUMN_DESCRIPTION);
1199 }
1200 }
1201 else if(HELPTEXT == m_eChildFocus )
1202 {
1203 if(GetView()->getController().isAlterAllowed())
1204 {
1205 SaveData(-1,HELP_TEXT);
1206 pHelpTextCell->get_widget().cut_clipboard();
1207 CellModified(-1,HELP_TEXT);
1208 }
1209 }
1210 else if(m_eChildFocus == ROW)
1211 {
1212 if (nCutEvent)
1213 Application::RemoveUserEvent(nCutEvent);
1214 nCutEvent = Application::PostUserEvent(LINK(this, OTableEditorCtrl, DelayedCut), nullptr, true);
1215 }
1216 }
1217
copy()1218 void OTableEditorCtrl::copy()
1219 {
1220 if (GetSelectRowCount())
1221 OTableRowView::copy();
1222 else if(m_eChildFocus == NAME)
1223 {
1224 weld::Entry& rEntry = pNameCell->get_widget();
1225 rEntry.copy_clipboard();
1226 }
1227 else if(HELPTEXT == m_eChildFocus )
1228 {
1229 weld::Entry& rEntry = pHelpTextCell->get_widget();
1230 rEntry.copy_clipboard();
1231 }
1232 else if(m_eChildFocus == DESCRIPTION )
1233 {
1234 weld::Entry& rEntry = pDescrCell->get_widget();
1235 rEntry.copy_clipboard();
1236 }
1237 }
1238
paste()1239 void OTableEditorCtrl::paste()
1240 {
1241 TransferableDataHelper aTransferData(TransferableDataHelper::CreateFromSystemClipboard(GetParent()));
1242 if(aTransferData.HasFormat(SotClipboardFormatId::SBA_TABED))
1243 {
1244 if( nPasteEvent )
1245 Application::RemoveUserEvent( nPasteEvent );
1246 nPasteEvent = Application::PostUserEvent( LINK(this, OTableEditorCtrl, DelayedPaste), nullptr, true );
1247 }
1248 else if(m_eChildFocus == NAME)
1249 {
1250 if(GetView()->getController().isAlterAllowed())
1251 {
1252 pNameCell->get_widget().paste_clipboard();
1253 CellModified();
1254 }
1255 }
1256 else if(HELPTEXT == m_eChildFocus )
1257 {
1258 if(GetView()->getController().isAlterAllowed())
1259 {
1260 pHelpTextCell->get_widget().paste_clipboard();
1261 CellModified();
1262 }
1263 }
1264 else if(m_eChildFocus == DESCRIPTION)
1265 {
1266 if(GetView()->getController().isAlterAllowed())
1267 {
1268 pDescrCell->get_widget().paste_clipboard();
1269 CellModified();
1270 }
1271 }
1272 }
1273
IsDeleteAllowed()1274 bool OTableEditorCtrl::IsDeleteAllowed()
1275 {
1276
1277 return GetSelectRowCount() != 0 && GetView()->getController().isDropAllowed();
1278 }
1279
IsInsertNewAllowed(sal_Int32 nRow)1280 bool OTableEditorCtrl::IsInsertNewAllowed( sal_Int32 nRow )
1281 {
1282
1283 bool bInsertNewAllowed = GetView()->getController().isAddAllowed();
1284 // If fields can be added, Paste in the new fields
1285 if (bInsertNewAllowed && !GetView()->getController().isDropAllowed())
1286 {
1287 SetDataPtr(nRow);
1288 if( GetActRow()->IsReadOnly() )
1289 return false;
1290 }
1291
1292 return bInsertNewAllowed;
1293 }
1294
IsPrimaryKeyAllowed()1295 bool OTableEditorCtrl::IsPrimaryKeyAllowed()
1296 {
1297 if( !GetSelectRowCount() )
1298 return false;
1299
1300 OTableController& rController = GetView()->getController();
1301 if ( !rController.getSdbMetaData().supportsPrimaryKeys() )
1302 return false;
1303
1304 Reference<XPropertySet> xTable = rController.getTable();
1305 // Key must not be changed
1306 // This applies only if the table is not new and not a css::sdbcx::View. Otherwise no DROP is executed
1307
1308 if(xTable.is() && ::comphelper::getString(xTable->getPropertyValue(PROPERTY_TYPE)) == "VIEW")
1309 return false;
1310 // If there is an empty field, no primary key
1311 // The entry is only permitted if
1312 // - there are no empty entries in the selection
1313 // - No Memo or Image entries
1314 // - DROP is not permitted (see above) and the column is not Required (not null flag is not set).
1315 tools::Long nIndex = FirstSelectedRow();
1316 std::shared_ptr<OTableRow> pRow;
1317 while( nIndex != SFX_ENDOFSELECTION )
1318 {
1319 pRow = (*m_pRowList)[nIndex];
1320 OFieldDescription* pFieldDescr = pRow->GetActFieldDescr();
1321 if(!pFieldDescr)
1322 return false;
1323 else
1324 {
1325 // Memo and Image fields cannot be primary keys
1326 // or if the column cannot be dropped and the Required flag is not set
1327 // or if a css::sdbcx::View is available and the Required flag is not set
1328 const TOTypeInfoSP& pTypeInfo = pFieldDescr->getTypeInfo();
1329 if( pTypeInfo->nSearchType == ColumnSearch::NONE
1330 || (pFieldDescr->IsNullable() && pRow->IsReadOnly())
1331 )
1332 return false;
1333 }
1334
1335 nIndex = NextSelectedRow();
1336 }
1337
1338 return true;
1339 }
1340
Command(const CommandEvent & rEvt)1341 void OTableEditorCtrl::Command(const CommandEvent& rEvt)
1342 {
1343 switch (rEvt.GetCommand())
1344 {
1345 case CommandEventId::ContextMenu:
1346 {
1347 Point aMenuPos( rEvt.GetMousePosPixel() );
1348 if (!rEvt.IsMouseEvent())
1349 {
1350 if ( 1 == GetSelectColumnCount() )
1351 {
1352 sal_uInt16 nSelId = GetColumnId(
1353 sal::static_int_cast< sal_uInt16 >(
1354 FirstSelectedColumn() ) );
1355 ::tools::Rectangle aColRect( GetFieldRectPixel( 0, nSelId, false ) );
1356
1357 aMenuPos = aColRect.TopCenter();
1358 }
1359 else if ( GetSelectRowCount() > 0 )
1360 {
1361 ::tools::Rectangle aColRect( GetFieldRectPixel( FirstSelectedRow(), HANDLE_ID ) );
1362
1363 aMenuPos = aColRect.TopCenter();
1364 }
1365 else
1366 {
1367 OTableRowView::Command(rEvt);
1368 return;
1369 }
1370 }
1371
1372 // Show the Context menu
1373 if( !IsReadOnly() )
1374 {
1375 sal_uInt16 nColId = GetColumnId(GetColumnAtXPosPixel(aMenuPos.X()));
1376 sal_Int32 nRow = GetRowAtYPosPixel(aMenuPos.Y());
1377
1378 if ( HANDLE_ID != nColId )
1379 {
1380 if ( nRow < 0 && nColId != BROWSER_INVALIDID )
1381 { // hit the header
1382 if ( 3 != nColId )
1383 { // 3 would mean the last column, and this last column is auto-sized
1384 if ( !IsColumnSelected( nColId ) )
1385 SelectColumnId( nColId );
1386
1387 ::tools::Rectangle aRect(aMenuPos, Size(1, 1));
1388 weld::Window* pPopupParent = weld::GetPopupParent(*this, aRect);
1389 std::unique_ptr<weld::Builder> xBuilder(Application::CreateBuilder(pPopupParent, "dbaccess/ui/querycolmenu.ui"));
1390 std::unique_ptr<weld::Menu> xContextMenu(xBuilder->weld_menu("menu"));
1391 xContextMenu->remove("delete");
1392 xContextMenu->remove("separator");
1393 if (xContextMenu->popup_at_rect(pPopupParent, aRect) == "width")
1394 adjustBrowseBoxColumnWidth( this, nColId );
1395 }
1396 }
1397 }
1398 else
1399 {
1400 ::tools::Rectangle aRect(aMenuPos, Size(1, 1));
1401 weld::Window* pPopupParent = weld::GetPopupParent(*this, aRect);
1402 std::unique_ptr<weld::Builder> xBuilder(Application::CreateBuilder(pPopupParent, "dbaccess/ui/tabledesignrowmenu.ui"));
1403 std::unique_ptr<weld::Menu> xContextMenu(xBuilder->weld_menu("menu"));
1404
1405 if (!IsCutAllowed())
1406 xContextMenu->remove("cut");
1407 if (!IsCopyAllowed())
1408 xContextMenu->remove("copy");
1409 if (!IsPasteAllowed())
1410 xContextMenu->remove("paste");
1411 if (!IsDeleteAllowed())
1412 xContextMenu->remove("delete");
1413 if (!IsPrimaryKeyAllowed())
1414 xContextMenu->remove("primarykey");
1415 if (!IsInsertNewAllowed(nRow))
1416 xContextMenu->remove("insert");
1417 xContextMenu->set_active("primarykey", IsRowSelected(GetCurRow()) && IsPrimaryKey());
1418
1419 if( SetDataPtr(m_nDataPos) )
1420 pDescrWin->SaveData( pActRow->GetActFieldDescr() );
1421
1422 // All actions which change the number of rows must be run asynchronously
1423 // otherwise there may be problems between the Context menu and the Browser
1424 m_nDataPos = GetCurRow();
1425 OString sIdent = xContextMenu->popup_at_rect(pPopupParent, aRect);
1426 if (sIdent == "cut")
1427 cut();
1428 else if (sIdent == "copy")
1429 copy();
1430 else if (sIdent == "paste")
1431 paste();
1432 else if (sIdent == "delete")
1433 {
1434 if( nDeleteEvent )
1435 Application::RemoveUserEvent( nDeleteEvent );
1436 nDeleteEvent = Application::PostUserEvent( LINK(this, OTableEditorCtrl, DelayedDelete), nullptr, true );
1437 }
1438 else if (sIdent == "insert")
1439 {
1440 if( nInsNewRowsEvent )
1441 Application::RemoveUserEvent( nInsNewRowsEvent );
1442 nInsNewRowsEvent = Application::PostUserEvent( LINK(this, OTableEditorCtrl, DelayedInsNewRows), nullptr, true );
1443 }
1444 else if (sIdent == "primarykey")
1445 {
1446 SetPrimaryKey( !IsPrimaryKey() );
1447 }
1448 }
1449 }
1450 }
1451 break;
1452 default:
1453 OTableRowView::Command(rEvt);
1454 }
1455
1456 }
1457
IMPL_LINK_NOARG(OTableEditorCtrl,DelayedCut,void *,void)1458 IMPL_LINK_NOARG( OTableEditorCtrl, DelayedCut, void*, void )
1459 {
1460 nCutEvent = nullptr;
1461 OTableRowView::cut();
1462 }
1463
IMPL_LINK_NOARG(OTableEditorCtrl,DelayedPaste,void *,void)1464 IMPL_LINK_NOARG( OTableEditorCtrl, DelayedPaste, void*, void )
1465 {
1466 nPasteEvent = nullptr;
1467
1468 sal_Int32 nPastePosition = GetView()->getController().getFirstEmptyRowPosition();
1469 if ( !GetView()->getController().getTable().is() )
1470 nPastePosition = GetSelectRowCount() ? FirstSelectedRow() : GetCurRow();
1471
1472 if (!IsInsertNewAllowed(nPastePosition))
1473 { // Insertion is not allowed, only appending, so test if there are full cells after the PastePosition
1474
1475 auto aIter = std::find_if(m_pRowList->rbegin(), m_pRowList->rend(), [](const std::shared_ptr<OTableRow>& rxRow) {
1476 return rxRow && rxRow->GetActFieldDescr() && !rxRow->GetActFieldDescr()->GetName().isEmpty(); });
1477 auto nFreeFromPos = static_cast<sal_Int32>(std::distance(aIter, m_pRowList->rend())); // from here on there are only empty rows
1478 if (nPastePosition < nFreeFromPos) // if at least one PastePosition is full, go right to the end
1479 nPastePosition = nFreeFromPos;
1480 }
1481
1482 OTableRowView::Paste( nPastePosition );
1483 SetNoSelection();
1484 GoToRow( nPastePosition );
1485 }
1486
IMPL_LINK_NOARG(OTableEditorCtrl,DelayedDelete,void *,void)1487 IMPL_LINK_NOARG( OTableEditorCtrl, DelayedDelete, void*, void )
1488 {
1489 nDeleteEvent = nullptr;
1490 DeleteRows();
1491 }
1492
IMPL_LINK_NOARG(OTableEditorCtrl,DelayedInsNewRows,void *,void)1493 IMPL_LINK_NOARG( OTableEditorCtrl, DelayedInsNewRows, void*, void )
1494 {
1495 nInsNewRowsEvent = nullptr;
1496 sal_Int32 nPastePosition = GetView()->getController().getFirstEmptyRowPosition();
1497 if ( !GetView()->getController().getTable().is() )
1498 nPastePosition = GetSelectRowCount() ? FirstSelectedRow() : m_nDataPos;
1499
1500 InsertNewRows( nPastePosition );
1501 SetNoSelection();
1502 GoToRow( nPastePosition );
1503 }
1504
AdjustFieldDescription(OFieldDescription * _pFieldDesc,MultiSelection & _rMultiSel,sal_Int32 _nPos,bool _bSet,bool _bPrimaryKey)1505 void OTableEditorCtrl::AdjustFieldDescription(OFieldDescription* _pFieldDesc,
1506 MultiSelection& _rMultiSel,
1507 sal_Int32 _nPos,
1508 bool _bSet,
1509 bool _bPrimaryKey)
1510 {
1511 _pFieldDesc->SetPrimaryKey( _bPrimaryKey );
1512 if(!_bSet && _pFieldDesc->getTypeInfo()->bNullable)
1513 {
1514 _pFieldDesc->SetIsNullable(ColumnValue::NO_NULLS);
1515 _pFieldDesc->SetControlDefault(Any());
1516 }
1517 if ( _pFieldDesc->IsAutoIncrement() && !_bPrimaryKey )
1518 {
1519 OTableController& rController = GetView()->getController();
1520 if ( rController.isAutoIncrementPrimaryKey() )
1521 {
1522 _pFieldDesc->SetAutoIncrement(false);
1523 }
1524 }
1525 // update field description
1526 pDescrWin->DisplayData(_pFieldDesc);
1527
1528 _rMultiSel.Insert( _nPos );
1529 _rMultiSel.Select( _nPos );
1530 }
1531
SetPrimaryKey(bool bSet)1532 void OTableEditorCtrl::SetPrimaryKey( bool bSet )
1533 {
1534 // Delete any existing Primary Keys
1535 MultiSelection aDeletedPrimKeys;
1536 aDeletedPrimKeys.SetTotalRange( Range(0,GetRowCount()) );
1537
1538 sal_Int32 nRow = 0;
1539 for (auto const& row : *m_pRowList)
1540 {
1541 OFieldDescription* pFieldDescr = row->GetActFieldDescr();
1542 if( pFieldDescr && row->IsPrimaryKey() && (!bSet || !IsRowSelected(nRow)) )
1543 {
1544 AdjustFieldDescription(pFieldDescr,aDeletedPrimKeys,nRow,bSet,false);
1545 }
1546 ++nRow;
1547 }
1548
1549 // Set the primary keys of the marked rows
1550 MultiSelection aInsertedPrimKeys;
1551 aInsertedPrimKeys.SetTotalRange( Range(0,GetRowCount()) );
1552 if( bSet )
1553 {
1554 tools::Long nIndex = FirstSelectedRow();
1555 while( nIndex != SFX_ENDOFSELECTION )
1556 {
1557 // Set the key
1558 std::shared_ptr<OTableRow> pRow = (*m_pRowList)[nIndex];
1559 OFieldDescription* pFieldDescr = pRow->GetActFieldDescr();
1560 if(pFieldDescr)
1561 AdjustFieldDescription(pFieldDescr,aInsertedPrimKeys,nIndex,false,true);
1562
1563 nIndex = NextSelectedRow();
1564 }
1565 }
1566
1567 GetUndoManager().AddUndoAction( std::make_unique<OPrimKeyUndoAct>(this, aDeletedPrimKeys, aInsertedPrimKeys) );
1568
1569 // Invalidate the handle-columns
1570 InvalidateHandleColumn();
1571
1572 // Set the TableDocSh's ModifyFlag
1573 GetView()->getController().setModified( true );
1574 InvalidateFeatures();
1575 }
1576
IsPrimaryKey()1577 bool OTableEditorCtrl::IsPrimaryKey()
1578 {
1579 // Are all marked fields part of the Primary Key ?
1580 tools::Long nPrimaryKeys = 0;
1581 sal_Int32 nRow=0;
1582 for (auto const& row : *m_pRowList)
1583 {
1584 if( IsRowSelected(nRow) && !row->IsPrimaryKey() )
1585 return false;
1586 if( row->IsPrimaryKey() )
1587 ++nPrimaryKeys;
1588 ++nRow;
1589 }
1590
1591 // Are there any unselected fields that are part of the Key ?
1592 return GetSelectRowCount() == nPrimaryKeys;
1593 }
1594
SwitchType(const TOTypeInfoSP & _pType)1595 void OTableEditorCtrl::SwitchType( const TOTypeInfoSP& _pType )
1596 {
1597 // if there is no assigned field name
1598 sal_Int32 nRow(GetCurRow());
1599 OFieldDescription* pActFieldDescr = GetFieldDescr( nRow );
1600 if( pActFieldDescr )
1601 // Store the old description
1602 pDescrWin->SaveData( pActFieldDescr );
1603
1604 if ( nRow < 0 || nRow > static_cast<tools::Long>(m_pRowList->size()) )
1605 return;
1606 // Show the new description
1607 std::shared_ptr<OTableRow> pRow = (*m_pRowList)[nRow];
1608 pRow->SetFieldType( _pType, true );
1609 if ( _pType )
1610 {
1611 weld::ComboBox& rTypeList = pTypeCell->get_widget();
1612 const sal_Int32 nCurrentlySelected = rTypeList.get_active();
1613
1614 if ( ( nCurrentlySelected == -1 )
1615 || ( GetView()->getController().getTypeInfo( nCurrentlySelected ) != _pType )
1616 )
1617 {
1618 sal_Int32 nEntryPos = 0;
1619 const OTypeInfoMap& rTypeInfo = GetView()->getController().getTypeInfo();
1620 for (auto const& elem : rTypeInfo)
1621 {
1622 if(elem.second == _pType)
1623 break;
1624 ++nEntryPos;
1625 }
1626 if (nEntryPos < rTypeList.get_count())
1627 rTypeList.set_active(nEntryPos);
1628 }
1629 }
1630
1631 pActFieldDescr = pRow->GetActFieldDescr();
1632 if (pActFieldDescr != nullptr && !pActFieldDescr->GetFormatKey())
1633 {
1634 sal_Int32 nFormatKey = ::dbtools::getDefaultNumberFormat( pActFieldDescr->GetType(),
1635 pActFieldDescr->GetScale(),
1636 pActFieldDescr->IsCurrency(),
1637 Reference< XNumberFormatTypes>(GetView()->getController().getNumberFormatter()->getNumberFormatsSupplier()->getNumberFormats(),UNO_QUERY),
1638 GetView()->getLocale());
1639
1640 pActFieldDescr->SetFormatKey(nFormatKey);
1641 }
1642
1643 pDescrWin->DisplayData( pActFieldDescr );
1644 }
1645
GetView() const1646 OTableDesignView* OTableEditorCtrl::GetView() const
1647 {
1648 return m_pView;
1649 }
1650
DeactivateCell(bool bUpdate)1651 void OTableEditorCtrl::DeactivateCell(bool bUpdate)
1652 {
1653 OTableRowView::DeactivateCell(bUpdate);
1654 // now we have to deactivate the field description
1655 sal_Int32 nRow(GetCurRow());
1656 if (pDescrWin)
1657 pDescrWin->SetReadOnly(bReadOnly || !SetDataPtr(nRow) || GetActRow()->IsReadOnly());
1658 }
1659
PreNotify(NotifyEvent & rNEvt)1660 bool OTableEditorCtrl::PreNotify( NotifyEvent& rNEvt )
1661 {
1662 if (rNEvt.GetType() == MouseNotifyEvent::GETFOCUS)
1663 {
1664 if( pHelpTextCell && pHelpTextCell->HasChildPathFocus() )
1665 m_eChildFocus = HELPTEXT;
1666 else if( pDescrCell && pDescrCell->HasChildPathFocus() )
1667 m_eChildFocus = DESCRIPTION;
1668 else if(pNameCell && pNameCell->HasChildPathFocus() )
1669 m_eChildFocus = NAME;
1670 else
1671 m_eChildFocus = ROW;
1672 }
1673
1674 return OTableRowView::PreNotify(rNEvt);
1675 }
1676
1677 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
1678