Extended loplugin:ostr manual changes
[LibreOffice.git] / dbaccess / source / ui / querydesign / SelectionBrowseBox.cxx
blob4653c0e6174b8224252335ca98e7627bc905f436
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
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 <sal/config.h>
22 #include <string_view>
24 #include "SelectionBrowseBox.hxx"
25 #include <com/sun/star/sdbc/XDatabaseMetaData.hpp>
26 #include <com/sun/star/sdbc/DataType.hpp>
27 #include <JoinExchange.hxx>
28 #include <QueryDesignView.hxx>
29 #include <querycontroller.hxx>
30 #include <sqlbison.hxx>
31 #include <QueryTableView.hxx>
32 #include <browserids.hxx>
33 #include <comphelper/stl_types.hxx>
34 #include <comphelper/string.hxx>
35 #include "TableFieldInfo.hxx"
36 #include <core_resource.hxx>
37 #include <strings.hrc>
38 #include <strings.hxx>
39 #include <helpids.h>
40 #include "QTableWindow.hxx"
41 #include <vcl/weld.hxx>
42 #include <vcl/settings.hxx>
43 #include "QueryDesignFieldUndoAct.hxx"
44 #include <sqlmessage.hxx>
45 #include <UITools.hxx>
46 #include <o3tl/safeint.hxx>
47 #include <osl/diagnose.h>
48 #include <i18nlangtag/languagetag.hxx>
49 #include <vcl/commandevent.hxx>
50 #include <vcl/svapp.hxx>
51 #include <comphelper/diagnose_ex.hxx>
52 #include <o3tl/string_view.hxx>
54 using namespace ::svt;
55 using namespace ::dbaui;
56 using namespace ::connectivity;
57 using namespace ::com::sun::star::uno;
58 using namespace ::com::sun::star::sdbc;
59 using namespace ::com::sun::star::beans;
60 using namespace ::com::sun::star::accessibility;
62 #define DEFAULT_QUERY_COLS 20
63 #define DEFAULT_SIZE GetTextWidth(u"0"_ustr) * 30
64 #define HANDLE_ID 0
65 #define HANDLE_COLUMN_WIDTH 70
66 #define SORT_COLUMN_NONE 0xFFFFFFFF
68 namespace
70 bool isFieldNameAsterisk(std::u16string_view _sFieldName )
72 bool bAsterisk = _sFieldName.empty() || _sFieldName[0] == '*';
73 if ( !bAsterisk )
75 sal_Int32 nTokenCount = comphelper::string::getTokenCount(_sFieldName, '.');
76 if ( (nTokenCount == 2 && o3tl::getToken(_sFieldName,1,'.')[0] == '*' )
77 || (nTokenCount == 3 && o3tl::getToken(_sFieldName,2,'.')[0] == '*' ) )
79 bAsterisk = true;
82 return bAsterisk;
84 bool lcl_SupportsCoreSQLGrammar(const Reference< XConnection>& _xConnection)
86 bool bSupportsCoreGrammar = false;
87 if ( _xConnection.is() )
89 try
91 Reference< XDatabaseMetaData > xMetaData = _xConnection->getMetaData();
92 bSupportsCoreGrammar = xMetaData.is() && xMetaData->supportsCoreSQLGrammar();
94 catch(Exception&)
98 return bSupportsCoreGrammar;
102 OSelectionBrowseBox::OSelectionBrowseBox( vcl::Window* pParent )
103 :EditBrowseBox( pParent,EditBrowseBoxFlags::NO_HANDLE_COLUMN_CONTENT, WB_3DLOOK, BrowserMode::COLUMNSELECTION | BrowserMode::KEEPHIGHLIGHT | BrowserMode::HIDESELECT |
104 BrowserMode::HIDECURSOR | BrowserMode::HLINES | BrowserMode::VLINES )
105 ,m_timerInvalidate("dbaccess OSelectionBrowseBox m_timerInvalidate")
106 ,m_nSeekRow(0)
107 ,m_nMaxColumns(0)
108 ,m_aFunctionStrings(DBA_RES(STR_QUERY_FUNCTIONS))
109 ,m_nVisibleCount(0)
110 ,m_nLastSortColumn(SORT_COLUMN_NONE)
111 ,m_bOrderByUnRelated(true)
112 ,m_bGroupByUnRelated(true)
113 ,m_bStopTimer(false)
114 ,m_bWasEditing(false)
115 ,m_bDisableErrorBox(false)
116 ,m_bInUndoMode(false)
118 SetHelpId(HID_CTL_QRYDGNCRIT);
120 m_nMode = BrowserMode::COLUMNSELECTION | BrowserMode::HIDESELECT
121 | BrowserMode::KEEPHIGHLIGHT | BrowserMode::HIDECURSOR
122 | BrowserMode::HLINES | BrowserMode::VLINES
123 | BrowserMode::HEADERBAR_NEW ;
125 m_pTextCell = VclPtr<EditControl>::Create(&GetDataWindow());
126 m_pVisibleCell = VclPtr<CheckBoxControl>::Create(&GetDataWindow());
127 m_pTableCell = VclPtr<ListBoxControl>::Create(&GetDataWindow());
128 m_pFieldCell = VclPtr<ComboBoxControl>::Create(&GetDataWindow());
129 m_pOrderCell = VclPtr<ListBoxControl>::Create(&GetDataWindow());
130 m_pFunctionCell = VclPtr<ListBoxControl>::Create(&GetDataWindow());
132 m_pVisibleCell->SetHelpId(HID_QRYDGN_ROW_VISIBLE);
133 m_pTableCell->SetHelpId(HID_QRYDGN_ROW_TABLE);
134 m_pFieldCell->SetHelpId(HID_QRYDGN_ROW_FIELD);
135 weld::ComboBox& rOrderBox = m_pOrderCell->get_widget();
136 m_pOrderCell->SetHelpId(HID_QRYDGN_ROW_ORDER);
137 m_pFunctionCell->SetHelpId(HID_QRYDGN_ROW_FUNCTION);
139 // switch off triState of css::form::CheckBox
140 m_pVisibleCell->EnableTriState( false );
142 vcl::Font aTitleFont = OutputDevice::GetDefaultFont( DefaultFontType::SANS_UNICODE,Window::GetSettings().GetLanguageTag().getLanguageType(),GetDefaultFontFlags::OnlyOne);
143 aTitleFont.SetFontSize(Size(0, 6));
144 SetTitleFont(aTitleFont);
146 const OUString aTxt(DBA_RES(STR_QUERY_SORTTEXT));
147 for (sal_Int32 nIdx {0}; nIdx>=0;)
148 rOrderBox.append_text(OUString(o3tl::getToken(aTxt, 0, ';', nIdx)));
150 m_bVisibleRow.insert(m_bVisibleRow.end(), BROW_ROW_CNT, true);
152 m_bVisibleRow[BROW_FUNCTION_ROW] = false; // first hide
154 m_timerInvalidate.SetTimeout(200);
155 m_timerInvalidate.SetInvokeHandler(LINK(this, OSelectionBrowseBox, OnInvalidateTimer));
156 m_timerInvalidate.Start();
159 OSelectionBrowseBox::~OSelectionBrowseBox()
161 disposeOnce();
164 void OSelectionBrowseBox::dispose()
166 m_pTextCell.disposeAndClear();
167 m_pVisibleCell.disposeAndClear();
168 m_pFieldCell.disposeAndClear();
169 m_pTableCell.disposeAndClear();
170 m_pOrderCell.disposeAndClear();
171 m_pFunctionCell.disposeAndClear();
172 ::svt::EditBrowseBox::dispose();
175 void OSelectionBrowseBox::initialize()
177 Reference< XConnection> xConnection = static_cast<OQueryController&>(getDesignView()->getController()).getConnection();
178 if(xConnection.is())
180 const IParseContext& rContext = static_cast<OQueryController&>(getDesignView()->getController()).getParser().getContext();
181 const IParseContext::InternationalKeyCode eFunctions[] = {
182 IParseContext::InternationalKeyCode::Avg,IParseContext::InternationalKeyCode::Count,IParseContext::InternationalKeyCode::Max
183 ,IParseContext::InternationalKeyCode::Min,IParseContext::InternationalKeyCode::Sum
184 ,IParseContext::InternationalKeyCode::Every
185 ,IParseContext::InternationalKeyCode::Any
186 ,IParseContext::InternationalKeyCode::Some
187 ,IParseContext::InternationalKeyCode::StdDevPop
188 ,IParseContext::InternationalKeyCode::StdDevSamp
189 ,IParseContext::InternationalKeyCode::VarSamp
190 ,IParseContext::InternationalKeyCode::VarPop
191 ,IParseContext::InternationalKeyCode::Collect
192 ,IParseContext::InternationalKeyCode::Fusion
193 ,IParseContext::InternationalKeyCode::Intersection
196 OUString sGroup = m_aFunctionStrings.copy(m_aFunctionStrings.lastIndexOf(';')+1);
197 m_aFunctionStrings = m_aFunctionStrings.getToken(0, ';');
199 for (IParseContext::InternationalKeyCode eFunction : eFunctions)
201 m_aFunctionStrings += ";" + OStringToOUString(rContext.getIntlKeywordAscii(eFunction), RTL_TEXTENCODING_UTF8);
203 m_aFunctionStrings += ";" + sGroup;
205 // Aggregate functions in general available only with Core SQL
206 // We slip in a few optionals one, too.
207 if ( lcl_SupportsCoreSQLGrammar(xConnection) )
209 weld::ComboBox& rComboBox = m_pFunctionCell->get_widget();
210 for (sal_Int32 nIdx {0}; nIdx>=0;)
211 rComboBox.append_text(m_aFunctionStrings.getToken(0, ';', nIdx));
213 else // else only COUNT(*) and COUNT("table".*)
215 weld::ComboBox& rComboBox = m_pFunctionCell->get_widget();
216 rComboBox.append_text(m_aFunctionStrings.getToken(0, ';'));
217 rComboBox.append_text(m_aFunctionStrings.getToken(2, ';')); // 2 -> COUNT
221 Reference< XDatabaseMetaData > xMetaData = xConnection->getMetaData();
222 if ( xMetaData.is() )
224 m_bOrderByUnRelated = xMetaData->supportsOrderByUnrelated();
225 m_bGroupByUnRelated = xMetaData->supportsGroupByUnrelated();
228 catch(Exception&)
233 Init();
236 OQueryDesignView* OSelectionBrowseBox::getDesignView()
238 OSL_ENSURE(static_cast<const OQueryDesignView*>(GetParent()),"Parent isn't an OQueryDesignView!");
239 return static_cast<OQueryDesignView*>(GetParent());
242 OQueryDesignView* OSelectionBrowseBox::getDesignView() const
244 OSL_ENSURE(static_cast<const OQueryDesignView*>(GetParent()),"Parent isn't an OQueryDesignView!");
245 return static_cast<OQueryDesignView*>(GetParent());
248 namespace
250 class OSelectionBrwBoxHeader : public ::svt::EditBrowserHeader
252 VclPtr<OSelectionBrowseBox> m_pBrowseBox;
253 protected:
254 virtual void Select() override;
255 public:
256 explicit OSelectionBrwBoxHeader(OSelectionBrowseBox* pParent);
257 virtual ~OSelectionBrwBoxHeader() override { disposeOnce(); }
258 virtual void dispose() override { m_pBrowseBox.clear(); ::svt::EditBrowserHeader::dispose(); }
260 OSelectionBrwBoxHeader::OSelectionBrwBoxHeader(OSelectionBrowseBox* pParent)
261 : ::svt::EditBrowserHeader(pParent,WB_BUTTONSTYLE|WB_DRAG)
262 ,m_pBrowseBox(pParent)
266 void OSelectionBrwBoxHeader::Select()
268 EditBrowserHeader::Select();
269 m_pBrowseBox->GrabFocus();
271 BrowserMode nMode = m_pBrowseBox->GetMode();
272 if ( 0 == m_pBrowseBox->GetSelectColumnCount() )
274 m_pBrowseBox->DeactivateCell();
275 // we are in the right mode if a row has been selected row
276 if ( nMode & BrowserMode::HIDESELECT )
278 nMode &= ~BrowserMode::HIDESELECT;
279 nMode |= BrowserMode::MULTISELECTION;
280 m_pBrowseBox->SetMode( nMode );
283 m_pBrowseBox->SelectColumnId( GetCurItemId() );
284 m_pBrowseBox->DeactivateCell();
288 VclPtr<BrowserHeader> OSelectionBrowseBox::imp_CreateHeaderBar(BrowseBox* /*pParent*/)
290 return VclPtr<OSelectionBrwBoxHeader>::Create(this);
293 void OSelectionBrowseBox::ColumnMoved( sal_uInt16 nColId, bool _bCreateUndo )
295 EditBrowseBox::ColumnMoved( nColId );
296 // swap the two columns
297 sal_uInt16 nNewPos = GetColumnPos( nColId );
298 OTableFields& rFields = getFields();
299 if ( rFields.size() > o3tl::make_unsigned(nNewPos-1) )
301 sal_uInt16 nOldPos = 0;
302 bool bFoundElem = false;
303 for (auto const& field : rFields)
305 if (field->GetColumnId() == nColId)
307 bFoundElem = true;
308 break;
310 ++nOldPos;
313 OSL_ENSURE( (nNewPos-1) != nOldPos && nOldPos < rFields.size(),"Old and new position are equal!");
314 if (bFoundElem)
316 OTableFieldDescRef pOldEntry = rFields[nOldPos];
317 rFields.erase(rFields.begin() + nOldPos);
318 rFields.insert(rFields.begin() + nNewPos - 1,pOldEntry);
320 // create the undo action
321 if ( !m_bInUndoMode && _bCreateUndo )
323 std::unique_ptr<OTabFieldMovedUndoAct> pUndoAct(new OTabFieldMovedUndoAct(this));
324 pUndoAct->SetColumnPosition( nOldPos + 1);
325 pUndoAct->SetTabFieldDescr(pOldEntry);
327 getDesignView()->getController().addUndoActionAndInvalidate(std::move(pUndoAct));
331 else
332 OSL_FAIL("Invalid column id!");
335 void OSelectionBrowseBox::Init()
338 EditBrowseBox::Init();
340 // set the header bar
341 VclPtr<BrowserHeader> pNewHeaderBar = CreateHeaderBar(this);
342 pNewHeaderBar->SetMouseTransparent(false);
344 SetHeaderBar(pNewHeaderBar);
345 SetMode(m_nMode);
347 vcl::Font aFont( GetDataWindow().GetFont() );
348 aFont.SetWeight( WEIGHT_NORMAL );
349 GetDataWindow().SetFont( aFont );
351 Size aHeight;
352 const Control* pControls[] = { m_pTextCell,m_pVisibleCell,m_pTableCell,m_pFieldCell };
354 for (const Control* pControl : pControls)
356 const Size aTemp(pControl->GetOptimalSize());
357 if ( aTemp.Height() > aHeight.Height() )
358 aHeight.setHeight( aTemp.Height() );
360 SetDataRowHeight(aHeight.Height());
361 SetTitleLines(1);
362 // get number of visible rows
363 for(tools::Long i=0;i<BROW_ROW_CNT;i++)
365 if(m_bVisibleRow[i])
366 m_nVisibleCount++;
368 RowInserted(0, m_nVisibleCount, false);
371 Reference< XConnection> xConnection = static_cast<OQueryController&>(getDesignView()->getController()).getConnection();
372 if(xConnection.is())
374 Reference< XDatabaseMetaData > xMetaData = xConnection->getMetaData();
375 m_nMaxColumns = xMetaData.is() ? xMetaData->getMaxColumnsInSelect() : 0;
378 else
379 m_nMaxColumns = 0;
381 catch(const SQLException&)
383 TOOLS_WARN_EXCEPTION( "dbaccess", "Caught Exception when asking for database metadata options!");
384 m_nMaxColumns = 0;
388 void OSelectionBrowseBox::PreFill()
390 SetUpdateMode(false);
392 if (GetCurRow() != 0)
393 GoToRow(0);
395 static_cast< OQueryController& >( getDesignView()->getController() ).clearFields();
397 DeactivateCell();
399 RemoveColumns();
400 InsertHandleColumn( HANDLE_COLUMN_WIDTH );
401 SetUpdateMode(true);
404 void OSelectionBrowseBox::ClearAll()
406 SetUpdateMode(false);
408 OTableFields::const_reverse_iterator aIter = getFields().rbegin();
409 for ( ;aIter != getFields().rend(); ++aIter )
411 if ( !(*aIter)->IsEmpty() )
413 RemoveField( (*aIter)->GetColumnId() );
414 aIter = getFields().rbegin();
417 m_nLastSortColumn = SORT_COLUMN_NONE;
418 SetUpdateMode(true);
421 void OSelectionBrowseBox::SetReadOnly(bool bRO)
423 if (bRO)
425 DeactivateCell();
426 m_nMode &= ~BrowserMode::HIDECURSOR;
427 SetMode(m_nMode);
429 else
431 m_nMode |= BrowserMode::HIDECURSOR;
432 SetMode(m_nMode);
433 ActivateCell();
437 CellController* OSelectionBrowseBox::GetController(sal_Int32 nRow, sal_uInt16 nColId)
439 if ( nColId > getFields().size() )
440 return nullptr;
441 OTableFieldDescRef pEntry = getFields()[nColId-1];
442 OSL_ENSURE(pEntry.is(), "OSelectionBrowseBox::GetController : invalid FieldDescription !");
444 if (!pEntry.is())
445 return nullptr;
447 if (static_cast<OQueryController&>(getDesignView()->getController()).isReadOnly())
448 return nullptr;
450 sal_Int32 nCellIndex = GetRealRow(nRow);
451 switch (nCellIndex)
453 case BROW_FIELD_ROW:
454 return new ComboBoxCellController(m_pFieldCell);
455 case BROW_TABLE_ROW:
456 return new ListBoxCellController(m_pTableCell);
457 case BROW_VIS_ROW:
458 return new CheckBoxCellController(m_pVisibleCell);
459 case BROW_ORDER_ROW:
460 return new ListBoxCellController(m_pOrderCell);
461 case BROW_FUNCTION_ROW:
462 return new ListBoxCellController(m_pFunctionCell);
463 default:
464 return new EditCellController(m_pTextCell);
468 void OSelectionBrowseBox::InitController(CellControllerRef& /*rController*/, sal_Int32 nRow, sal_uInt16 nColId)
470 OSL_ENSURE(nColId != BROWSER_INVALIDID,"An Invalid Id was set!");
471 if ( nColId == BROWSER_INVALIDID )
472 return;
473 sal_uInt16 nPos = GetColumnPos(nColId);
474 if ( nPos == 0 || nPos == BROWSER_INVALIDID || nPos > getFields().size() )
475 return;
476 OTableFieldDescRef pEntry = getFields()[nPos-1];
477 OSL_ENSURE(pEntry.is(), "OSelectionBrowseBox::InitController : invalid FieldDescription !");
478 sal_Int32 nCellIndex = GetRealRow(nRow);
480 switch (nCellIndex)
482 case BROW_FIELD_ROW:
484 weld::ComboBox& rComboBox = m_pFieldCell->get_widget();
485 rComboBox.clear();
486 rComboBox.set_entry_text(OUString());
488 OUString aField(pEntry->GetField());
489 OUString aTable(pEntry->GetAlias());
491 getDesignView()->fillValidFields(aTable, rComboBox);
493 // replace with alias.*
494 if (o3tl::trim(aField) == u"*")
496 aField = aTable + ".*";
498 rComboBox.set_entry_text(aField);
499 } break;
500 case BROW_TABLE_ROW:
502 weld::ComboBox& rComboBox = m_pTableCell->get_widget();
503 rComboBox.clear();
504 enableControl(pEntry, m_pTableCell);
505 if ( !pEntry->isCondition() )
507 for (auto const& tabWin : getDesignView()->getTableView()->GetTabWinMap())
508 rComboBox.append_text(static_cast<OQueryTableWindow*>(tabWin.second.get())->GetAliasName());
510 rComboBox.insert_text(0, DBA_RES(STR_QUERY_NOTABLE));
511 if (!pEntry->GetAlias().isEmpty())
512 rComboBox.set_active_text(pEntry->GetAlias());
513 else
514 rComboBox.set_active_text(DBA_RES(STR_QUERY_NOTABLE));
516 } break;
517 case BROW_VIS_ROW:
519 m_pVisibleCell->GetBox().set_active(pEntry->IsVisible());
520 m_pVisibleCell->GetBox().save_state();
522 enableControl(pEntry,m_pTextCell);
524 if(!pEntry->IsVisible() && pEntry->GetOrderDir() != ORDER_NONE && !m_bOrderByUnRelated)
526 // a column has to visible in order to show up in ORDER BY
527 pEntry->SetVisible();
528 m_pVisibleCell->GetBox().set_active(pEntry->IsVisible());
529 m_pVisibleCell->GetBox().save_state();
530 m_pVisibleCell->GetBox().set_sensitive(false);
531 OUString aMessage(DBA_RES(STR_QRY_ORDERBY_UNRELATED));
532 OQueryDesignView* paDView = getDesignView();
533 std::unique_ptr<weld::MessageDialog> xInfoBox(Application::CreateMessageDialog(paDView ? paDView->GetFrameWeld() : nullptr,
534 VclMessageType::Info, VclButtonsType::Ok,
535 aMessage));
536 xInfoBox->run();
538 } break;
539 case BROW_ORDER_ROW:
541 weld::ComboBox& rComboBox = m_pOrderCell->get_widget();
542 rComboBox.set_active(
543 sal::static_int_cast< sal_uInt16 >(pEntry->GetOrderDir()));
544 enableControl(pEntry,m_pOrderCell);
545 break;
547 case BROW_COLUMNALIAS_ROW:
548 setTextCellContext(pEntry,pEntry->GetFieldAlias(),HID_QRYDGN_ROW_ALIAS);
549 break;
550 case BROW_FUNCTION_ROW:
551 setFunctionCell(pEntry);
552 break;
553 default:
555 sal_uInt16 nIdx = sal_uInt16(nCellIndex - BROW_CRIT1_ROW);
556 setTextCellContext(pEntry,pEntry->GetCriteria( nIdx ),HID_QRYDGN_ROW_CRIT);
559 Controller()->SaveValue();
562 void OSelectionBrowseBox::notifyTableFieldChanged(const OUString& _sOldAlias, std::u16string_view _sAlias, bool& _bListAction, sal_uInt16 _nColumnId)
564 appendUndoAction(_sOldAlias,_sAlias,BROW_TABLE_ROW,_bListAction);
565 if ( m_bVisibleRow[BROW_TABLE_ROW] )
566 RowModified(GetBrowseRow(BROW_TABLE_ROW), _nColumnId);
569 void OSelectionBrowseBox::notifyFunctionFieldChanged(const OUString& _sOldFunctionName, std::u16string_view _sFunctionName, bool& _bListAction, sal_uInt16 _nColumnId)
571 appendUndoAction(_sOldFunctionName,_sFunctionName,BROW_FUNCTION_ROW,_bListAction);
572 if ( !m_bVisibleRow[BROW_FUNCTION_ROW] )
573 SetRowVisible(BROW_FUNCTION_ROW, true);
574 RowModified(GetBrowseRow(BROW_FUNCTION_ROW), _nColumnId);
577 void OSelectionBrowseBox::clearEntryFunctionField(std::u16string_view _sFieldName,OTableFieldDescRef const & _pEntry, bool& _bListAction,sal_uInt16 _nColumnId)
579 if ( !(isFieldNameAsterisk( _sFieldName ) && (!_pEntry->isNoneFunction() || _pEntry->IsGroupBy())) )
580 return;
582 OUString sFunctionName;
583 GetFunctionName(SQL_TOKEN_COUNT,sFunctionName);
584 OUString sOldLocalizedFunctionName = _pEntry->GetFunction();
585 if ( sOldLocalizedFunctionName != sFunctionName || _pEntry->IsGroupBy() )
587 // append undo action for the function field
588 _pEntry->SetFunctionType(FKT_NONE);
589 _pEntry->SetFunction(OUString());
590 _pEntry->SetGroupBy(false);
591 notifyFunctionFieldChanged(sOldLocalizedFunctionName,_pEntry->GetFunction(),_bListAction,_nColumnId);
595 bool OSelectionBrowseBox::fillColumnRef(const OSQLParseNode* _pColumnRef, const Reference< XConnection >& _rxConnection, OTableFieldDescRef const & _pEntry, bool& _bListAction )
597 OSL_ENSURE(_pColumnRef,"No valid parsenode!");
598 OUString sColumnName,sTableRange;
599 OSQLParseTreeIterator::getColumnRange(_pColumnRef,_rxConnection,sColumnName,sTableRange);
600 return fillColumnRef(sColumnName,sTableRange,_rxConnection->getMetaData(),_pEntry,_bListAction);
603 bool OSelectionBrowseBox::fillColumnRef(const OUString& _sColumnName, std::u16string_view _sTableRange, const Reference<XDatabaseMetaData>& _xMetaData, OTableFieldDescRef const & _pEntry, bool& _bListAction)
605 bool bError = false;
606 ::comphelper::UStringMixEqual bCase(_xMetaData->supportsMixedCaseQuotedIdentifiers());
607 // check if the table name is the same
608 if ( !_sTableRange.empty() && (bCase(_pEntry->GetTable(),_sTableRange) || bCase(_pEntry->GetAlias(),_sTableRange)) )
609 { // a table was already inserted and the tables contains that column name
611 if ( !_pEntry->GetTabWindow() )
612 { // fill tab window
613 OUString sOldAlias = _pEntry->GetAlias();
614 if ( !fillEntryTable(_pEntry,_pEntry->GetTable()) )
615 fillEntryTable(_pEntry,_pEntry->GetAlias()); // only when the first failed
616 if ( !bCase(sOldAlias,_pEntry->GetAlias()) )
617 notifyTableFieldChanged(sOldAlias,_pEntry->GetAlias(),_bListAction,GetCurColumnId());
620 // check if the table window
621 OQueryTableWindow* pEntryTab = static_cast<OQueryTableWindow*>(_pEntry->GetTabWindow());
622 if ( !pEntryTab ) // no table found with this name so we have to travel through all tables
624 sal_uInt16 nTabCount = 0;
625 if ( !static_cast<OQueryTableView*>(getDesignView()->getTableView())->FindTableFromField(_sColumnName,_pEntry,nTabCount) ) // error occurred: column not in table window
627 OUString sErrorMsg(DBA_RES(RID_STR_FIELD_DOESNT_EXIST));
628 sErrorMsg = sErrorMsg.replaceFirst("$name$",_sColumnName);
629 OSQLErrorBox aWarning(GetFrameWeld(), sErrorMsg);
630 aWarning.run();
631 bError = true;
633 else
635 pEntryTab = static_cast<OQueryTableWindow*>(_pEntry->GetTabWindow());
636 notifyTableFieldChanged(OUString(),_pEntry->GetAlias(),_bListAction,GetCurColumnId());
639 if ( pEntryTab ) // here we got a valid table
640 _pEntry->SetField(_sColumnName);
642 return bError;
645 bool OSelectionBrowseBox::saveField(OUString& _sFieldName ,OTableFieldDescRef const & _pEntry, bool& _bListAction)
647 bool bError = false;
649 OQueryController& rController = static_cast<OQueryController&>(getDesignView()->getController());
651 // first look if the name can be found in our tables
652 sal_uInt16 nTabCount = 0;
653 OUString sOldAlias = _pEntry->GetAlias();
654 if ( static_cast<OQueryTableView*>(getDesignView()->getTableView())->FindTableFromField(_sFieldName,_pEntry,nTabCount) )
656 // append undo action for the alias name
657 _pEntry->SetField(_sFieldName);
658 notifyTableFieldChanged(sOldAlias,_pEntry->GetAlias(),_bListAction,GetCurColumnId());
659 clearEntryFunctionField(_sFieldName,_pEntry,_bListAction,_pEntry->GetColumnId());
660 return bError;
663 Reference<XConnection> xConnection( rController.getConnection() );
664 Reference< XDatabaseMetaData > xMetaData;
665 if ( xConnection.is() )
666 xMetaData = xConnection->getMetaData();
667 OSL_ENSURE( xMetaData.is(), "OSelectionBrowseBox::saveField: invalid connection/meta data!" );
668 if ( !xMetaData.is() )
669 return true;
671 OUString sErrorMsg;
672 // second test if the name can be set as select columns in a pseudo statement
673 // we have to look which entries we should quote
675 const OUString sFieldAlias = _pEntry->GetFieldAlias();
676 ::connectivity::OSQLParser& rParser( rController.getParser() );
678 // automatically add parentheses around subqueries
679 OUString devnull;
680 std::unique_ptr<OSQLParseNode> pParseNode = rParser.parseTree( devnull, _sFieldName, true );
681 if (pParseNode == nullptr)
682 pParseNode = rParser.parseTree( devnull, _sFieldName );
683 if (pParseNode != nullptr && SQL_ISRULE(pParseNode, select_statement))
684 _sFieldName = "(" + _sFieldName + ")";
687 std::unique_ptr<OSQLParseNode> pParseNode;
689 // 4 passes in trying to interpret the field name
690 // - don't quote the field name, parse internationally
691 // - don't quote the field name, parse en-US
692 // - quote the field name, parse internationally
693 // - quote the field name, parse en-US
694 size_t nPass = 4;
695 OUString sQuotedFullFieldName(::dbtools::quoteName( xMetaData->getIdentifierQuoteString(), _sFieldName ));
696 OUString sFullFieldName(_sFieldName);
698 if ( _pEntry->isAggregateFunction() )
700 OSL_ENSURE(!_pEntry->GetFunction().isEmpty(),"No empty Function name allowed here! ;-(");
701 sQuotedFullFieldName = _pEntry->GetFunction() + "(" + sQuotedFullFieldName + ")";
702 sFullFieldName = _pEntry->GetFunction() + "(" + sFullFieldName + ")";
707 bool bQuote = ( nPass <= 2 );
708 bool bInternational = ( nPass % 2 ) == 0;
710 OUString sSql {"SELECT "};
711 if ( bQuote )
712 sSql += sQuotedFullFieldName;
713 else
714 sSql += sFullFieldName;
716 if ( !sFieldAlias.isEmpty() )
717 { // always quote the alias name: there cannot be a function in it
718 sSql += " " + ::dbtools::quoteName( xMetaData->getIdentifierQuoteString(), sFieldAlias );
720 sSql += " FROM x";
722 pParseNode = rParser.parseTree( sErrorMsg, sSql, bInternational );
724 while ( ( pParseNode == nullptr ) && ( --nPass > 0 ) );
727 if ( pParseNode == nullptr )
729 // something different which we have to check
730 OUString sErrorMessage( DBA_RES( STR_QRY_COLUMN_NOT_FOUND ) );
731 sErrorMessage = sErrorMessage.replaceFirst("$name$",_sFieldName);
732 OSQLErrorBox aWarning(GetFrameWeld(), sErrorMessage);
733 aWarning.run();
735 return true;
738 // we got a valid select column
739 // find what type of column has be inserted
740 ::connectivity::OSQLParseNode* pSelection = pParseNode->getChild(2);
741 if ( SQL_ISRULE(pSelection,selection) ) // we found the asterisk
743 _pEntry->SetField(_sFieldName);
744 clearEntryFunctionField(_sFieldName,_pEntry,_bListAction,_pEntry->GetColumnId());
746 else // travel through the select column parse node
748 OTableFieldDescRef aSelEntry = _pEntry;
749 sal_uInt16 nColumnId = aSelEntry->GetColumnId();
751 sal_uInt32 nCount = pSelection->count();
752 for (sal_uInt32 i = 0; i < nCount; ++i)
754 if ( i > 0 ) // may we have to append more than one field
756 sal_uInt16 nColumnPosition;
757 aSelEntry = FindFirstFreeCol(nColumnPosition);
758 if ( !aSelEntry.is() )
760 AppendNewCol();
761 aSelEntry = FindFirstFreeCol(nColumnPosition);
763 ++nColumnPosition;
764 nColumnId = GetColumnId(nColumnPosition);
767 ::connectivity::OSQLParseNode* pChild = pSelection->getChild( i );
768 OSL_ENSURE(SQL_ISRULE(pChild,derived_column), "No derived column found!");
769 // get the column alias
770 OUString sColumnAlias = OSQLParseTreeIterator::getColumnAlias(pChild);
771 if ( !sColumnAlias.isEmpty() ) // we found an as clause
773 OUString aSelectionAlias = aSelEntry->GetFieldAlias();
774 aSelEntry->SetFieldAlias( sColumnAlias );
775 // append undo
776 appendUndoAction(aSelectionAlias,aSelEntry->GetFieldAlias(),BROW_COLUMNALIAS_ROW,_bListAction);
777 if ( m_bVisibleRow[BROW_COLUMNALIAS_ROW] )
778 RowModified(GetBrowseRow(BROW_COLUMNALIAS_ROW), nColumnId);
781 ::connectivity::OSQLParseNode* pColumnRef = pChild->getChild(0);
782 if (
783 pColumnRef->getKnownRuleID() != OSQLParseNode::subquery &&
784 pColumnRef->count() == 3 &&
785 SQL_ISPUNCTUATION(pColumnRef->getChild(0),"(") &&
786 SQL_ISPUNCTUATION(pColumnRef->getChild(2),")")
788 pColumnRef = pColumnRef->getChild(1);
790 if ( SQL_ISRULE(pColumnRef,column_ref) ) // we found a valid column name or more column names
792 // look if we can find the corresponding table
793 bError = fillColumnRef( pColumnRef, xConnection, aSelEntry, _bListAction );
795 // we found a simple column so we must clear the function fields but only when the column name is '*'
796 // and the function is different to count
797 clearEntryFunctionField(_sFieldName,aSelEntry,_bListAction,nColumnId);
799 // do we have an aggregate function and only a function?
800 else if ( SQL_ISRULE(pColumnRef,general_set_fct) )
802 OUString sLocalizedFunctionName;
803 if ( GetFunctionName(pColumnRef->getChild(0)->getTokenID(),sLocalizedFunctionName) )
805 OUString sOldLocalizedFunctionName = aSelEntry->GetFunction();
806 aSelEntry->SetFunction(sLocalizedFunctionName);
807 sal_uInt32 nFunCount = pColumnRef->count() - 1;
808 sal_Int32 nFunctionType = FKT_AGGREGATE;
809 bool bQuote = false;
810 // may be there exists only one parameter which is a column, fill all information into our fields
811 if ( nFunCount == 4 && SQL_ISRULE(pColumnRef->getChild(3),column_ref) )
812 bError = fillColumnRef( pColumnRef->getChild(3), xConnection, aSelEntry, _bListAction );
813 else if ( nFunCount == 3 ) // we have a COUNT(*) here, so take the first table
814 bError = fillColumnRef( "*", std::u16string_view(), xMetaData, aSelEntry, _bListAction );
815 else
817 nFunctionType |= FKT_NUMERIC;
818 bQuote = true;
819 aSelEntry->SetDataType(DataType::DOUBLE);
820 aSelEntry->SetFieldType(TAB_NORMAL_FIELD);
823 // now parse the parameters
824 OUString sParameters;
825 for(sal_uInt32 function = 2; function < nFunCount; ++function) // we only want to parse the parameters of the function
826 pColumnRef->getChild(function)->parseNodeToStr( sParameters, xConnection, &rParser.getContext(), true, bQuote );
828 aSelEntry->SetFunctionType(nFunctionType);
829 aSelEntry->SetField(sParameters);
830 if ( aSelEntry->IsGroupBy() )
832 sOldLocalizedFunctionName = m_aFunctionStrings.copy(m_aFunctionStrings.lastIndexOf(';')+1);
833 aSelEntry->SetGroupBy(false);
836 // append undo action
837 notifyFunctionFieldChanged(sOldLocalizedFunctionName,sLocalizedFunctionName,_bListAction, nColumnId);
839 else
840 OSL_FAIL("Unsupported function inserted!");
843 else
845 // so we first clear the function field
846 clearEntryFunctionField(_sFieldName,aSelEntry,_bListAction,nColumnId);
847 OUString sFunction;
848 pColumnRef->parseNodeToStr( sFunction,
849 xConnection,
850 &rController.getParser().getContext(),
851 true); // quote is to true because we need quoted elements inside the function
853 getDesignView()->fillFunctionInfo(pColumnRef,sFunction,aSelEntry);
855 if( SQL_ISRULEOR3(pColumnRef, position_exp, extract_exp, fold) ||
856 SQL_ISRULEOR3(pColumnRef, char_substring_fct, length_exp, char_value_fct) )
857 // a calculation has been found ( can be calc and function )
859 // now parse the whole statement
860 sal_uInt32 nFunCount = pColumnRef->count();
861 OUString sParameters;
862 for(sal_uInt32 function = 0; function < nFunCount; ++function)
863 pColumnRef->getChild(function)->parseNodeToStr( sParameters, xConnection, &rParser.getContext(), true );
865 sOldAlias = aSelEntry->GetAlias();
866 sal_Int32 nNewFunctionType = aSelEntry->GetFunctionType() | FKT_NUMERIC | FKT_OTHER;
867 aSelEntry->SetFunctionType(nNewFunctionType);
868 aSelEntry->SetField(sParameters);
870 else
872 aSelEntry->SetFieldAlias(sColumnAlias);
873 if ( SQL_ISRULE(pColumnRef,set_fct_spec) )
874 aSelEntry->SetFunctionType(/*FKT_NUMERIC | */FKT_OTHER);
875 else
876 aSelEntry->SetFunctionType(FKT_NUMERIC | FKT_OTHER);
879 aSelEntry->SetAlias(OUString());
880 notifyTableFieldChanged(sOldAlias,aSelEntry->GetAlias(),_bListAction, nColumnId);
883 if ( i > 0 && !InsertField(aSelEntry,BROWSER_INVALIDID,true,false).is() ) // may we have to append more than one field
884 { // the field could not be inserted
885 OUString sErrorMessage( DBA_RES( RID_STR_FIELD_DOESNT_EXIST ) );
886 sErrorMessage = sErrorMessage.replaceFirst("$name$",aSelEntry->GetField());
887 OSQLErrorBox aWarning(GetFrameWeld(), sErrorMessage);
888 aWarning.run();
889 bError = true;
894 return bError;
897 bool OSelectionBrowseBox::SaveModified()
899 OQueryController& rController = static_cast<OQueryController&>(getDesignView()->getController());
900 OTableFieldDescRef pEntry;
901 sal_uInt16 nCurrentColumnPos = GetColumnPos(GetCurColumnId());
902 if(getFields().size() > o3tl::make_unsigned(nCurrentColumnPos - 1))
903 pEntry = getEntry(nCurrentColumnPos - 1);
905 bool bWasEmpty = pEntry.is() && pEntry->IsEmpty();
906 bool bError = false;
907 bool bListAction = false;
909 if (pEntry.is() && Controller().is() && Controller()->IsValueChangedFromSaved())
911 // for the Undo-action
912 OUString strOldCellContents,sNewValue;
913 sal_Int32 nRow = GetRealRow(GetCurRow());
914 bool bAppendRow = false;
915 switch (nRow)
917 case BROW_VIS_ROW:
919 bool bOldValue = m_pVisibleCell->GetBox().get_saved_state() != TRISTATE_FALSE;
920 strOldCellContents
921 = bOldValue ? std::u16string_view(u"1") : std::u16string_view(u"0");
922 sNewValue
923 = !bOldValue ? std::u16string_view(u"1") : std::u16string_view(u"0");
925 if((m_bOrderByUnRelated || pEntry->GetOrderDir() == ORDER_NONE) &&
926 (m_bGroupByUnRelated || !pEntry->IsGroupBy()))
928 pEntry->SetVisible(m_pVisibleCell->GetBox().get_active());
930 else
932 pEntry->SetVisible();
933 m_pVisibleCell->GetBox().set_active(true);
935 break;
937 case BROW_FIELD_ROW:
939 weld::ComboBox& rComboBox = m_pFieldCell->get_widget();
940 OUString aFieldName(rComboBox.get_active_text());
943 if (aFieldName.isEmpty())
945 OTableFieldDescRef pNewEntry = new OTableFieldDesc();
946 pNewEntry->SetColumnId( pEntry->GetColumnId() );
947 std::replace(getFields().begin(),getFields().end(),pEntry,pNewEntry);
948 sal_uInt16 nCol = GetCurColumnId();
949 for (int i = 0; i < m_nVisibleCount; i++) // redraw column
950 RowModified(i,nCol);
952 else
954 strOldCellContents = pEntry->GetField();
955 bListAction = true;
956 if ( !m_bInUndoMode )
957 rController.GetUndoManager().EnterListAction(OUString(),OUString(),0,ViewShellId(-1));
959 sal_Int32 nPos = rComboBox.find_text(aFieldName);
960 OUString aAliasName = pEntry->GetAlias();
961 if ( nPos != -1 && aAliasName.isEmpty() && aFieldName.indexOf('.') >= 0 )
962 { // special case, we have a table field so we must cut the table name
963 OUString sTableAlias = aFieldName.getToken(0,'.');
964 pEntry->SetAlias(sTableAlias);
965 OUString sColumnName = aFieldName.copy(sTableAlias.getLength()+1);
966 const Reference<XConnection>& xConnection = rController.getConnection();
967 if ( !xConnection.is() )
968 return false;
969 bError = fillColumnRef( sColumnName, sTableAlias, xConnection->getMetaData(), pEntry, bListAction );
971 else
972 bError = true;
974 if ( bError )
975 bError = saveField(aFieldName,pEntry,bListAction);
978 catch(Exception&)
980 bError = true;
982 if ( bError )
984 sNewValue = aFieldName;
985 if ( !m_bInUndoMode )
986 static_cast<OQueryController&>(getDesignView()->getController()).GetUndoManager().LeaveListAction();
987 bListAction = false;
989 else
990 sNewValue = pEntry->GetField();
991 rController.InvalidateFeature( ID_BROWSER_QUERY_EXECUTE );
993 break;
995 case BROW_TABLE_ROW:
997 weld::ComboBox& rComboBox = m_pTableCell->get_widget();
998 OUString aAliasName = rComboBox.get_active_text();
999 strOldCellContents = pEntry->GetAlias();
1000 if (rComboBox.get_active() != 0)
1002 pEntry->SetAlias(aAliasName);
1003 // we have to set the table name as well as the table window
1004 OJoinTableView::OTableWindowMap& rTabWinList = getDesignView()->getTableView()->GetTabWinMap();
1005 OJoinTableView::OTableWindowMap::const_iterator aIter = rTabWinList.find(aAliasName);
1006 if(aIter != rTabWinList.end())
1008 OQueryTableWindow* pEntryTab = static_cast<OQueryTableWindow*>(aIter->second.get());
1009 if (pEntryTab)
1011 pEntry->SetTable(pEntryTab->GetTableName());
1012 pEntry->SetTabWindow(pEntryTab);
1016 else
1018 pEntry->SetAlias(OUString());
1019 pEntry->SetTable(OUString());
1020 pEntry->SetTabWindow(nullptr);
1022 sNewValue = pEntry->GetAlias();
1024 } break;
1026 case BROW_ORDER_ROW:
1028 strOldCellContents = OUString::number(static_cast<sal_uInt16>(pEntry->GetOrderDir()));
1029 weld::ComboBox& rComboBox = m_pOrderCell->get_widget();
1030 sal_Int32 nIdx = rComboBox.get_active();
1031 if (nIdx == -1)
1032 nIdx = 0;
1033 pEntry->SetOrderDir(EOrderDir(nIdx));
1034 if(!m_bOrderByUnRelated)
1036 pEntry->SetVisible();
1037 m_pVisibleCell->GetBox().set_active(true);
1038 RowModified(GetBrowseRow(BROW_VIS_ROW), GetCurColumnId());
1040 sNewValue = OUString::number(static_cast<sal_uInt16>(pEntry->GetOrderDir()));
1041 } break;
1043 case BROW_COLUMNALIAS_ROW:
1044 strOldCellContents = pEntry->GetFieldAlias();
1045 pEntry->SetFieldAlias(m_pTextCell->get_widget().get_text());
1046 sNewValue = pEntry->GetFieldAlias();
1047 break;
1048 case BROW_FUNCTION_ROW:
1050 strOldCellContents = pEntry->GetFunction();
1051 weld::ComboBox& rComboBox = m_pFunctionCell->get_widget();
1052 sal_Int32 nPos = rComboBox.get_active();
1053 // these functions are only available in CORE
1054 OUString sFunctionName = rComboBox.get_text(nPos);
1055 std::u16string_view sGroupFunctionName = m_aFunctionStrings.subView(m_aFunctionStrings.lastIndexOf(';')+1);
1056 bool bGroupBy = false;
1057 if ( sGroupFunctionName == sFunctionName ) // check if the function name is GROUP
1059 bGroupBy = true;
1061 if ( !m_bGroupByUnRelated && !pEntry->IsVisible() )
1063 // we have to change the visible flag, so we must append also an undo action
1064 pEntry->SetVisible();
1065 m_pVisibleCell->GetBox().set_active(true);
1066 appendUndoAction("0",u"1",BROW_VIS_ROW,bListAction);
1067 RowModified(GetBrowseRow(BROW_VIS_ROW), GetCurColumnId());
1070 pEntry->SetFunction(OUString());
1071 pEntry->SetFunctionType(pEntry->GetFunctionType() & ~FKT_AGGREGATE );
1073 else if ( nPos ) // we found an aggregate function
1075 pEntry->SetFunctionType(pEntry->GetFunctionType() | FKT_AGGREGATE );
1076 pEntry->SetFunction(sFunctionName);
1078 else
1080 sFunctionName.clear();
1081 pEntry->SetFunction(OUString());
1082 pEntry->SetFunctionType(pEntry->GetFunctionType() & ~FKT_AGGREGATE );
1085 pEntry->SetGroupBy(bGroupBy);
1087 sNewValue = sFunctionName;
1089 break;
1090 default:
1092 Reference< XConnection> xConnection = static_cast<OQueryController&>(getDesignView()->getController()).getConnection();
1093 if(!xConnection.is())
1094 break;
1096 sal_uInt16 nIdx = sal_uInt16(nRow - BROW_CRIT1_ROW);
1097 OUString aText = comphelper::string::stripStart(m_pTextCell->get_widget().get_text(), ' ');
1099 OUString aCrit;
1100 if(!aText.isEmpty())
1102 OUString aErrorMsg;
1103 Reference<XPropertySet> xColumn;
1104 std::unique_ptr<OSQLParseNode> pParseNode = getDesignView()->getPredicateTreeFromEntry(pEntry,aText,aErrorMsg,xColumn);
1106 if (pParseNode)
1108 pParseNode->parseNodeToPredicateStr(aCrit,
1109 xConnection,
1110 static_cast<OQueryController&>(getDesignView()->getController()).getNumberFormatter(),
1111 xColumn,
1112 pEntry->GetAlias(),
1113 getDesignView()->getLocale(),
1114 getDesignView()->getDecimalSeparator(),
1115 &(static_cast<OQueryController&>(getDesignView()->getController()).getParser().getContext()));
1117 else
1119 if(xColumn.is())
1121 sal_Int32 nType = 0;
1122 xColumn->getPropertyValue(PROPERTY_TYPE) >>= nType;
1123 switch(nType)
1125 case DataType::CHAR:
1126 case DataType::VARCHAR:
1127 case DataType::LONGVARCHAR:
1128 case DataType::CLOB:
1129 if(!aText.startsWith("'") || !aText.endsWith("'"))
1131 aText = aText.replaceAll("'", "''");
1132 aText = "'" + aText + "'";
1134 break;
1135 default:
1138 ::connectivity::OSQLParser& rParser = static_cast<OQueryController&>(getDesignView()->getController()).getParser();
1139 pParseNode = rParser.predicateTree(aErrorMsg,
1140 aText,
1141 static_cast<OQueryController&>(getDesignView()->getController()).getNumberFormatter(),
1142 xColumn);
1143 if (pParseNode)
1145 pParseNode->parseNodeToPredicateStr(aCrit,
1146 xConnection,
1147 static_cast<OQueryController&>(getDesignView()->getController()).getNumberFormatter(),
1148 xColumn,
1149 pEntry->GetAlias(),
1150 getDesignView()->getLocale(),
1151 getDesignView()->getDecimalSeparator(),
1152 &(static_cast<OQueryController&>(getDesignView()->getController()).getParser().getContext()));
1154 else
1156 if ( !m_bDisableErrorBox )
1158 OSQLWarningBox aWarning(GetFrameWeld(), aErrorMsg);
1159 aWarning.run();
1161 bError = true;
1164 else
1166 if ( !m_bDisableErrorBox )
1168 OSQLWarningBox aWarning(GetFrameWeld(), aErrorMsg);
1169 aWarning.run();
1171 bError = true;
1175 strOldCellContents = pEntry->GetCriteria(nIdx);
1176 pEntry->SetCriteria(nIdx, aCrit);
1177 sNewValue = pEntry->GetCriteria(nIdx);
1178 if(!aCrit.isEmpty() && nRow >= (GetRowCount()-1))
1179 bAppendRow = true;
1182 if( !bError && Controller().is() )
1183 Controller()->SaveValue();
1185 RowModified(GetCurRow(), GetCurColumnId());
1187 if ( bAppendRow )
1189 RowInserted( GetRowCount()-1 );
1190 m_bVisibleRow.push_back(true);
1191 ++m_nVisibleCount;
1194 if(!bError)
1196 // and now the undo-action for the total
1197 appendUndoAction(strOldCellContents,sNewValue,nRow);
1202 // did I store data in a FieldDescription which was empty before and which is not empty anymore after the changes?
1203 if ( pEntry.is() && bWasEmpty && !pEntry->IsEmpty() && !bError )
1205 // Default to visible
1206 pEntry->SetVisible();
1207 appendUndoAction("0",u"1",BROW_VIS_ROW,bListAction);
1208 RowModified(BROW_VIS_ROW, GetCurColumnId());
1210 // if required add empty columns
1211 sal_uInt16 nDummy;
1212 CheckFreeColumns(nDummy);
1215 if ( bListAction && !m_bInUndoMode )
1216 static_cast<OQueryController&>(getDesignView()->getController()).GetUndoManager().LeaveListAction();
1218 return pEntry != nullptr && !bError;
1221 bool OSelectionBrowseBox::SeekRow(sal_Int32 nRow)
1223 m_nSeekRow = nRow;
1224 return nRow < m_nVisibleCount;
1227 void OSelectionBrowseBox::PaintCell(OutputDevice& rDev, const tools::Rectangle& rRect, sal_uInt16 nColumnId) const
1229 rDev.SetClipRegion(vcl::Region(rRect));
1231 OTableFieldDescRef pEntry;
1232 sal_uInt16 nPos = GetColumnPos(nColumnId);
1233 if(getFields().size() > o3tl::make_unsigned(nPos - 1))
1234 pEntry = getFields()[nPos - 1];
1236 if (!pEntry.is())
1237 return;
1239 sal_Int32 nRow = GetRealRow(m_nSeekRow);
1240 if (nRow == BROW_VIS_ROW)
1241 PaintTristate(rRect, pEntry->IsVisible() ? TRISTATE_TRUE : TRISTATE_FALSE);
1242 else
1243 rDev.DrawText(rRect, GetCellText(nRow, nColumnId),DrawTextFlags::VCenter);
1245 rDev.SetClipRegion( );
1248 void OSelectionBrowseBox::PaintStatusCell(OutputDevice& rDev, const tools::Rectangle& rRect) const
1250 tools::Rectangle aRect(rRect);
1251 aRect.TopLeft().AdjustY( -2 );
1252 OUString aLabel(DBA_RES(STR_QUERY_HANDLETEXT));
1254 // from BROW_CRIT2_ROW onwards all rows are shown "or"
1255 sal_Int32 nToken = (m_nSeekRow >= GetBrowseRow(BROW_CRIT2_ROW))
1256 ? BROW_CRIT2_ROW : GetRealRow(m_nSeekRow);
1257 rDev.DrawText(aRect, aLabel.getToken(nToken, ';'),DrawTextFlags::VCenter);
1260 void OSelectionBrowseBox::RemoveColumn(sal_uInt16 _nColumnId)
1262 OQueryController& rController = static_cast<OQueryController&>(getDesignView()->getController());
1264 sal_uInt16 nPos = GetColumnPos(_nColumnId);
1265 // the control should always have exactly one more column: the HandleColumn
1266 OSL_ENSURE((nPos == 0) || (nPos <= getFields().size()), "OSelectionBrowseBox::RemoveColumn : invalid parameter nColId");
1267 // ColId is synonymous to Position, and the condition should be valid
1269 sal_uInt16 nCurCol = GetCurColumnId();
1270 sal_Int32 nCurrentRow = GetCurRow();
1272 DeactivateCell();
1274 getFields().erase( getFields().begin() + (nPos - 1) );
1275 OTableFieldDescRef pEntry = new OTableFieldDesc();
1276 pEntry->SetColumnId(_nColumnId);
1277 getFields().push_back(pEntry);
1279 EditBrowseBox::RemoveColumn( _nColumnId );
1280 InsertDataColumn( _nColumnId , OUString(), DEFAULT_SIZE );
1282 // redraw
1283 tools::Rectangle aInvalidRect = GetInvalidRect( _nColumnId );
1284 Invalidate( aInvalidRect );
1286 ActivateCell( nCurrentRow, nCurCol );
1288 rController.setModified( true );
1290 invalidateUndoRedo();
1293 void OSelectionBrowseBox::RemoveField(sal_uInt16 nColumnId )
1295 OQueryController& rController = static_cast<OQueryController&>(getDesignView()->getController());
1297 sal_uInt16 nPos = GetColumnPos(nColumnId);
1298 OSL_ENSURE(getFields().size() > o3tl::make_unsigned(nPos-1),"ID is to great!");
1300 OTableFieldDescRef pDesc = getEntry(static_cast<sal_uInt32>(nPos - 1)) ;
1301 pDesc->SetColWidth( static_cast<sal_uInt16>(GetColumnWidth(nColumnId)) ); // was not stored this before
1303 // trigger UndoAction
1304 if ( !m_bInUndoMode )
1306 std::unique_ptr<OTabFieldDelUndoAct> pUndoAction(new OTabFieldDelUndoAct( this ));
1307 pUndoAction->SetTabFieldDescr(pDesc);
1308 pUndoAction->SetColumnPosition(nPos);
1309 rController.addUndoActionAndInvalidate( std::move(pUndoAction) );
1312 RemoveColumn(nColumnId);
1314 invalidateUndoRedo();
1317 void OSelectionBrowseBox::adjustSelectionMode( bool _bClickedOntoHeader, bool _bClickedOntoHandleCol )
1319 // if a Header has been selected it should be shown otherwise not
1320 if ( _bClickedOntoHeader )
1322 if (0 == GetSelectColumnCount() )
1323 // I am in the correct mode if a selected column exists
1324 if ( BrowserMode::HIDESELECT == ( m_nMode & BrowserMode::HIDESELECT ) )
1326 m_nMode &= ~BrowserMode::HIDESELECT;
1327 m_nMode |= BrowserMode::MULTISELECTION;
1328 SetMode( m_nMode );
1331 else if ( BrowserMode::HIDESELECT != ( m_nMode & BrowserMode::HIDESELECT ) )
1333 if ( GetSelectColumnCount() != 0 )
1334 SetNoSelection();
1336 if ( _bClickedOntoHandleCol )
1338 m_nMode |= BrowserMode::HIDESELECT;
1339 m_nMode &= ~BrowserMode::MULTISELECTION;
1340 SetMode( m_nMode );
1345 void OSelectionBrowseBox::MouseButtonDown(const BrowserMouseEvent& rEvt)
1347 if( rEvt.IsLeft() )
1349 bool bOnHandle = HANDLE_ID == rEvt.GetColumnId();
1350 bool bOnHeader = ( rEvt.GetRow() < 0 ) && !bOnHandle;
1351 adjustSelectionMode( bOnHeader, bOnHandle );
1353 EditBrowseBox::MouseButtonDown(rEvt);
1356 void OSelectionBrowseBox::MouseButtonUp(const BrowserMouseEvent& rEvt)
1358 EditBrowseBox::MouseButtonUp( rEvt );
1359 static_cast<OQueryController&>(getDesignView()->getController()).InvalidateFeature( ID_BROWSER_QUERY_EXECUTE );
1362 void OSelectionBrowseBox::KeyInput( const KeyEvent& rEvt )
1364 if (IsColumnSelected(GetCurColumnId()))
1366 if (rEvt.GetKeyCode().GetCode() == KEY_DELETE && // Delete rows
1367 !rEvt.GetKeyCode().IsShift() &&
1368 !rEvt.GetKeyCode().IsMod1())
1370 RemoveField(GetCurColumnId());
1371 return;
1374 EditBrowseBox::KeyInput(rEvt);
1377 sal_Int8 OSelectionBrowseBox::AcceptDrop( const BrowserAcceptDropEvent& rEvt )
1379 sal_Int8 nDropAction = DND_ACTION_NONE;
1380 if ( rEvt.GetRow() >= -1 )
1382 if ( IsEditing() )
1384 // allow the asterisk again
1385 m_bDisableErrorBox = true;
1386 SaveModified();
1387 m_bDisableErrorBox = false;
1388 DeactivateCell();
1390 // check if the format is already supported, if not deactivate the current cell and try again
1391 if ( OJoinExchObj::isFormatAvailable(GetDataFlavors()) )
1392 nDropAction = DND_ACTION_LINK;
1395 return nDropAction;
1398 sal_Int8 OSelectionBrowseBox::ExecuteDrop( const BrowserExecuteDropEvent& _rEvt )
1401 TransferableDataHelper aDropped(_rEvt.maDropEvent.Transferable);
1402 if (!OJoinExchObj::isFormatAvailable(aDropped.GetDataFlavorExVector()))
1404 OSL_FAIL("OSelectionBrowseBox::ExecuteDrop: this should never have passed AcceptDrop!");
1405 return DND_ACTION_NONE;
1408 // insert the field at the selected position
1409 OJoinExchangeData jxdSource = OJoinExchObj::GetSourceDescription(_rEvt.maDropEvent.Transferable);
1410 InsertField(jxdSource);
1412 return DND_ACTION_LINK;
1415 OTableFieldDescRef const & OSelectionBrowseBox::AppendNewCol( sal_uInt16 nCnt)
1417 // one or more can be created, but the first one will is not returned
1418 sal_uInt32 nCount = getFields().size();
1419 for (sal_uInt16 i=0 ; i<nCnt ; i++)
1421 OTableFieldDescRef pEmptyEntry = new OTableFieldDesc();
1422 getFields().push_back(pEmptyEntry);
1423 sal_uInt16 nColumnId = sal::static_int_cast< sal_uInt16 >(getFields().size());
1424 pEmptyEntry->SetColumnId( nColumnId );
1426 InsertDataColumn( nColumnId , OUString(), DEFAULT_SIZE );
1429 return getFields()[nCount];
1432 void OSelectionBrowseBox::DeleteFields(const OUString& rAliasName)
1434 if (getFields().empty())
1435 return;
1437 sal_uInt16 nColId = GetCurColumnId();
1438 sal_uInt32 nRow = GetCurRow();
1440 bool bWasEditing = IsEditing();
1441 if (bWasEditing)
1442 DeactivateCell();
1444 auto aIter = std::find_if(getFields().rbegin(), getFields().rend(),
1445 [&rAliasName](const OTableFieldDescRef pEntry) { return pEntry->GetAlias() == rAliasName; });
1446 if (aIter != getFields().rend())
1448 sal_uInt16 nPos = sal::static_int_cast<sal_uInt16>(std::distance(aIter, getFields().rend()));
1449 RemoveField( GetColumnId( nPos ) );
1452 if (bWasEditing)
1453 ActivateCell(nRow , nColId);
1456 void OSelectionBrowseBox::SetColWidth(sal_uInt16 nColId, tools::Long nNewWidth)
1458 bool bWasEditing = IsEditing();
1459 if (bWasEditing)
1460 DeactivateCell();
1462 // create the BaseClass
1463 SetColumnWidth(nColId, nNewWidth);
1465 // tell it the FieldDescription
1466 OTableFieldDescRef pEntry = getEntry(GetColumnPos(nColId) - 1);
1467 if (pEntry.is())
1468 pEntry->SetColWidth(sal_uInt16(GetColumnWidth(nColId)));
1470 if (bWasEditing)
1471 ActivateCell(GetCurRow(), GetCurColumnId());
1474 tools::Rectangle OSelectionBrowseBox::GetInvalidRect( sal_uInt16 nColId )
1476 // The rectangle is the full output area of the window
1477 tools::Rectangle aInvalidRect( Point(0,0), GetOutputSizePixel() );
1479 // now update the left side
1480 tools::Rectangle aFieldRect(GetCellRect( 0, nColId )); // used instead of GetFieldRectPixel
1481 aInvalidRect.SetLeft( aFieldRect.Left() );
1483 return aInvalidRect;
1486 void OSelectionBrowseBox::InsertColumn(const OTableFieldDescRef& pEntry, sal_uInt16& _nColumnPosition)
1488 // the control should have exactly one more column: the HandleColumn
1489 OSL_ENSURE(_nColumnPosition == BROWSER_INVALIDID || (_nColumnPosition <= static_cast<tools::Long>(getFields().size())), "OSelectionBrowseBox::InsertColumn : invalid parameter nColId.");
1490 // -1 means at the end. Count means at the end, others denotes a correct position
1492 sal_uInt16 nCurCol = GetCurColumnId();
1493 sal_Int32 nCurrentRow = GetCurRow();
1495 DeactivateCell();
1497 // remember the column id of the current position
1498 sal_uInt16 nColumnId = GetColumnId(_nColumnPosition);
1499 // put at the end of the list if too small or too big,
1500 if ((_nColumnPosition == BROWSER_INVALIDID) || (_nColumnPosition >= getFields().size())) // append the field
1502 if (FindFirstFreeCol(_nColumnPosition) == nullptr) // no more free columns
1504 AppendNewCol();
1505 _nColumnPosition = sal::static_int_cast< sal_uInt16 >(
1506 getFields().size());
1508 else
1509 ++_nColumnPosition; // within the list
1510 nColumnId = GetColumnId(_nColumnPosition);
1511 pEntry->SetColumnId( nColumnId );
1512 getFields()[ _nColumnPosition - 1] = pEntry;
1515 // check if the column ids are identical, if not we have to move
1516 if ( pEntry->GetColumnId() != nColumnId )
1518 sal_uInt16 nOldPosition = GetColumnPos(pEntry->GetColumnId());
1519 OSL_ENSURE( nOldPosition != 0,"Old position was 0. Not possible!");
1520 SetColumnPos(pEntry->GetColumnId(),_nColumnPosition);
1521 // we have to delete an empty field for the fields list, because the columns must have equal length
1522 if ( nOldPosition > 0 && nOldPosition <= getFields().size() )
1523 getFields()[nOldPosition - 1] = pEntry;
1525 ColumnMoved(pEntry->GetColumnId(),false);
1528 if ( pEntry->GetFunctionType() & FKT_AGGREGATE )
1530 OUString sFunctionName = pEntry->GetFunction();
1531 if ( GetFunctionName(sal_uInt32(-1),sFunctionName) )
1532 pEntry->SetFunction(sFunctionName);
1535 nColumnId = pEntry->GetColumnId();
1537 SetColWidth(nColumnId,getDesignView()->getColWidth(GetColumnPos(nColumnId)-1));
1538 // redraw
1539 tools::Rectangle aInvalidRect = GetInvalidRect( nColumnId );
1540 Invalidate( aInvalidRect );
1542 ActivateCell( nCurrentRow, nCurCol );
1543 static_cast<OQueryController&>(getDesignView()->getController()).setModified( true );
1545 invalidateUndoRedo();
1548 OTableFieldDescRef OSelectionBrowseBox::InsertField(const OJoinExchangeData& jxdSource)
1550 OQueryTableWindow* pSourceWin = static_cast<OQueryTableWindow*>(jxdSource.pListBox->GetTabWin());
1551 if (!pSourceWin)
1552 return nullptr;
1554 // name and position of the selected field
1555 weld::TreeView& rTreeView = jxdSource.pListBox->get_widget();
1556 OUString aFieldName = rTreeView.get_text(jxdSource.nEntry);
1557 sal_uInt32 nFieldIndex = jxdSource.nEntry;
1558 OTableFieldInfo* pInf = weld::fromId<OTableFieldInfo*>(rTreeView.get_id(jxdSource.nEntry));
1560 // construct DragInfo, such that I use the other InsertField
1561 OTableFieldDescRef aInfo = new OTableFieldDesc(pSourceWin->GetTableName(),aFieldName);
1562 aInfo->SetTabWindow(pSourceWin);
1563 aInfo->SetFieldIndex(nFieldIndex);
1564 aInfo->SetFieldType(pInf->GetKeyType());
1565 aInfo->SetAlias(pSourceWin->GetAliasName());
1567 aInfo->SetDataType(pInf->GetDataType());
1568 aInfo->SetVisible();
1570 return InsertField(aInfo);
1573 OTableFieldDescRef OSelectionBrowseBox::InsertField(const OTableFieldDescRef& _rInfo, sal_uInt16 _nColumnPosition, bool bVis, bool bActivate)
1576 if(m_nMaxColumns && m_nMaxColumns <= FieldsCount())
1577 return nullptr;
1578 if (bActivate)
1579 SaveModified();
1581 // new column description
1582 OTableFieldDescRef pEntry = _rInfo;
1583 pEntry->SetVisible(bVis);
1585 // insert column
1586 InsertColumn( pEntry, _nColumnPosition );
1588 if ( !m_bInUndoMode )
1590 // trigger UndoAction
1591 std::unique_ptr<OTabFieldCreateUndoAct> pUndoAction(new OTabFieldCreateUndoAct( this ));
1592 pUndoAction->SetTabFieldDescr( pEntry );
1593 pUndoAction->SetColumnPosition(_nColumnPosition);
1594 getDesignView()->getController().addUndoActionAndInvalidate( std::move(pUndoAction) );
1597 return pEntry;
1600 sal_uInt16 OSelectionBrowseBox::FieldsCount()
1602 sal_uInt16 nCount = 0;
1603 for (auto const& field : getFields())
1605 if (field.is() && !field->IsEmpty())
1606 ++nCount;
1609 return nCount;
1612 OTableFieldDescRef OSelectionBrowseBox::FindFirstFreeCol(sal_uInt16& _rColumnPosition )
1615 _rColumnPosition = BROWSER_INVALIDID;
1617 for (auto const& field : getFields())
1619 ++_rColumnPosition;
1620 OTableFieldDescRef pEntry = field;
1621 if ( pEntry.is() && pEntry->IsEmpty() )
1622 return pEntry;
1625 return nullptr;
1628 void OSelectionBrowseBox::CheckFreeColumns(sal_uInt16& _rColumnPosition)
1630 if (FindFirstFreeCol(_rColumnPosition) == nullptr)
1632 // it is full, so append a pack of columns
1633 AppendNewCol(DEFAULT_QUERY_COLS);
1634 OSL_VERIFY(FindFirstFreeCol(_rColumnPosition).is());
1638 void OSelectionBrowseBox::AddGroupBy( const OTableFieldDescRef& rInfo )
1640 Reference< XConnection> xConnection = static_cast<OQueryController&>(getDesignView()->getController()).getConnection();
1641 if(!xConnection.is())
1642 return;
1643 OSL_ENSURE(!rInfo->IsEmpty(),"AddGroupBy:: OTableFieldDescRef should not be empty!");
1644 OTableFieldDescRef pEntry;
1645 const Reference<XDatabaseMetaData> xMeta = xConnection->getMetaData();
1646 const ::comphelper::UStringMixEqual bCase(xMeta.is() && xMeta->supportsMixedCaseQuotedIdentifiers());
1647 //sal_Bool bAppend = sal_False;
1649 bool bAllFieldsSearched = true;
1650 for (auto const& field : getFields())
1652 pEntry = field;
1653 OSL_ENSURE(pEntry.is(),"OTableFieldDescRef was null!");
1655 const OUString aField = pEntry->GetField();
1656 const OUString aAlias = pEntry->GetAlias();
1658 if (bCase(aField,rInfo->GetField()) &&
1659 bCase(aAlias,rInfo->GetAlias()) &&
1660 pEntry->GetFunctionType() == rInfo->GetFunctionType() &&
1661 pEntry->GetFunction() == rInfo->GetFunction())
1663 if ( pEntry->isNumericOrAggregateFunction() && rInfo->IsGroupBy() )
1665 pEntry->SetGroupBy(false);
1666 // we do want to consider that bAllFieldsSearched still true here
1667 // bAllFieldsSearched = false;
1668 break;
1670 else
1672 if ( !pEntry->IsGroupBy() && !pEntry->HasCriteria() ) // here we have a where condition which is no having clause
1674 pEntry->SetGroupBy(rInfo->IsGroupBy());
1675 if(!m_bGroupByUnRelated && pEntry->IsGroupBy())
1676 pEntry->SetVisible();
1677 bAllFieldsSearched = false;
1678 break;
1685 if (bAllFieldsSearched)
1687 OTableFieldDescRef pTmp = InsertField(rInfo, BROWSER_INVALIDID, false, false );
1688 if ( pTmp->isNumericOrAggregateFunction() && rInfo->IsGroupBy() ) // the GroupBy is inherited from rInfo
1689 pTmp->SetGroupBy(false);
1693 void OSelectionBrowseBox::DuplicateConditionLevel( const sal_uInt16 nLevel)
1695 const sal_uInt16 nNewLevel = nLevel +1;
1696 for (auto const& field : getFields())
1698 const OTableFieldDescRef& pEntry = field;
1699 OUString sValue = pEntry->GetCriteria(nLevel);
1700 if ( !sValue.isEmpty() )
1702 pEntry->SetCriteria( nNewLevel, sValue);
1703 if ( nNewLevel == (m_nVisibleCount-BROW_CRIT1_ROW-1) )
1705 RowInserted( GetRowCount()-1 );
1706 m_bVisibleRow.push_back(true);
1707 ++m_nVisibleCount;
1709 m_bVisibleRow[BROW_CRIT1_ROW + nNewLevel] = true;
1714 void OSelectionBrowseBox::AddCondition( const OTableFieldDescRef& rInfo, const OUString& rValue, const sal_uInt16 nLevel,bool _bAddOrOnOneLine )
1716 Reference< XConnection> xConnection = static_cast<OQueryController&>(getDesignView()->getController()).getConnection();
1717 if(!xConnection.is())
1718 return;
1719 OSL_ENSURE(rInfo.is() && !rInfo->IsEmpty(),"AddCondition:: OTableFieldDescRef should not be Empty!");
1721 OTableFieldDescRef pLastEntry;
1722 Reference<XDatabaseMetaData> xMeta = xConnection->getMetaData();
1723 ::comphelper::UStringMixEqual bCase(xMeta.is() && xMeta->supportsMixedCaseQuotedIdentifiers());
1725 bool bAllFieldsSearched = true;
1726 for (auto const& field : getFields())
1728 const OTableFieldDescRef& pEntry = field;
1729 const OUString aField = pEntry->GetField();
1730 const OUString aAlias = pEntry->GetAlias();
1732 if (bCase(aField,rInfo->GetField()) &&
1733 bCase(aAlias,rInfo->GetAlias()) &&
1734 pEntry->GetFunctionType() == rInfo->GetFunctionType() &&
1735 pEntry->GetFunction() == rInfo->GetFunction() &&
1736 pEntry->IsGroupBy() == rInfo->IsGroupBy() )
1738 if ( pEntry->isNumericOrAggregateFunction() && rInfo->IsGroupBy() )
1739 pEntry->SetGroupBy(false);
1740 else
1742 if(!m_bGroupByUnRelated && pEntry->IsGroupBy())
1743 pEntry->SetVisible();
1745 if (pEntry->GetCriteria(nLevel).isEmpty() )
1747 pEntry->SetCriteria( nLevel, rValue);
1748 if(nLevel == (m_nVisibleCount-BROW_CRIT1_ROW-1))
1750 RowInserted( GetRowCount()-1 );
1751 m_bVisibleRow.push_back(true);
1752 ++m_nVisibleCount;
1754 m_bVisibleRow[BROW_CRIT1_ROW + nLevel] = true;
1755 bAllFieldsSearched = false;
1756 break;
1758 if ( _bAddOrOnOneLine )
1760 pLastEntry = pEntry;
1764 if ( pLastEntry.is() )
1766 OUString sCriteria = rValue;
1767 OUString sOldCriteria = pLastEntry->GetCriteria( nLevel );
1768 if ( !sOldCriteria.isEmpty() )
1770 sCriteria = "( " + sOldCriteria + " OR " + rValue + " )";
1772 pLastEntry->SetCriteria( nLevel, sCriteria);
1773 if(nLevel == (m_nVisibleCount-BROW_CRIT1_ROW-1))
1775 RowInserted( GetRowCount()-1 );
1776 m_bVisibleRow.push_back(true);
1777 ++m_nVisibleCount;
1779 m_bVisibleRow[BROW_CRIT1_ROW + nLevel] = true;
1781 else if (bAllFieldsSearched)
1783 OTableFieldDescRef pTmp = InsertField(rInfo, BROWSER_INVALIDID, false, false );
1784 if ( pTmp->isNumericOrAggregateFunction() && rInfo->IsGroupBy() ) // the GroupBy was inherited from rInfo
1785 pTmp->SetGroupBy(false);
1786 if ( pTmp.is() )
1788 pTmp->SetCriteria( nLevel, rValue);
1789 if(nLevel == (m_nVisibleCount-BROW_CRIT1_ROW-1))
1791 RowInserted( GetRowCount()-1 );
1792 m_bVisibleRow.push_back(true);
1793 ++m_nVisibleCount;
1799 void OSelectionBrowseBox::AddOrder( const OTableFieldDescRef& rInfo, const EOrderDir eDir, sal_uInt32 _nCurrentPos)
1801 if (_nCurrentPos == 0)
1802 m_nLastSortColumn = SORT_COLUMN_NONE;
1804 Reference< XConnection> xConnection = static_cast<OQueryController&>(getDesignView()->getController()).getConnection();
1805 if(!xConnection.is())
1806 return;
1807 OSL_ENSURE(!rInfo->IsEmpty(),"AddOrder:: OTableFieldDescRef should not be Empty!");
1808 OTableFieldDescRef pEntry;
1809 Reference<XDatabaseMetaData> xMeta = xConnection->getMetaData();
1810 ::comphelper::UStringMixEqual bCase(xMeta.is() && xMeta->supportsMixedCaseQuotedIdentifiers());
1812 bool bAppend = false;
1813 sal_uInt32 nPos = 0;
1814 bool bAllFieldsSearched = true;
1815 for (auto const& field : getFields())
1817 pEntry = field;
1818 OUString aField = pEntry->GetField();
1819 OUString aAlias = pEntry->GetAlias();
1821 if (bCase(aField,rInfo->GetField()) &&
1822 bCase(aAlias,rInfo->GetAlias()))
1824 bAppend = (m_nLastSortColumn != SORT_COLUMN_NONE) && (nPos <= m_nLastSortColumn);
1825 if ( bAppend )
1827 // we do want to consider that bAllFieldsSearched still true here
1828 // bAllFieldsSearched = false;
1829 break;
1831 else
1833 if ( !m_bOrderByUnRelated )
1834 pEntry->SetVisible();
1835 pEntry->SetOrderDir( eDir );
1836 m_nLastSortColumn = nPos;
1838 bAllFieldsSearched = false;
1839 break;
1841 ++nPos;
1844 if (bAllFieldsSearched)
1846 OTableFieldDescRef pTmp = InsertField(rInfo, BROWSER_INVALIDID, false, false );
1847 if(pTmp.is())
1849 m_nLastSortColumn = pTmp->GetColumnId() - 1;
1850 if ( !m_bOrderByUnRelated && !bAppend )
1851 pTmp->SetVisible();
1852 pTmp->SetOrderDir( eDir );
1857 bool OSelectionBrowseBox::Save()
1859 bool bRet = true;
1860 if (IsModified())
1861 bRet = SaveModified();
1862 return bRet;
1865 void OSelectionBrowseBox::CellModified()
1867 sal_Int32 nRow = GetRealRow(GetCurRow());
1868 switch (nRow)
1870 case BROW_VIS_ROW:
1872 OTableFieldDescRef pEntry = getEntry(GetColumnPos(GetCurColumnId()) - 1);
1874 weld::ComboBox& rComboBox = m_pOrderCell->get_widget();
1875 sal_Int32 nIdx = rComboBox.get_active();
1876 if(!m_bOrderByUnRelated && nIdx > 0 &&
1877 nIdx != -1 &&
1878 !pEntry->IsEmpty() &&
1879 pEntry->GetOrderDir() != ORDER_NONE)
1881 m_pVisibleCell->GetBox().set_active(true);
1882 pEntry->SetVisible();
1884 else
1885 pEntry->SetVisible(m_pVisibleCell->GetBox().get_active());
1887 break;
1889 static_cast<OQueryController&>(getDesignView()->getController()).setModified( true );
1892 void OSelectionBrowseBox::Fill()
1894 OSL_ENSURE(ColCount() >= 1, "OSelectionBrowseBox::Fill : please call only after inserting the handle column !");
1896 sal_uInt16 nColCount = ColCount() - 1;
1897 if (nColCount < DEFAULT_QUERY_COLS)
1898 AppendNewCol(DEFAULT_QUERY_COLS - nColCount);
1901 Size OSelectionBrowseBox::CalcOptimalSize( const Size& _rAvailable )
1903 Size aReturn( _rAvailable.Width(), GetTitleHeight() );
1905 aReturn.AdjustHeight(( m_nVisibleCount ? m_nVisibleCount : 15 ) * GetDataRowHeight() );
1906 aReturn.AdjustHeight(40 ); // just some space
1908 return aReturn;
1911 void OSelectionBrowseBox::Command(const CommandEvent& rEvt)
1913 switch (rEvt.GetCommand())
1915 case CommandEventId::ContextMenu:
1917 Point aMenuPos( rEvt.GetMousePosPixel() );
1919 if (!rEvt.IsMouseEvent())
1921 if ( 1 == GetSelectColumnCount() )
1923 sal_uInt16 nSelId = GetColumnId(
1924 sal::static_int_cast< sal_uInt16 >(
1925 FirstSelectedColumn() ) );
1926 ::tools::Rectangle aColRect( GetFieldRectPixel( 0, nSelId, false ) );
1928 aMenuPos = aColRect.TopCenter();
1930 else
1932 EditBrowseBox::Command(rEvt);
1933 return;
1937 sal_uInt16 nColId = GetColumnId(GetColumnAtXPosPixel( aMenuPos.X() ));
1938 sal_Int32 nRow = GetRowAtYPosPixel( aMenuPos.Y() );
1940 if (nRow < 0 && nColId > HANDLE_ID )
1942 if ( !IsColumnSelected( nColId ) )
1944 adjustSelectionMode( true /* clicked onto a header */ , false /* not onto the handle col */ );
1945 SelectColumnId( nColId );
1948 if (!static_cast<OQueryController&>(getDesignView()->getController()).isReadOnly())
1950 ::tools::Rectangle aRect(aMenuPos, Size(1, 1));
1951 weld::Window* pPopupParent = weld::GetPopupParent(*this, aRect);
1952 std::unique_ptr<weld::Builder> xBuilder(Application::CreateBuilder(pPopupParent, "dbaccess/ui/querycolmenu.ui"));
1953 std::unique_ptr<weld::Menu> xContextMenu(xBuilder->weld_menu("menu"));
1954 OUString sIdent = xContextMenu->popup_at_rect(pPopupParent, aRect);
1955 if (sIdent == "delete")
1956 RemoveField(nColId);
1957 else if (sIdent == "width")
1958 adjustBrowseBoxColumnWidth( this, nColId );
1961 else if(nRow >= 0 && nColId <= HANDLE_ID)
1963 if (!static_cast<OQueryController&>(getDesignView()->getController()).isReadOnly())
1965 ::tools::Rectangle aRect(aMenuPos, Size(1, 1));
1966 weld::Window* pPopupParent = weld::GetPopupParent(*this, aRect);
1967 std::unique_ptr<weld::Builder> xBuilder(Application::CreateBuilder(pPopupParent, "dbaccess/ui/queryfuncmenu.ui"));
1968 std::unique_ptr<weld::Menu> xContextMenu(xBuilder->weld_menu("menu"));
1969 xContextMenu->set_active("functions", m_bVisibleRow[BROW_FUNCTION_ROW]);
1970 xContextMenu->set_active("tablename", m_bVisibleRow[BROW_TABLE_ROW]);
1971 xContextMenu->set_active("alias", m_bVisibleRow[BROW_COLUMNALIAS_ROW]);
1972 xContextMenu->set_active("distinct", static_cast<OQueryController&>(getDesignView()->getController()).isDistinct());
1974 OUString sIdent = xContextMenu->popup_at_rect(pPopupParent, aRect);
1975 if (sIdent == "functions")
1977 SetRowVisible(BROW_FUNCTION_ROW, !IsRowVisible(BROW_FUNCTION_ROW));
1978 static_cast<OQueryController&>(getDesignView()->getController()).InvalidateFeature( SID_QUERY_VIEW_FUNCTIONS );
1980 else if (sIdent == "tablename")
1982 SetRowVisible(BROW_TABLE_ROW, !IsRowVisible(BROW_TABLE_ROW));
1983 static_cast<OQueryController&>(getDesignView()->getController()).InvalidateFeature( SID_QUERY_VIEW_TABLES );
1985 else if (sIdent == "alias")
1987 SetRowVisible(BROW_COLUMNALIAS_ROW, !IsRowVisible(BROW_COLUMNALIAS_ROW));
1988 static_cast<OQueryController&>(getDesignView()->getController()).InvalidateFeature( SID_QUERY_VIEW_ALIASES );
1990 else if (sIdent == "distinct")
1992 static_cast<OQueryController&>(getDesignView()->getController()).setDistinct(!static_cast<OQueryController&>(getDesignView()->getController()).isDistinct());
1993 static_cast<OQueryController&>(getDesignView()->getController()).setModified( true );
1994 static_cast<OQueryController&>(getDesignView()->getController()).InvalidateFeature( SID_QUERY_DISTINCT_VALUES );
1997 static_cast<OQueryController&>(getDesignView()->getController()).setModified( true );
2000 else
2002 EditBrowseBox::Command(rEvt);
2003 return;
2006 [[fallthrough]];
2008 default:
2009 EditBrowseBox::Command(rEvt);
2013 bool OSelectionBrowseBox::IsRowVisible(sal_uInt16 _nWhich) const
2015 OSL_ENSURE(_nWhich<(m_bVisibleRow.size()), "OSelectionBrowseBox::IsRowVisible : invalid parameter !");
2016 return m_bVisibleRow[_nWhich];
2019 void OSelectionBrowseBox::SetRowVisible(sal_uInt16 _nWhich, bool _bVis)
2021 OSL_ENSURE(_nWhich<m_bVisibleRow.size(), "OSelectionBrowseBox::SetRowVisible : invalid parameter !");
2023 bool bWasEditing = IsEditing();
2024 if (bWasEditing)
2025 DeactivateCell();
2027 // do this before removing or inserting rows, as this triggers ActivateCell-calls, which rely on m_bVisibleRow
2028 m_bVisibleRow[_nWhich] = !m_bVisibleRow[_nWhich];
2030 tools::Long nId = GetBrowseRow(_nWhich);
2031 if (_bVis)
2033 RowInserted(nId);
2034 ++m_nVisibleCount;
2036 else
2038 RowRemoved(nId);
2039 --m_nVisibleCount;
2042 if (bWasEditing)
2043 ActivateCell();
2046 sal_Int32 OSelectionBrowseBox::GetBrowseRow(sal_Int32 nRowId) const
2048 sal_Int32 nCount(0);
2049 for(sal_Int32 i = 0 ; i < nRowId ; ++i)
2051 if ( m_bVisibleRow[i] )
2052 ++nCount;
2054 return nCount;
2057 sal_Int32 OSelectionBrowseBox::GetRealRow(sal_Int32 nRowId) const
2059 sal_Int32 nErg=0,i;
2060 const sal_Int32 nCount = m_bVisibleRow.size();
2061 for(i=0;i < nCount; ++i)
2063 if(m_bVisibleRow[i] && nErg++ == nRowId)
2064 break;
2066 OSL_ENSURE(nErg <= tools::Long(m_bVisibleRow.size()),"nErg cannot be greater than BROW_ROW_CNT!");
2067 return i;
2070 const tools::Long nVisibleRowMask[] =
2072 0x0001,
2073 0x0002,
2074 0x0004,
2075 0x0008,
2076 0x0010,
2077 0x0020,
2078 0x0040,
2079 0x0080,
2080 0x0100,
2081 0x0200,
2082 0x0400,
2083 0x0800
2085 sal_Int32 OSelectionBrowseBox::GetNoneVisibleRows() const
2087 sal_Int32 nErg(0);
2088 // only the first 11 rows are interesting
2089 std::size_t const nSize = std::size(nVisibleRowMask);
2090 for(std::size_t i=0;i<nSize;i++)
2092 if(!m_bVisibleRow[i])
2093 nErg |= nVisibleRowMask[i];
2095 return nErg;
2098 void OSelectionBrowseBox::SetNoneVisibleRow(sal_Int32 nRows)
2100 // only the first 11 rows are interesting
2101 std::size_t const nSize = std::size(nVisibleRowMask);
2102 for(std::size_t i=0;i< nSize;i++)
2103 m_bVisibleRow[i] = !(nRows & nVisibleRowMask[i]);
2106 OUString OSelectionBrowseBox::GetCellText(sal_Int32 nRow, sal_uInt16 nColId) const
2109 sal_uInt16 nPos = GetColumnPos(nColId);
2110 if ( nPos == 0 || nPos == BROWSER_INVALIDID || nPos > getFields().size() )
2111 return OUString();
2113 OTableFieldDescRef pEntry = getFields()[nPos-1];
2114 OSL_ENSURE(pEntry != nullptr, "OSelectionBrowseBox::GetCellText : invalid column id, prepare for GPF ... ");
2115 if ( pEntry->IsEmpty() )
2116 return OUString();
2118 OUString aText;
2119 switch (nRow)
2121 case BROW_TABLE_ROW:
2122 aText = pEntry->GetAlias();
2123 break;
2124 case BROW_FIELD_ROW:
2126 OUString aField = pEntry->GetField();
2127 if (!aField.isEmpty() && aField[0] == '*') // * replace with alias.*
2129 aField = pEntry->GetAlias();
2130 if(!aField.isEmpty())
2131 aField += ".";
2132 aField += "*";
2134 aText = aField;
2135 } break;
2136 case BROW_ORDER_ROW:
2137 if (pEntry->GetOrderDir() != ORDER_NONE)
2138 aText = DBA_RES(STR_QUERY_SORTTEXT).getToken(sal::static_int_cast< sal_uInt16 >(pEntry->GetOrderDir()), ';');
2139 break;
2140 case BROW_VIS_ROW:
2141 break;
2142 case BROW_COLUMNALIAS_ROW:
2143 aText = pEntry->GetFieldAlias();
2144 break;
2145 case BROW_FUNCTION_ROW:
2146 // we always show the group function at first
2147 if ( pEntry->IsGroupBy() )
2148 aText = m_aFunctionStrings.copy(m_aFunctionStrings.lastIndexOf(';')+1);
2149 else if ( pEntry->isNumericOrAggregateFunction() )
2150 aText = pEntry->GetFunction();
2151 break;
2152 default:
2153 aText = pEntry->GetCriteria(sal_uInt16(nRow - BROW_CRIT1_ROW));
2155 return aText;
2158 bool OSelectionBrowseBox::GetFunctionName(sal_uInt32 _nFunctionTokenId, OUString& rFkt)
2160 weld::ComboBox& rComboBox = m_pFunctionCell->get_widget();
2161 switch(_nFunctionTokenId)
2163 case SQL_TOKEN_COUNT:
2164 rFkt = (rComboBox.get_count() < 3) ? rComboBox.get_text(1) : rComboBox.get_text(2);
2165 break;
2166 case SQL_TOKEN_AVG:
2167 rFkt = rComboBox.get_text(1);
2168 break;
2169 case SQL_TOKEN_MAX:
2170 rFkt = rComboBox.get_text(3);
2171 break;
2172 case SQL_TOKEN_MIN:
2173 rFkt = rComboBox.get_text(4);
2174 break;
2175 case SQL_TOKEN_SUM:
2176 rFkt = rComboBox.get_text(5);
2177 break;
2178 case SQL_TOKEN_EVERY:
2179 rFkt = rComboBox.get_text(6);
2180 break;
2181 case SQL_TOKEN_ANY:
2182 rFkt = rComboBox.get_text(7);
2183 break;
2184 case SQL_TOKEN_SOME:
2185 rFkt = rComboBox.get_text(8);
2186 break;
2187 case SQL_TOKEN_STDDEV_POP:
2188 rFkt = rComboBox.get_text(9);
2189 break;
2190 case SQL_TOKEN_STDDEV_SAMP:
2191 rFkt = rComboBox.get_text(10);
2192 break;
2193 case SQL_TOKEN_VAR_SAMP:
2194 rFkt = rComboBox.get_text(11);
2195 break;
2196 case SQL_TOKEN_VAR_POP:
2197 rFkt = rComboBox.get_text(12);
2198 break;
2199 case SQL_TOKEN_COLLECT:
2200 rFkt = rComboBox.get_text(13);
2201 break;
2202 case SQL_TOKEN_FUSION:
2203 rFkt = rComboBox.get_text(14);
2204 break;
2205 case SQL_TOKEN_INTERSECTION:
2206 rFkt = rComboBox.get_text(15);
2207 break;
2208 default:
2210 const sal_Int32 nStopIdx = m_aFunctionStrings.lastIndexOf(';'); // grouping is not counted
2211 for (sal_Int32 nIdx {0}; nIdx<nStopIdx;)
2213 const OUString sFunc {m_aFunctionStrings.getToken(0, ';', nIdx)};
2214 if (rFkt.equalsIgnoreAsciiCase(sFunc))
2216 rFkt = sFunc;
2217 return true;
2220 return false;
2224 return true;
2227 OUString OSelectionBrowseBox::GetCellContents(sal_Int32 nCellIndex, sal_uInt16 nColId)
2229 if ( GetCurColumnId() == nColId && !m_bInUndoMode )
2230 SaveModified();
2232 sal_uInt16 nPos = GetColumnPos(nColId);
2233 OTableFieldDescRef pEntry = getFields()[nPos - 1];
2234 OSL_ENSURE(pEntry != nullptr, "OSelectionBrowseBox::GetCellContents : invalid column id, prepare for GPF ... ");
2236 switch (nCellIndex)
2238 case BROW_VIS_ROW :
2239 return OUString(pEntry->IsVisible() ? std::u16string_view(u"1") : std::u16string_view(u"0"));
2240 case BROW_ORDER_ROW:
2242 sal_Int32 nIdx = m_pOrderCell->get_widget().get_active();
2243 if (nIdx == -1)
2244 nIdx = 0;
2245 return OUString::number(nIdx);
2247 default:
2248 return GetCellText(nCellIndex, nColId);
2252 void OSelectionBrowseBox::SetCellContents(sal_Int32 nRow, sal_uInt16 nColId, const OUString& strNewText)
2254 bool bWasEditing = IsEditing() && (GetCurColumnId() == nColId) && IsRowVisible(static_cast<sal_uInt16>(nRow)) && (GetCurRow() == static_cast<sal_uInt16>(GetBrowseRow(nRow)));
2255 if (bWasEditing)
2256 DeactivateCell();
2258 sal_uInt16 nPos = GetColumnPos(nColId);
2259 OTableFieldDescRef pEntry = getEntry(nPos - 1);
2260 OSL_ENSURE(pEntry != nullptr, "OSelectionBrowseBox::SetCellContents : invalid column id, prepare for GPF ... ");
2262 switch (nRow)
2264 case BROW_VIS_ROW:
2265 pEntry->SetVisible(strNewText == "1");
2266 break;
2267 case BROW_FIELD_ROW:
2268 pEntry->SetField(strNewText);
2269 break;
2270 case BROW_TABLE_ROW:
2271 pEntry->SetAlias(strNewText);
2272 break;
2273 case BROW_ORDER_ROW:
2275 sal_uInt16 nIdx = static_cast<sal_uInt16>(strNewText.toInt32());
2276 pEntry->SetOrderDir(EOrderDir(nIdx));
2277 } break;
2278 case BROW_COLUMNALIAS_ROW:
2279 pEntry->SetFieldAlias(strNewText);
2280 break;
2281 case BROW_FUNCTION_ROW:
2283 std::u16string_view sGroupFunctionName = m_aFunctionStrings.subView(m_aFunctionStrings.lastIndexOf(';')+1);
2284 pEntry->SetFunction(strNewText);
2285 // first reset this two member
2286 sal_Int32 nFunctionType = pEntry->GetFunctionType();
2287 nFunctionType &= ~FKT_AGGREGATE;
2288 pEntry->SetFunctionType(nFunctionType);
2289 if ( pEntry->IsGroupBy() && !o3tl::equalsIgnoreAsciiCase(sGroupFunctionName, strNewText) )
2290 pEntry->SetGroupBy(false);
2292 if ( o3tl::equalsIgnoreAsciiCase(sGroupFunctionName, strNewText) )
2293 pEntry->SetGroupBy(true);
2294 else if ( !strNewText.isEmpty() )
2296 nFunctionType |= FKT_AGGREGATE;
2297 pEntry->SetFunctionType(nFunctionType);
2299 } break;
2300 default:
2301 pEntry->SetCriteria(sal_uInt16(nRow - BROW_CRIT1_ROW), strNewText);
2304 tools::Long nCellIndex = GetRealRow(nRow);
2305 if(IsRowVisible(static_cast<sal_uInt16>(nRow)))
2306 RowModified(nCellIndex, nColId);
2308 // the appropriate field-description is now empty -> set Visible to sal_False (now it is consistent to normal empty rows)
2309 if (pEntry->IsEmpty())
2310 pEntry->SetVisible(false);
2312 if (bWasEditing)
2313 ActivateCell(nCellIndex, nColId);
2315 static_cast<OQueryController&>(getDesignView()->getController()).setModified( true );
2318 void OSelectionBrowseBox::ColumnResized(sal_uInt16 nColId)
2320 if (static_cast<OQueryController&>(getDesignView()->getController()).isReadOnly())
2321 return;
2322 // The resizing of columns can't be suppressed (BrowseBox doesn't support that) so we have to do this
2323 // fake. It's not _that_ bad : the user may change column widths while in read-only mode to see all details
2324 // but the changes aren't permanent ...
2326 sal_uInt16 nPos = GetColumnPos(nColId);
2327 OSL_ENSURE(nPos <= getFields().size(),"ColumnResized:: nColId should not be greater than List::count!");
2328 OTableFieldDescRef pEntry = getEntry(nPos-1);
2329 OSL_ENSURE(pEntry.is(), "OSelectionBrowseBox::ColumnResized : invalid FieldDescription !");
2330 static_cast<OQueryController&>(getDesignView()->getController()).setModified( true );
2331 EditBrowseBox::ColumnResized(nColId);
2333 if ( pEntry.is())
2335 if ( !m_bInUndoMode )
2337 // create the undo action
2338 std::unique_ptr<OTabFieldSizedUndoAct> pUndo(new OTabFieldSizedUndoAct(this));
2339 pUndo->SetColumnPosition( nPos );
2340 pUndo->SetOriginalWidth(pEntry->GetColWidth());
2341 getDesignView()->getController().addUndoActionAndInvalidate(std::move(pUndo));
2343 pEntry->SetColWidth(sal_uInt16(GetColumnWidth(nColId)));
2347 sal_uInt32 OSelectionBrowseBox::GetTotalCellWidth(sal_Int32 nRowId, sal_uInt16 nColId)
2349 sal_uInt16 nPos = GetColumnPos(nColId);
2350 OSL_ENSURE((nPos == 0) || (nPos <= getFields().size()), "OSelectionBrowseBox::GetTotalCellWidth : invalid parameter nColId");
2352 OTableFieldDescRef pEntry = getFields()[nPos-1];
2353 OSL_ENSURE(pEntry.is(), "OSelectionBrowseBox::GetTotalCellWidth : invalid FieldDescription !");
2355 sal_Int32 nRow = GetRealRow(nRowId);
2356 OUString strText(GetCellText(nRow, nColId));
2357 return GetDataWindow().LogicToPixel(Size(GetDataWindow().GetTextWidth(strText),0)).Width();
2360 bool OSelectionBrowseBox::isCutAllowed() const
2362 bool bCutAllowed = false;
2363 sal_Int32 nRow = GetRealRow(GetCurRow());
2364 switch (nRow)
2366 case BROW_VIS_ROW:
2367 case BROW_ORDER_ROW:
2368 case BROW_TABLE_ROW:
2369 case BROW_FUNCTION_ROW:
2370 break;
2371 case BROW_FIELD_ROW:
2373 weld::ComboBox& rComboBox = m_pFieldCell->get_widget();
2374 int nStartPos, nEndPos;
2375 bCutAllowed = rComboBox.get_entry_selection_bounds(nStartPos, nEndPos);
2376 break;
2378 default:
2380 weld::Entry& rEntry = m_pTextCell->get_widget();
2381 int nStartPos, nEndPos;
2382 bCutAllowed = rEntry.get_selection_bounds(nStartPos, nEndPos);
2383 break;
2386 return bCutAllowed;
2389 void OSelectionBrowseBox::cut()
2391 sal_Int32 nRow = GetRealRow(GetCurRow());
2392 switch (nRow)
2394 case BROW_FIELD_ROW:
2396 weld::ComboBox& rComboBox = m_pFieldCell->get_widget();
2397 rComboBox.cut_entry_clipboard();
2398 break;
2400 default:
2402 weld::Entry& rEntry = m_pTextCell->get_widget();
2403 rEntry.cut_clipboard();
2406 SaveModified();
2407 RowModified(GetBrowseRow(nRow), GetCurColumnId());
2409 invalidateUndoRedo();
2412 void OSelectionBrowseBox::paste()
2414 sal_Int32 nRow = GetRealRow(GetCurRow());
2415 switch (nRow)
2417 case BROW_FIELD_ROW:
2419 weld::ComboBox& rComboBox = m_pFieldCell->get_widget();
2420 rComboBox.paste_entry_clipboard();
2421 break;
2423 default:
2425 weld::Entry& rEntry = m_pTextCell->get_widget();
2426 rEntry.paste_clipboard();
2427 break;
2430 RowModified(GetBrowseRow(nRow), GetCurColumnId());
2431 invalidateUndoRedo();
2434 bool OSelectionBrowseBox::isPasteAllowed() const
2436 bool bPasteAllowed = true;
2437 sal_Int32 nRow = GetRealRow(GetCurRow());
2438 switch (nRow)
2440 case BROW_VIS_ROW:
2441 case BROW_ORDER_ROW:
2442 case BROW_TABLE_ROW:
2443 case BROW_FUNCTION_ROW:
2444 bPasteAllowed = false;
2445 break;
2447 return bPasteAllowed;
2450 bool OSelectionBrowseBox::isCopyAllowed() const
2452 return isCutAllowed();
2455 void OSelectionBrowseBox::copy()
2457 sal_Int32 nRow = GetRealRow(GetCurRow());
2458 switch (nRow)
2460 case BROW_FIELD_ROW:
2462 weld::ComboBox& rComboBox = m_pFieldCell->get_widget();
2463 rComboBox.copy_entry_clipboard();
2464 break;
2466 default:
2468 weld::Entry& rEntry = m_pTextCell->get_widget();
2469 rEntry.copy_clipboard();
2470 break;
2475 void OSelectionBrowseBox::appendUndoAction(const OUString& _rOldValue, std::u16string_view _rNewValue, sal_Int32 _nRow, bool& _bListAction)
2477 if ( !m_bInUndoMode && _rNewValue != _rOldValue )
2479 if ( !_bListAction )
2481 _bListAction = true;
2482 static_cast<OQueryController&>(getDesignView()->getController()).GetUndoManager().EnterListAction(OUString(),OUString(),0,ViewShellId(-1));
2484 appendUndoAction(_rOldValue,_rNewValue,_nRow);
2488 void OSelectionBrowseBox::appendUndoAction(const OUString& _rOldValue,std::u16string_view _rNewValue,sal_Int32 _nRow)
2490 if ( !m_bInUndoMode && _rNewValue != _rOldValue )
2492 std::unique_ptr<OTabFieldCellModifiedUndoAct> pUndoAct(new OTabFieldCellModifiedUndoAct(this));
2493 pUndoAct->SetCellIndex(_nRow);
2494 OSL_ENSURE(GetColumnPos(GetCurColumnId()) != BROWSER_INVALIDID,"Current position isn't valid!");
2495 pUndoAct->SetColumnPosition( GetColumnPos(GetCurColumnId()) );
2496 pUndoAct->SetCellContents(_rOldValue);
2497 getDesignView()->getController().addUndoActionAndInvalidate(std::move(pUndoAct));
2501 IMPL_LINK_NOARG(OSelectionBrowseBox, OnInvalidateTimer, Timer *, void)
2503 static_cast<OQueryController&>(getDesignView()->getController()).InvalidateFeature(SID_CUT);
2504 static_cast<OQueryController&>(getDesignView()->getController()).InvalidateFeature(SID_COPY);
2505 static_cast<OQueryController&>(getDesignView()->getController()).InvalidateFeature(SID_PASTE);
2506 if(!m_bStopTimer)
2507 m_timerInvalidate.Start();
2510 void OSelectionBrowseBox::stopTimer()
2512 m_bStopTimer = true;
2513 if (m_timerInvalidate.IsActive())
2514 m_timerInvalidate.Stop();
2517 void OSelectionBrowseBox::startTimer()
2519 m_bStopTimer = false;
2520 if (!m_timerInvalidate.IsActive())
2521 m_timerInvalidate.Start();
2524 OTableFields& OSelectionBrowseBox::getFields() const
2526 OQueryController& rController = static_cast<OQueryController&>(getDesignView()->getController());
2527 return rController.getTableFieldDesc();
2530 void OSelectionBrowseBox::enableControl(const OTableFieldDescRef& _rEntry,Window* _pControl)
2532 bool bEnable = !_rEntry->isCondition();
2533 _pControl->Enable(bEnable);
2534 _pControl->EnableInput(bEnable);
2537 void OSelectionBrowseBox::setTextCellContext(const OTableFieldDescRef& _rEntry,const OUString& _sText,const OUString& _sHelpId)
2539 weld::Entry& rEntry = m_pTextCell->get_widget();
2540 rEntry.set_text(_sText);
2541 rEntry.save_value();
2542 if (!m_pTextCell->HasFocus())
2543 m_pTextCell->GrabFocus();
2545 enableControl(_rEntry,m_pTextCell);
2547 if (m_pTextCell->GetHelpId() != _sHelpId)
2548 // as TextCell is used in various contexts I will delete the cached HelpText
2549 m_pTextCell->SetHelpText(OUString());
2550 m_pTextCell->SetHelpId(_sHelpId);
2553 void OSelectionBrowseBox::invalidateUndoRedo()
2555 OQueryController& rController = static_cast<OQueryController&>(getDesignView()->getController());
2556 rController.InvalidateFeature( ID_BROWSER_UNDO );
2557 rController.InvalidateFeature( ID_BROWSER_REDO );
2558 rController.InvalidateFeature( ID_BROWSER_QUERY_EXECUTE );
2561 OTableFieldDescRef OSelectionBrowseBox::getEntry(OTableFields::size_type _nPos)
2563 // we have to check if we need a new entry at this position
2564 OTableFields& aFields = getFields();
2565 OSL_ENSURE(aFields.size() > _nPos,"ColID is to great!");
2567 OTableFieldDescRef pEntry = aFields[_nPos];
2568 OSL_ENSURE(pEntry.is(),"Invalid entry!");
2569 if ( !pEntry.is() )
2571 pEntry = new OTableFieldDesc();
2572 pEntry->SetColumnId(
2573 GetColumnId(sal::static_int_cast< sal_uInt16 >(_nPos+1)));
2574 aFields[_nPos] = pEntry;
2576 return pEntry;
2579 void OSelectionBrowseBox::GetFocus()
2581 if(!IsEditing() && !m_bWasEditing)
2582 ActivateCell();
2583 EditBrowseBox::GetFocus();
2586 void OSelectionBrowseBox::DeactivateCell(bool _bUpdate)
2588 m_bWasEditing = true;
2589 EditBrowseBox::DeactivateCell(_bUpdate);
2590 m_bWasEditing = false;
2593 OUString OSelectionBrowseBox::GetRowDescription( sal_Int32 _nRow ) const
2595 OUString aLabel(DBA_RES(STR_QUERY_HANDLETEXT));
2597 // from BROW_CRIT2_ROW onwards all rows are shown as "or"
2598 sal_Int32 nToken = (_nRow >= GetBrowseRow(BROW_CRIT2_ROW))
2599 ? BROW_CRIT2_ROW : GetRealRow(_nRow);
2600 return aLabel.getToken(nToken, ';');
2603 OUString OSelectionBrowseBox::GetAccessibleObjectName( AccessibleBrowseBoxObjType _eObjType,sal_Int32 _nPosition) const
2605 OUString sRetText;
2606 switch( _eObjType )
2608 case AccessibleBrowseBoxObjType::RowHeaderCell:
2609 sRetText = GetRowDescription(_nPosition);
2610 break;
2611 default:
2612 sRetText = EditBrowseBox::GetAccessibleObjectDescription(_eObjType,_nPosition);
2614 return sRetText;
2617 bool OSelectionBrowseBox::fillEntryTable(OTableFieldDescRef const & _pEntry,const OUString& _sTableName)
2619 bool bRet = false;
2620 OJoinTableView::OTableWindowMap& rTabWinList = getDesignView()->getTableView()->GetTabWinMap();
2621 OJoinTableView::OTableWindowMap::const_iterator aIter = rTabWinList.find(_sTableName);
2622 if(aIter != rTabWinList.end())
2624 OQueryTableWindow* pEntryTab = static_cast<OQueryTableWindow*>(aIter->second.get());
2625 if (pEntryTab)
2627 _pEntry->SetTable(pEntryTab->GetTableName());
2628 _pEntry->SetTabWindow(pEntryTab);
2629 bRet = true;
2632 return bRet;
2635 void OSelectionBrowseBox::setFunctionCell(OTableFieldDescRef const & _pEntry)
2637 Reference< XConnection> xConnection = static_cast<OQueryController&>(getDesignView()->getController()).getConnection();
2638 if ( !xConnection.is() )
2639 return;
2641 // Aggregate functions in general only available with Core SQL
2642 if ( lcl_SupportsCoreSQLGrammar(xConnection) )
2644 sal_Int32 nIdx {0};
2645 // if we have an asterisk, no other function than count is allowed
2646 weld::ComboBox& rComboBox = m_pFunctionCell->get_widget();
2647 rComboBox.clear();
2648 rComboBox.append_text(m_aFunctionStrings.getToken(0, ';', nIdx));
2649 if ( isFieldNameAsterisk(_pEntry->GetField()) )
2650 rComboBox.append_text(m_aFunctionStrings.getToken(1, ';', nIdx)); // 2nd token: COUNT
2651 else
2653 const bool bSkipLastToken {_pEntry->isNumeric()};
2654 while (nIdx>0)
2656 const OUString sTok {m_aFunctionStrings.getToken(0, ';', nIdx)};
2657 if (bSkipLastToken && nIdx<0)
2658 break;
2659 rComboBox.append_text(sTok);
2663 if ( _pEntry->IsGroupBy() )
2665 OSL_ENSURE(!_pEntry->isNumeric(),"Not allowed to combine group by and numeric values!");
2666 rComboBox.set_active_text(rComboBox.get_text(rComboBox.get_count() - 1));
2668 else if (rComboBox.find_text(_pEntry->GetFunction()) != -1)
2669 rComboBox.set_active_text(_pEntry->GetFunction());
2670 else
2671 rComboBox.set_active(0);
2673 enableControl(_pEntry, m_pFunctionCell);
2675 else
2677 // only COUNT(*) and COUNT("table".*) allowed
2678 bool bCountRemoved = !isFieldNameAsterisk(_pEntry->GetField());
2679 weld::ComboBox& rComboBox = m_pFunctionCell->get_widget();
2680 if ( bCountRemoved )
2681 rComboBox.remove(1);
2683 if ( !bCountRemoved && rComboBox.get_count() < 2)
2684 rComboBox.append_text(m_aFunctionStrings.getToken(2, ';')); // 2 -> COUNT
2686 if (rComboBox.find_text(_pEntry->GetFunction()) != -1)
2687 rComboBox.set_active_text(_pEntry->GetFunction());
2688 else
2689 rComboBox.set_active(0);
2693 Reference< XAccessible > OSelectionBrowseBox::CreateAccessibleCell( sal_Int32 _nRow, sal_uInt16 _nColumnPos )
2695 OTableFieldDescRef pEntry;
2696 if ( _nColumnPos != 0 && _nColumnPos != BROWSER_INVALIDID && _nColumnPos <= getFields().size() )
2697 pEntry = getFields()[_nColumnPos - 1];
2699 if ( _nRow == BROW_VIS_ROW && pEntry.is() )
2700 return EditBrowseBox::CreateAccessibleCheckBoxCell( _nRow, _nColumnPos,pEntry->IsVisible() ? TRISTATE_TRUE : TRISTATE_FALSE );
2702 return EditBrowseBox::CreateAccessibleCell( _nRow, _nColumnPos );
2705 bool OSelectionBrowseBox::HasFieldByAliasName(std::u16string_view rFieldName, OTableFieldDescRef const & rInfo) const
2707 for (auto const& field : getFields())
2709 if ( field->GetFieldAlias() == rFieldName )
2711 *rInfo = *field;
2712 return true;
2715 return false;
2718 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */