bump product version to 6.3.0.0.beta1
[LibreOffice.git] / reportdesign / source / ui / dlg / GroupsSorting.cxx
blob84e5c626b1238f5ebf5a55a2ab6d4006f379b2ef
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 .
19 #include <GroupsSorting.hxx>
20 #include <connectivity/dbtools.hxx>
21 #include <sot/exchange.hxx>
22 #include <svtools/editbrowsebox.hxx>
23 #include <svtools/imgdef.hxx>
24 #include <com/sun/star/beans/XPropertySet.hpp>
25 #include <com/sun/star/container/XContainerListener.hpp>
26 #include <com/sun/star/report/GroupOn.hpp>
27 #include <com/sun/star/sdbc/DataType.hpp>
29 #include <strings.hrc>
30 #include <rptui_slotid.hrc>
31 #include <core_resource.hxx>
32 #include <helpids.h>
33 #include "GroupExchange.hxx"
34 #include <UITools.hxx>
35 #include <UndoActions.hxx>
36 #include <strings.hxx>
37 #include <ReportController.hxx>
38 #include <ColumnInfo.hxx>
40 #include <cppuhelper/implbase.hxx>
41 #include <comphelper/property.hxx>
42 #include <vcl/settings.hxx>
44 #include <algorithm>
46 #include <cppuhelper/bootstrap.hxx>
48 #define HANDLE_ID 0
49 #define FIELD_EXPRESSION 1
50 #define GROUPS_START_LEN 5
51 #define NO_GROUP -1
53 namespace rptui
55 using namespace ::com::sun::star;
56 using namespace svt;
57 using namespace ::comphelper;
59 static void lcl_addToList_throw( ComboBoxControl& _rListBox, ::std::vector<ColumnInfo>& o_aColumnList,const uno::Reference< container::XNameAccess>& i_xColumns )
61 uno::Sequence< OUString > aEntries = i_xColumns->getElementNames();
62 const OUString* pEntries = aEntries.getConstArray();
63 sal_Int32 nEntries = aEntries.getLength();
64 for ( sal_Int32 i = 0; i < nEntries; ++i, ++pEntries )
66 uno::Reference< beans::XPropertySet> xColumn(i_xColumns->getByName(*pEntries),uno::UNO_QUERY_THROW);
67 OUString sLabel;
68 if ( xColumn->getPropertySetInfo()->hasPropertyByName(PROPERTY_LABEL) )
69 xColumn->getPropertyValue(PROPERTY_LABEL) >>= sLabel;
70 o_aColumnList.emplace_back(*pEntries,sLabel );
71 if ( !sLabel.isEmpty() )
72 _rListBox.InsertEntry( sLabel );
73 else
74 _rListBox.InsertEntry( *pEntries );
78 /**
79 * Separated out from OFieldExpressionControl to prevent collision of ref-counted base classes
81 class OFieldExpressionControl;
82 class OFieldExpressionControlContainerListener : public ::cppu::WeakImplHelper< container::XContainerListener >
84 VclPtr<OFieldExpressionControl> mpParent;
85 public:
86 explicit OFieldExpressionControlContainerListener(OFieldExpressionControl* pParent) : mpParent(pParent) {}
88 // XEventListener
89 virtual void SAL_CALL disposing(const css::lang::EventObject& Source) override;
90 // XContainerListener
91 virtual void SAL_CALL elementInserted(const css::container::ContainerEvent& rEvent) override;
92 virtual void SAL_CALL elementReplaced(const css::container::ContainerEvent& rEvent) override;
93 virtual void SAL_CALL elementRemoved(const css::container::ContainerEvent& rEvent) override;
96 class OFieldExpressionControl : public ::svt::EditBrowseBox
98 ::osl::Mutex m_aMutex;
99 ::std::vector<sal_Int32> m_aGroupPositions;
100 ::std::vector<ColumnInfo> m_aColumnInfo;
101 VclPtr< ::svt::ComboBoxControl> m_pComboCell;
102 sal_Int32 m_nDataPos;
103 sal_Int32 m_nCurrentPos;
104 ImplSVEvent * m_nDeleteEvent;
105 VclPtr<OGroupsSortingDialog> m_pParent;
106 bool m_bIgnoreEvent;
107 rtl::Reference<OFieldExpressionControlContainerListener> aContainerListener;
109 public:
110 OFieldExpressionControl(OGroupsSortingDialog* _pParentDialog, vcl::Window *_pParent);
111 virtual ~OFieldExpressionControl() override;
112 virtual void dispose() override;
114 // XContainerListener
115 /// @throws css::uno::RuntimeException
116 void elementInserted(const css::container::ContainerEvent& rEvent);
117 /// @throws css::uno::RuntimeException
118 void elementRemoved(const css::container::ContainerEvent& rEvent);
120 virtual Size GetOptimalSize() const override;
122 void fillColumns(const uno::Reference< container::XNameAccess>& _xColumns);
123 void lateInit();
124 bool IsDeleteAllowed( );
125 void DeleteRows();
127 sal_Int32 getGroupPosition(sal_Int32 _nRow) const { return _nRow != BROWSER_ENDOFSELECTION ? m_aGroupPositions[_nRow] : sal_Int32(NO_GROUP); }
129 ::svt::ComboBoxControl* getExpressionControl() const { return m_pComboCell; }
131 /** returns the sequence with the selected groups
133 uno::Sequence<uno::Any> fillSelectedGroups();
135 /** move groups given by _aGroups
137 void moveGroups(const uno::Sequence<uno::Any>& _aGroups,sal_Int32 _nRow,bool _bSelect = true);
139 virtual bool CursorMoving(long nNewRow, sal_uInt16 nNewCol) override;
140 using ::svt::EditBrowseBox::GetRowCount;
141 protected:
142 virtual bool IsTabAllowed(bool bForward) const override;
144 virtual void InitController( ::svt::CellControllerRef& rController, long nRow, sal_uInt16 nCol ) override;
145 virtual ::svt::CellController* GetController( long nRow, sal_uInt16 nCol ) override;
146 virtual void PaintCell( OutputDevice& rDev, const tools::Rectangle& rRect, sal_uInt16 nColId ) const override;
147 virtual bool SeekRow( long nRow ) override;
148 virtual bool SaveModified() override;
149 virtual OUString GetCellText( long nRow, sal_uInt16 nColId ) const override;
150 virtual RowStatus GetRowStatus(long nRow) const override;
152 virtual void KeyInput(const KeyEvent& rEvt) override;
153 virtual void Command( const CommandEvent& rEvt ) override;
155 // D&D
156 virtual void StartDrag( sal_Int8 nAction, const Point& rPosPixel ) override;
157 virtual sal_Int8 AcceptDrop( const BrowserAcceptDropEvent& rEvt ) override;
158 virtual sal_Int8 ExecuteDrop( const BrowserExecuteDropEvent& rEvt ) override;
160 using BrowseBox::AcceptDrop;
161 using BrowseBox::ExecuteDrop;
163 private:
165 DECL_LINK( CBChangeHdl, ComboBox&, void);
167 public:
168 DECL_LINK( DelayedDelete, void*, void );
173 void OFieldExpressionControlContainerListener::disposing(const css::lang::EventObject& )
176 void OFieldExpressionControlContainerListener::elementInserted(const css::container::ContainerEvent& rEvent)
177 { mpParent->elementInserted(rEvent); }
179 void OFieldExpressionControlContainerListener::elementReplaced(const css::container::ContainerEvent& )
182 void OFieldExpressionControlContainerListener::elementRemoved(const css::container::ContainerEvent& rEvent)
183 { mpParent->elementRemoved(rEvent); }
186 // class OFieldExpressionControl
187 OFieldExpressionControl::OFieldExpressionControl(OGroupsSortingDialog* _pParentDialog, vcl::Window *_pParent)
188 :EditBrowseBox( _pParent, EditBrowseBoxFlags::NONE, WB_TABSTOP,
189 BrowserMode::COLUMNSELECTION | BrowserMode::MULTISELECTION | BrowserMode::AUTOSIZE_LASTCOL |
190 BrowserMode::KEEPHIGHLIGHT | BrowserMode::HLINES | BrowserMode::VLINES)
191 ,m_aGroupPositions(GROUPS_START_LEN,-1)
192 ,m_pComboCell(nullptr)
193 ,m_nDataPos(-1)
194 ,m_nCurrentPos(-1)
195 ,m_nDeleteEvent(nullptr)
196 ,m_pParent(_pParentDialog)
197 ,m_bIgnoreEvent(false)
198 ,aContainerListener(new OFieldExpressionControlContainerListener(this))
200 SetBorderStyle(WindowBorderStyle::MONO);
204 OFieldExpressionControl::~OFieldExpressionControl()
206 disposeOnce();
210 void OFieldExpressionControl::dispose()
212 uno::Reference< report::XGroups > xGroups = m_pParent->getGroups();
213 xGroups->removeContainerListener(aContainerListener.get());
215 // delete events from queue
216 if( m_nDeleteEvent )
217 Application::RemoveUserEvent( m_nDeleteEvent );
219 m_pComboCell.disposeAndClear();
220 m_pParent.clear();
221 ::svt::EditBrowseBox::dispose();
224 uno::Sequence<uno::Any> OFieldExpressionControl::fillSelectedGroups()
226 uno::Sequence<uno::Any> aList;
227 ::std::vector<uno::Any> vClipboardList;
228 vClipboardList.reserve(GetSelectRowCount());
230 uno::Reference<report::XGroups> xGroups = m_pParent->getGroups();
231 sal_Int32 nCount = xGroups->getCount();
232 if ( nCount >= 1 )
234 for( long nIndex=FirstSelectedRow(); nIndex != SFX_ENDOFSELECTION; nIndex=NextSelectedRow() )
238 if ( m_aGroupPositions[nIndex] != NO_GROUP )
240 uno::Reference< report::XGroup> xOrgGroup(xGroups->getByIndex(m_aGroupPositions[nIndex]),uno::UNO_QUERY);
241 /*uno::Reference< report::XGroup> xCopy = xGroups->createGroup();
242 ::comphelper::copyProperties(xOrgGroup.get(),xCopy.get());*/
243 vClipboardList.push_back( uno::makeAny(xOrgGroup) );
246 catch(uno::Exception&)
248 OSL_FAIL("Can not access group!");
251 if ( !vClipboardList.empty() )
252 aList = uno::Sequence< uno::Any >(vClipboardList.data(), vClipboardList.size());
254 return aList;
257 void OFieldExpressionControl::StartDrag( sal_Int8 /*_nAction*/ , const Point& /*_rPosPixel*/ )
259 if ( m_pParent && !m_pParent->isReadOnly( ) )
261 uno::Sequence<uno::Any> aClipboardList = fillSelectedGroups();
263 if( aClipboardList.hasElements() )
265 rtl::Reference<OGroupExchange> pData = new OGroupExchange(aClipboardList);
266 pData->StartDrag(this, DND_ACTION_MOVE );
271 sal_Int8 OFieldExpressionControl::AcceptDrop( const BrowserAcceptDropEvent& rEvt )
273 sal_Int8 nAction = DND_ACTION_NONE;
274 if ( IsEditing() )
276 sal_Int32 nPos = m_pComboCell->GetSelectedEntryPos();
277 if ( COMBOBOX_ENTRY_NOTFOUND != nPos || !m_pComboCell->GetText().isEmpty() )
278 SaveModified();
279 DeactivateCell();
281 if ( IsDropFormatSupported( OGroupExchange::getReportGroupId() ) && m_pParent->getGroups()->getCount() > 1 && rEvt.GetWindow() == &GetDataWindow() )
283 nAction = DND_ACTION_MOVE;
285 return nAction;
288 sal_Int8 OFieldExpressionControl::ExecuteDrop( const BrowserExecuteDropEvent& rEvt )
290 sal_Int8 nAction = DND_ACTION_NONE;
291 if ( IsDropFormatSupported( OGroupExchange::getReportGroupId() ) )
293 sal_Int32 nRow = GetRowAtYPosPixel(rEvt.maPosPixel.Y(), false);
294 SetNoSelection();
296 TransferableDataHelper aDropped( rEvt.maDropEvent.Transferable );
297 uno::Any aDrop = aDropped.GetAny(OGroupExchange::getReportGroupId(), OUString());
298 uno::Sequence< uno::Any > aGroups;
299 aDrop >>= aGroups;
300 if ( aGroups.hasElements() )
302 moveGroups(aGroups,nRow);
303 nAction = DND_ACTION_MOVE;
306 return nAction;
309 void OFieldExpressionControl::moveGroups(const uno::Sequence<uno::Any>& _aGroups,sal_Int32 _nRow,bool _bSelect)
311 if ( _aGroups.hasElements() )
313 m_bIgnoreEvent = true;
315 sal_Int32 nRow = _nRow;
316 const OUString sUndoAction(RptResId(RID_STR_UNDO_MOVE_GROUP));
317 const UndoContext aUndoContext( m_pParent->m_pController->getUndoManager(), sUndoAction );
319 uno::Reference< report::XGroups> xGroups = m_pParent->getGroups();
320 const uno::Any* pIter = _aGroups.getConstArray();
321 const uno::Any* pEnd = pIter + _aGroups.getLength();
322 for(;pIter != pEnd;++pIter)
324 uno::Reference< report::XGroup> xGroup(*pIter,uno::UNO_QUERY);
325 if ( xGroup.is() )
327 uno::Sequence< beans::PropertyValue > aArgs(1);
328 aArgs[0].Name = PROPERTY_GROUP;
329 aArgs[0].Value <<= xGroup;
330 // we use this way to create undo actions
331 m_pParent->m_pController->executeChecked(SID_GROUP_REMOVE,aArgs);
332 aArgs.realloc(2);
333 if ( nRow > xGroups->getCount() )
334 nRow = xGroups->getCount();
335 if ( _bSelect )
336 SelectRow(nRow);
337 aArgs[1].Name = PROPERTY_POSITIONY;
338 aArgs[1].Value <<= nRow;
339 m_pParent->m_pController->executeChecked(SID_GROUP_APPEND,aArgs);
340 ++nRow;
344 m_bIgnoreEvent = false;
345 Invalidate();
349 void OFieldExpressionControl::fillColumns(const uno::Reference< container::XNameAccess>& _xColumns)
351 m_pComboCell->Clear();
352 if ( _xColumns.is() )
353 lcl_addToList_throw(*m_pComboCell,m_aColumnInfo,_xColumns);
356 void OFieldExpressionControl::lateInit()
358 uno::Reference< report::XGroups > xGroups = m_pParent->getGroups();
359 sal_Int32 nGroupsCount = xGroups->getCount();
360 m_aGroupPositions.resize(::std::max<sal_Int32>(nGroupsCount,sal_Int32(GROUPS_START_LEN)),NO_GROUP);
361 ::std::vector<sal_Int32>::iterator aIter = m_aGroupPositions.begin();
362 for (sal_Int32 i = 0; i < nGroupsCount; ++i,++aIter)
363 *aIter = i;
365 if ( ColCount() == 0 )
367 vcl::Font aFont( GetDataWindow().GetFont() );
368 aFont.SetWeight( WEIGHT_NORMAL );
369 GetDataWindow().SetFont( aFont );
371 // Set font of the headline to light
372 aFont = GetFont();
373 aFont.SetWeight( WEIGHT_LIGHT );
374 SetFont(aFont);
376 InsertHandleColumn(static_cast<sal_uInt16>(GetTextWidth(OUString('0')) * 4)/*, sal_True */);
377 InsertDataColumn( FIELD_EXPRESSION, RptResId(STR_RPT_EXPRESSION), 100);
379 m_pComboCell = VclPtr<ComboBoxControl>::Create( &GetDataWindow() );
380 m_pComboCell->SetSelectHdl(LINK(this,OFieldExpressionControl,CBChangeHdl));
381 m_pComboCell->SetHelpId(HID_RPT_FIELDEXPRESSION);
383 m_pComboCell->SetGetFocusHdl(LINK(m_pParent, OGroupsSortingDialog, OnControlFocusGot));
384 m_pComboCell->SetLoseFocusHdl(LINK(m_pParent, OGroupsSortingDialog, OnControlFocusLost));
387 // set browse mode
388 BrowserMode nMode(BrowserMode::COLUMNSELECTION | BrowserMode::MULTISELECTION | BrowserMode::KEEPHIGHLIGHT |
389 BrowserMode::HLINES | BrowserMode::VLINES | BrowserMode::AUTOSIZE_LASTCOL | BrowserMode::AUTO_VSCROLL | BrowserMode::AUTO_HSCROLL);
390 if( m_pParent->isReadOnly() )
391 nMode |= BrowserMode::HIDECURSOR;
392 SetMode(nMode);
393 xGroups->addContainerListener(aContainerListener.get());
395 else
396 // not the first call
397 RowRemoved(0, GetRowCount());
399 RowInserted(0, m_aGroupPositions.size());
403 IMPL_LINK_NOARG( OFieldExpressionControl, CBChangeHdl, ComboBox&, void )
406 SaveModified();
410 bool OFieldExpressionControl::IsTabAllowed(bool /*bForward*/) const
412 return false;
416 bool OFieldExpressionControl::SaveModified()
418 sal_Int32 nRow = GetCurRow();
419 if ( nRow != BROWSER_ENDOFSELECTION )
423 bool bAppend = false;
424 uno::Reference< report::XGroup> xGroup;
425 if ( m_aGroupPositions[nRow] == NO_GROUP )
427 bAppend = true;
428 OUString sUndoAction(RptResId(RID_STR_UNDO_APPEND_GROUP));
429 m_pParent->m_pController->getUndoManager().EnterListAction( sUndoAction, OUString(), 0, ViewShellId(-1) );
430 xGroup = m_pParent->getGroups()->createGroup();
431 xGroup->setHeaderOn(true);
433 uno::Sequence< beans::PropertyValue > aArgs(2);
434 aArgs[0].Name = PROPERTY_GROUP;
435 aArgs[0].Value <<= xGroup;
436 // find position where to insert the new group
437 sal_Int32 nGroupPos = 0;
438 ::std::vector<sal_Int32>::iterator aIter = m_aGroupPositions.begin();
439 ::std::vector<sal_Int32>::const_iterator aEnd = m_aGroupPositions.begin() + nRow;
440 for(;aIter != aEnd;++aIter)
441 if ( *aIter != NO_GROUP )
442 nGroupPos = *aIter + 1;
443 aArgs[1].Name = PROPERTY_POSITIONY;
444 aArgs[1].Value <<= nGroupPos;
445 m_bIgnoreEvent = true;
446 m_pParent->m_pController->executeChecked(SID_GROUP_APPEND,aArgs);
447 m_bIgnoreEvent = false;
448 OSL_ENSURE(*aIter == NO_GROUP ,"Illegal iterator!");
449 *aIter++ = nGroupPos;
451 aEnd = m_aGroupPositions.end();
452 for(;aIter != aEnd;++aIter)
453 if ( *aIter != NO_GROUP )
454 ++*aIter;
456 else
457 xGroup = m_pParent->getGroup(m_aGroupPositions[nRow]);
458 if ( xGroup.is() )
460 sal_Int32 nPos = m_pComboCell->GetSelectedEntryPos();
461 OUString sExpression;
462 if ( COMBOBOX_ENTRY_NOTFOUND == nPos )
463 sExpression = m_pComboCell->GetText();
464 else
466 sExpression = m_aColumnInfo[nPos].sColumnName;
468 xGroup->setExpression( sExpression );
470 ::rptui::adjustSectionName(xGroup,nPos);
472 if ( bAppend )
473 m_pParent->m_pController->getUndoManager().LeaveListAction();
476 if ( Controller().is() )
477 Controller()->ClearModified();
478 if ( GetRowCount() == m_pParent->getGroups()->getCount() )
480 RowInserted( GetRowCount()-1);
481 m_aGroupPositions.push_back(NO_GROUP);
484 GoToRow(nRow);
485 m_pParent->DisplayData(nRow);
487 catch(uno::Exception&)
489 OSL_FAIL("OFieldExpressionControl::SaveModified: Exception caught!");
493 return true;
496 OUString OFieldExpressionControl::GetCellText( long nRow, sal_uInt16 /*nColId*/ ) const
498 OUString sText;
499 if ( nRow != BROWSER_ENDOFSELECTION && m_aGroupPositions[nRow] != NO_GROUP )
503 uno::Reference< report::XGroup> xGroup = m_pParent->getGroup(m_aGroupPositions[nRow]);
504 OUString sExpression = xGroup->getExpression();
506 auto aIter = std::find_if(m_aColumnInfo.begin(), m_aColumnInfo.end(),
507 [&sExpression](const ColumnInfo& rColumnInfo) { return rColumnInfo.sColumnName == sExpression; });
508 if (aIter != m_aColumnInfo.end() && !aIter->sLabel.isEmpty())
509 sExpression = aIter->sLabel;
510 sText = sExpression;
512 catch (const uno::Exception&)
514 OSL_FAIL("Exception caught while getting expression value from the group");
517 return sText;
521 void OFieldExpressionControl::InitController( CellControllerRef& /*rController*/, long nRow, sal_uInt16 nColumnId )
524 m_pComboCell->SetText( GetCellText( nRow, nColumnId ) );
527 bool OFieldExpressionControl::CursorMoving(long nNewRow, sal_uInt16 nNewCol)
530 if (!EditBrowseBox::CursorMoving(nNewRow, nNewCol))
531 return false;
532 m_nDataPos = nNewRow;
533 long nOldDataPos = GetCurRow();
534 InvalidateStatusCell( m_nDataPos );
535 InvalidateStatusCell( nOldDataPos );
537 m_pParent->SaveData( nOldDataPos );
538 m_pParent->DisplayData( m_nDataPos );
539 return true;
542 CellController* OFieldExpressionControl::GetController( long /*nRow*/, sal_uInt16 /*nColumnId*/ )
544 ComboBoxCellController* pCellController = new ComboBoxCellController( m_pComboCell );
545 pCellController->GetComboBox().SetReadOnly(!m_pParent->m_pController->isEditable());
546 return pCellController;
550 bool OFieldExpressionControl::SeekRow( long _nRow )
552 // the basis class needs the call, because that's how the class knows which line will be painted
553 EditBrowseBox::SeekRow(_nRow);
554 m_nCurrentPos = _nRow;
555 return true;
559 void OFieldExpressionControl::PaintCell( OutputDevice& rDev, const tools::Rectangle& rRect, sal_uInt16 nColumnId ) const
561 OUString aText =GetCellText( m_nCurrentPos, nColumnId );
563 Point aPos( rRect.TopLeft() );
564 Size aTextSize( GetDataWindow().GetTextWidth( aText ), GetDataWindow().GetTextHeight() );
566 if( aPos.X() < rRect.Left() || aPos.X() + aTextSize.Width() > rRect.Right() ||
567 aPos.Y() < rRect.Top() || aPos.Y() + aTextSize.Height() > rRect.Bottom() )
568 rDev.SetClipRegion(vcl::Region(rRect));
570 rDev.DrawText( aPos, aText );
572 if( rDev.IsClipRegion() )
573 rDev.SetClipRegion();
576 EditBrowseBox::RowStatus OFieldExpressionControl::GetRowStatus(long nRow) const
578 if (nRow >= 0 && nRow == m_nDataPos)
579 return EditBrowseBox::CURRENT;
580 if ( nRow != BROWSER_ENDOFSELECTION && nRow < static_cast<long>(m_aGroupPositions.size()) && m_aGroupPositions[nRow] != NO_GROUP )
584 uno::Reference< report::XGroup> xGroup = m_pParent->getGroup(m_aGroupPositions[nRow]);
585 return (xGroup->getHeaderOn() || xGroup->getFooterOn())? EditBrowseBox::HEADERFOOTER : EditBrowseBox::CLEAN;
587 catch(uno::Exception&)
589 OSL_FAIL("Exception caught while try to get a group!");
592 return EditBrowseBox::CLEAN;
595 // XContainerListener
597 void OFieldExpressionControl::elementInserted(const container::ContainerEvent& evt)
599 if ( m_bIgnoreEvent )
600 return;
601 SolarMutexGuard aSolarGuard;
602 ::osl::MutexGuard aGuard( m_aMutex );
603 sal_Int32 nGroupPos = 0;
604 if ( evt.Accessor >>= nGroupPos )
606 if ( nGroupPos >= GetRowCount() )
608 sal_Int32 nAddedRows = nGroupPos - GetRowCount();
609 RowInserted(nAddedRows);
610 for (sal_Int32 i = 0; i < nAddedRows; ++i)
611 m_aGroupPositions.push_back(NO_GROUP);
612 m_aGroupPositions[nGroupPos] = nGroupPos;
614 else
616 ::std::vector<sal_Int32>::iterator aFind = m_aGroupPositions.begin()+ nGroupPos;
617 if ( aFind == m_aGroupPositions.end() )
618 aFind = ::std::find(m_aGroupPositions.begin(),m_aGroupPositions.end(),NO_GROUP);
620 if ( aFind != m_aGroupPositions.end() )
622 if ( *aFind != NO_GROUP )
623 aFind = m_aGroupPositions.insert(aFind,nGroupPos);
624 else
625 *aFind = nGroupPos;
627 ::std::vector<sal_Int32>::const_iterator aEnd = m_aGroupPositions.end();
628 for(++aFind;aFind != aEnd;++aFind)
629 if ( *aFind != NO_GROUP )
630 ++*aFind;
633 Invalidate();
637 void OFieldExpressionControl::elementRemoved(const container::ContainerEvent& evt)
639 SolarMutexGuard aSolarGuard;
640 ::osl::MutexGuard aGuard( m_aMutex );
642 if ( m_bIgnoreEvent )
643 return;
645 sal_Int32 nGroupPos = 0;
646 if ( evt.Accessor >>= nGroupPos )
648 std::vector<sal_Int32>::iterator aEnd = m_aGroupPositions.end();
649 std::vector<sal_Int32>::iterator aFind = std::find(m_aGroupPositions.begin(), aEnd, nGroupPos);
650 if (aFind != aEnd)
652 *aFind = NO_GROUP;
653 for(++aFind;aFind != aEnd;++aFind)
654 if ( *aFind != NO_GROUP )
655 --*aFind;
656 Invalidate();
661 bool OFieldExpressionControl::IsDeleteAllowed( )
663 return !m_pParent->isReadOnly() && GetSelectRowCount() > 0;
666 void OFieldExpressionControl::KeyInput( const KeyEvent& rEvt )
668 if (IsDeleteAllowed())
670 if (rEvt.GetKeyCode().GetCode() == KEY_DELETE && // Delete rows
671 !rEvt.GetKeyCode().IsShift() &&
672 !rEvt.GetKeyCode().IsMod1())
674 DeleteRows();
675 return;
678 EditBrowseBox::KeyInput(rEvt);
681 void OFieldExpressionControl::Command(const CommandEvent& rEvt)
683 switch (rEvt.GetCommand())
685 case CommandEventId::ContextMenu:
687 if (!rEvt.IsMouseEvent())
689 EditBrowseBox::Command(rEvt);
690 return;
693 sal_uInt16 nColId = GetColumnId(GetColumnAtXPosPixel(rEvt.GetMousePosPixel().X()));
695 if ( nColId == HANDLE_ID )
697 bool bEnable = false;
698 long nIndex = FirstSelectedRow();
699 while( nIndex != SFX_ENDOFSELECTION && !bEnable )
701 if ( m_aGroupPositions[nIndex] != NO_GROUP )
702 bEnable = true;
703 nIndex = NextSelectedRow();
705 VclBuilder aBuilder(nullptr, VclBuilderContainer::getUIRootDir(), "modules/dbreport/ui/groupsortmenu.ui", "");
706 VclPtr<PopupMenu> aContextMenu(aBuilder.get_menu("menu"));
707 aContextMenu->EnableItem(aContextMenu->GetItemId("delete"), IsDeleteAllowed() && bEnable);
708 if (aContextMenu->Execute(this, rEvt.GetMousePosPixel()))
710 if( m_nDeleteEvent )
711 Application::RemoveUserEvent( m_nDeleteEvent );
712 m_nDeleteEvent = Application::PostUserEvent( LINK(this, OFieldExpressionControl, DelayedDelete), nullptr, true );
715 [[fallthrough]];
717 default:
718 EditBrowseBox::Command(rEvt);
723 void OFieldExpressionControl::DeleteRows()
726 bool bIsEditing = IsEditing();
727 if (bIsEditing)
729 DeactivateCell();
731 long nIndex = FirstSelectedRow();
732 if (nIndex == SFX_ENDOFSELECTION)
734 nIndex = GetCurRow();
736 bool bFirstTime = true;
738 long nOldDataPos = nIndex;
739 uno::Sequence< beans::PropertyValue > aArgs(1);
740 aArgs[0].Name = PROPERTY_GROUP;
741 m_bIgnoreEvent = true;
742 while( nIndex >= 0 )
744 if ( m_aGroupPositions[nIndex] != NO_GROUP )
746 if ( bFirstTime )
748 bFirstTime = false;
749 OUString sUndoAction(RptResId(RID_STR_UNDO_REMOVE_SELECTION));
750 m_pParent->m_pController->getUndoManager().EnterListAction( sUndoAction, OUString(), 0, ViewShellId(-1) );
753 sal_Int32 nGroupPos = m_aGroupPositions[nIndex];
754 uno::Reference< report::XGroup> xGroup = m_pParent->getGroup(nGroupPos);
755 aArgs[0].Value <<= xGroup;
756 // we use this way to create undo actions
757 m_pParent->m_pController->executeChecked(SID_GROUP_REMOVE,aArgs);
759 std::vector<sal_Int32>::iterator aEnd = m_aGroupPositions.end();
760 std::vector<sal_Int32>::iterator aFind = std::find(m_aGroupPositions.begin(), aEnd, nGroupPos);
761 if (aFind != aEnd)
763 *aFind = NO_GROUP;
764 for(++aFind;aFind != aEnd;++aFind)
765 if ( *aFind != NO_GROUP )
766 --*aFind;
769 nIndex = NextSelectedRow();
772 if ( !bFirstTime )
773 m_pParent->m_pController->getUndoManager().LeaveListAction();
775 m_nDataPos = GetCurRow();
776 InvalidateStatusCell( nOldDataPos );
777 InvalidateStatusCell( m_nDataPos );
778 ActivateCell();
779 m_pParent->DisplayData( m_nDataPos );
780 m_bIgnoreEvent = false;
781 Invalidate();
784 IMPL_LINK_NOARG( OFieldExpressionControl, DelayedDelete, void*, void )
786 m_nDeleteEvent = nullptr;
787 DeleteRows();
790 Size OFieldExpressionControl::GetOptimalSize() const
792 return LogicToPixel(Size(106, 75), MapMode(MapUnit::MapAppFont));
795 // class OGroupsSortingDialog
796 OGroupsSortingDialog::OGroupsSortingDialog(vcl::Window* _pParent, bool _bReadOnly,
797 OReportController* _pController)
798 : FloatingWindow(_pParent, "FloatingSort", "modules/dbreport/ui/floatingsort.ui")
799 , OPropertyChangeListener(m_aMutex)
800 , m_pController(_pController)
801 , m_xGroups(m_pController->getReportDefinition()->getGroups())
802 , m_bReadOnly(_bReadOnly)
804 get(m_pToolBox, "toolbox");
805 m_nMoveUpId = m_pToolBox->GetItemId(0);
806 m_nMoveDownId = m_pToolBox->GetItemId(1);
807 m_nDeleteId = m_pToolBox->GetItemId(2);
808 get(m_pOrderLst, "sorting");
809 get(m_pHeaderLst, "header");
810 get(m_pFooterLst, "footer");
811 get(m_pGroupOnLst, "group");
812 get(m_pGroupIntervalEd, "interval");
813 get(m_pKeepTogetherLst, "keep");
814 get(m_pHelpWindow, "helptext");
815 m_pHelpWindow->set_height_request(GetTextHeight() * 4);
816 get(m_pProperties, "properties");
817 m_pFieldExpression = VclPtr<OFieldExpressionControl>::Create(this, get<vcl::Window>("box"));
818 m_pFieldExpression->set_hexpand(true);
819 m_pFieldExpression->set_vexpand(true);
821 Control* pControlsLst[] = { m_pHeaderLst, m_pFooterLst, m_pGroupOnLst, m_pKeepTogetherLst, m_pOrderLst, m_pGroupIntervalEd};
822 for (Control* i : pControlsLst)
824 i->SetGetFocusHdl(LINK(this, OGroupsSortingDialog, OnControlFocusGot));
825 i->SetLoseFocusHdl(LINK(this, OGroupsSortingDialog, OnControlFocusLost));
826 i->Show();
829 for (size_t i = 0; i < SAL_N_ELEMENTS(pControlsLst) - 1; ++i)
830 static_cast<ListBox*>(pControlsLst[i])->SetSelectHdl(LINK(this,OGroupsSortingDialog,LBChangeHdl));
832 m_pReportListener = new OPropertyChangeMultiplexer(this,m_pController->getReportDefinition().get());
833 m_pReportListener->addProperty(PROPERTY_COMMAND);
834 m_pReportListener->addProperty(PROPERTY_COMMANDTYPE);
836 m_pFieldExpression->lateInit();
837 fillColumns();
838 m_pFieldExpression->Show();
840 m_pHelpWindow->SetControlBackground( GetSettings().GetStyleSettings().GetFaceColor() );
842 m_pToolBox->SetLineSpacing(true);
843 m_pToolBox->SetSelectHdl(LINK(this, OGroupsSortingDialog, OnFormatAction));
845 checkButtons(0);
847 Show();
850 OGroupsSortingDialog::~OGroupsSortingDialog()
852 disposeOnce();
855 void OGroupsSortingDialog::dispose()
857 m_xColumns.clear();
858 m_pReportListener->dispose();
859 if ( m_pCurrentGroupListener.is() )
860 m_pCurrentGroupListener->dispose();
861 m_pToolBox.clear();
862 m_pProperties.clear();
863 m_pOrderLst.clear();
864 m_pHeaderLst.clear();
865 m_pFooterLst.clear();
866 m_pGroupOnLst.clear();
867 m_pGroupIntervalEd.clear();
868 m_pKeepTogetherLst.clear();
869 m_pHelpWindow.clear();
870 m_pFieldExpression.disposeAndClear();
871 FloatingWindow::dispose();
874 void OGroupsSortingDialog::UpdateData( )
876 m_pFieldExpression->Invalidate();
877 long nCurRow = m_pFieldExpression->GetCurRow();
878 m_pFieldExpression->DeactivateCell();
879 m_pFieldExpression->ActivateCell(nCurRow, m_pFieldExpression->GetCurColumnId());
880 DisplayData(nCurRow);
883 void OGroupsSortingDialog::DisplayData( sal_Int32 _nRow )
885 const sal_Int32 nGroupPos = m_pFieldExpression->getGroupPosition(_nRow);
886 const bool bEmpty = nGroupPos == NO_GROUP;
887 m_pProperties->Enable(!bEmpty);
889 checkButtons(_nRow);
891 if ( m_pCurrentGroupListener.is() )
892 m_pCurrentGroupListener->dispose();
893 m_pCurrentGroupListener = nullptr;
894 if (!bEmpty)
896 uno::Reference< report::XGroup> xGroup = getGroup(nGroupPos);
898 m_pCurrentGroupListener = new OPropertyChangeMultiplexer(this,xGroup.get());
899 m_pCurrentGroupListener->addProperty(PROPERTY_HEADERON);
900 m_pCurrentGroupListener->addProperty(PROPERTY_FOOTERON);
902 displayGroup(xGroup);
906 void OGroupsSortingDialog::SaveData( sal_Int32 _nRow)
908 sal_Int32 nGroupPos = m_pFieldExpression->getGroupPosition(_nRow);
909 if ( nGroupPos == NO_GROUP )
910 return;
912 uno::Reference< report::XGroup> xGroup = getGroup(nGroupPos);
913 if ( m_pHeaderLst->IsValueChangedFromSaved() )
914 xGroup->setHeaderOn( m_pHeaderLst->GetSelectedEntryPos() == 0 );
915 if ( m_pFooterLst->IsValueChangedFromSaved() )
916 xGroup->setFooterOn( m_pFooterLst->GetSelectedEntryPos() == 0 );
917 if ( m_pKeepTogetherLst->IsValueChangedFromSaved() )
918 xGroup->setKeepTogether( m_pKeepTogetherLst->GetSelectedEntryPos() );
919 if ( m_pGroupOnLst->IsValueChangedFromSaved() )
921 sal_Int16 nGroupOn = static_cast<sal_Int16>(reinterpret_cast<sal_IntPtr>(m_pGroupOnLst->GetSelectedEntryData()));
922 xGroup->setGroupOn( nGroupOn );
924 if ( m_pGroupIntervalEd->IsValueChangedFromSaved() )
926 xGroup->setGroupInterval( static_cast<sal_Int32>(m_pGroupIntervalEd->GetValue()) );
927 m_pGroupIntervalEd->SaveValue();
929 if ( m_pOrderLst->IsValueChangedFromSaved() )
930 xGroup->setSortAscending( m_pOrderLst->GetSelectedEntryPos() == 0 );
932 ListBox* pControls[] = { m_pHeaderLst, m_pFooterLst, m_pGroupOnLst, m_pKeepTogetherLst, m_pOrderLst};
933 for (ListBox* pControl : pControls)
934 pControl->SaveValue();
938 sal_Int32 OGroupsSortingDialog::getColumnDataType(const OUString& _sColumnName)
940 sal_Int32 nDataType = sdbc::DataType::VARCHAR;
943 if ( !m_xColumns.is() )
944 fillColumns();
945 if ( m_xColumns.is() && m_xColumns->hasByName(_sColumnName) )
947 uno::Reference< beans::XPropertySet> xColumn(m_xColumns->getByName(_sColumnName),uno::UNO_QUERY);
948 if ( xColumn.is() )
949 xColumn->getPropertyValue(PROPERTY_TYPE) >>= nDataType;
952 catch(uno::Exception&)
954 OSL_FAIL("Exception caught while getting the type of a column");
957 return nDataType;
960 IMPL_LINK(OGroupsSortingDialog, OnControlFocusGot, Control&, rControl, void )
962 if ( m_pFieldExpression && m_pFieldExpression->getExpressionControl() )
964 const std::pair<Control*, const char*> pControls[] = {
965 { m_pFieldExpression->getExpressionControl(), STR_RPT_HELP_FIELD },
966 { m_pHeaderLst, STR_RPT_HELP_HEADER },
967 { m_pFooterLst, STR_RPT_HELP_FOOTER },
968 { m_pGroupOnLst, STR_RPT_HELP_GROUPON },
969 { m_pGroupIntervalEd, STR_RPT_HELP_INTERVAL },
970 { m_pKeepTogetherLst, STR_RPT_HELP_KEEP },
971 { m_pOrderLst, STR_RPT_HELP_SORT }
973 for (size_t i = 0; i < SAL_N_ELEMENTS(pControls); ++i)
975 if (&rControl == pControls[i].first)
977 ListBox* pListBox = dynamic_cast< ListBox* >( &rControl );
978 if ( pListBox )
979 pListBox->SaveValue();
980 NumericField* pNumericField = dynamic_cast< NumericField* >( &rControl );
981 if ( pNumericField )
982 pNumericField->SaveValue();
983 //shows the text given by the id in the multiline edit
984 m_pHelpWindow->SetText(RptResId(pControls[i].second));
985 break;
991 IMPL_LINK(OGroupsSortingDialog, OnControlFocusLost, Control&, rControl, void )
993 if (m_pFieldExpression && &rControl == m_pGroupIntervalEd)
995 if ( m_pGroupIntervalEd->IsModified() )
996 SaveData(m_pFieldExpression->GetCurRow());
1000 IMPL_LINK_NOARG( OGroupsSortingDialog, OnFormatAction, ToolBox*, void )
1003 sal_uInt16 nCommand = m_pToolBox->GetCurItemId();
1005 if ( m_pFieldExpression )
1007 long nIndex = m_pFieldExpression->GetCurrRow();
1008 sal_Int32 nGroupPos = m_pFieldExpression->getGroupPosition(nIndex);
1009 uno::Sequence<uno::Any> aClipboardList;
1010 if ( nIndex >= 0 && nGroupPos != NO_GROUP )
1012 aClipboardList.realloc(1);
1013 aClipboardList[0] = m_xGroups->getByIndex(nGroupPos);
1015 if ( nCommand == m_nMoveUpId )
1017 --nIndex;
1019 if ( nCommand == m_nMoveDownId )
1021 ++nIndex;
1023 if ( nCommand == m_nDeleteId )
1025 Application::PostUserEvent( LINK(m_pFieldExpression, OFieldExpressionControl, DelayedDelete), nullptr, true );
1027 else
1029 if ( nIndex >= 0 && aClipboardList.hasElements() )
1031 m_pFieldExpression->SetNoSelection();
1032 m_pFieldExpression->moveGroups(aClipboardList,nIndex,false);
1033 m_pFieldExpression->DeactivateCell();
1034 m_pFieldExpression->GoToRow(nIndex);
1035 m_pFieldExpression->ActivateCell(nIndex, m_pFieldExpression->GetCurColumnId());
1036 DisplayData(nIndex);
1042 IMPL_LINK( OGroupsSortingDialog, LBChangeHdl, ListBox&, rListBox, void )
1044 if ( rListBox.IsValueChangedFromSaved() )
1046 sal_Int32 nRow = m_pFieldExpression->GetCurRow();
1047 sal_Int32 nGroupPos = m_pFieldExpression->getGroupPosition(nRow);
1048 if (&rListBox != m_pHeaderLst && &rListBox != m_pFooterLst)
1050 if ( rListBox.IsValueChangedFromSaved() )
1051 SaveData(nRow);
1052 if ( &rListBox == m_pGroupOnLst )
1053 m_pGroupIntervalEd->Enable( rListBox.GetSelectedEntryPos() != 0 );
1055 else if ( nGroupPos != NO_GROUP )
1057 uno::Reference< report::XGroup> xGroup = getGroup(nGroupPos);
1058 uno::Sequence< beans::PropertyValue > aArgs(2);
1059 aArgs[1].Name = PROPERTY_GROUP;
1060 aArgs[1].Value <<= xGroup;
1062 if ( m_pHeaderLst == &rListBox )
1063 aArgs[0].Name = PROPERTY_HEADERON;
1064 else
1065 aArgs[0].Name = PROPERTY_FOOTERON;
1067 aArgs[0].Value <<= rListBox.GetSelectedEntryPos() == 0;
1068 m_pController->executeChecked(m_pHeaderLst == &rListBox ? SID_GROUPHEADER : SID_GROUPFOOTER, aArgs);
1069 m_pFieldExpression->InvalidateHandleColumn();
1074 void OGroupsSortingDialog::_propertyChanged(const beans::PropertyChangeEvent& _rEvent)
1076 uno::Reference< report::XGroup > xGroup(_rEvent.Source,uno::UNO_QUERY);
1077 if ( xGroup.is() )
1078 displayGroup(xGroup);
1079 else
1080 fillColumns();
1083 void OGroupsSortingDialog::fillColumns()
1085 m_xColumns = m_pController->getColumns();
1086 m_pFieldExpression->fillColumns(m_xColumns);
1089 void OGroupsSortingDialog::displayGroup(const uno::Reference<report::XGroup>& _xGroup)
1091 m_pHeaderLst->SelectEntryPos(_xGroup->getHeaderOn() ? 0 : 1 );
1092 m_pFooterLst->SelectEntryPos(_xGroup->getFooterOn() ? 0 : 1 );
1093 sal_Int32 nDataType = getColumnDataType(_xGroup->getExpression());
1095 // first clear whole group on list
1096 while(m_pGroupOnLst->GetEntryCount() > 1 )
1098 m_pGroupOnLst->RemoveEntry(1);
1101 switch(nDataType)
1103 case sdbc::DataType::LONGVARCHAR:
1104 case sdbc::DataType::VARCHAR:
1105 case sdbc::DataType::CHAR:
1106 m_pGroupOnLst->InsertEntry(RptResId(STR_RPT_PREFIXCHARS));
1107 m_pGroupOnLst->SetEntryData(1,reinterpret_cast<void*>(report::GroupOn::PREFIX_CHARACTERS));
1108 break;
1109 case sdbc::DataType::DATE:
1110 case sdbc::DataType::TIME:
1111 case sdbc::DataType::TIMESTAMP:
1113 const char* aIds[] = { STR_RPT_YEAR, STR_RPT_QUARTER,STR_RPT_MONTH,STR_RPT_WEEK,STR_RPT_DAY,STR_RPT_HOUR,STR_RPT_MINUTE };
1114 for (size_t i = 0; i < SAL_N_ELEMENTS(aIds); ++i)
1116 m_pGroupOnLst->InsertEntry(RptResId(aIds[i]));
1117 m_pGroupOnLst->SetEntryData(i+1,reinterpret_cast<void*>(i+2));
1120 break;
1121 default:
1122 m_pGroupOnLst->InsertEntry(RptResId(STR_RPT_INTERVAL));
1123 m_pGroupOnLst->SetEntryData(1,reinterpret_cast<void*>(report::GroupOn::INTERVAL));
1124 break;
1126 sal_Int32 nPos = 0;
1127 switch(_xGroup->getGroupOn())
1129 case report::GroupOn::DEFAULT:
1130 nPos = 0;
1131 break;
1132 case report::GroupOn::PREFIX_CHARACTERS:
1133 nPos = 1;
1134 break;
1135 case report::GroupOn::YEAR:
1136 nPos = 1;
1137 break;
1138 case report::GroupOn::QUARTAL:
1139 nPos = 2;
1140 break;
1141 case report::GroupOn::MONTH:
1142 nPos = 3;
1143 break;
1144 case report::GroupOn::WEEK:
1145 nPos = 4;
1146 break;
1147 case report::GroupOn::DAY:
1148 nPos = 5;
1149 break;
1150 case report::GroupOn::HOUR:
1151 nPos = 6;
1152 break;
1153 case report::GroupOn::MINUTE:
1154 nPos = 7;
1155 break;
1156 case report::GroupOn::INTERVAL:
1157 nPos = 1;
1158 break;
1159 default:
1160 nPos = 0;
1162 m_pGroupOnLst->SelectEntryPos(nPos);
1163 m_pGroupIntervalEd->SetText(OUString::number(_xGroup->getGroupInterval()));
1164 m_pGroupIntervalEd->SaveValue();
1165 m_pGroupIntervalEd->Enable( nPos != 0 );
1166 m_pKeepTogetherLst->SelectEntryPos(_xGroup->getKeepTogether());
1167 m_pOrderLst->SelectEntryPos(_xGroup->getSortAscending() ? 0 : 1);
1169 ListBox* pControls[] = { m_pHeaderLst, m_pFooterLst, m_pGroupOnLst, m_pKeepTogetherLst, m_pOrderLst};
1170 for (ListBox* pControl : pControls)
1171 pControl->SaveValue();
1173 ListBox* pControlsLst2[] = { m_pHeaderLst, m_pFooterLst, m_pGroupOnLst, m_pKeepTogetherLst, m_pOrderLst};
1174 bool bReadOnly = !m_pController->isEditable();
1175 for (ListBox* i : pControlsLst2)
1176 i->SetReadOnly(bReadOnly);
1177 m_pGroupIntervalEd->SetReadOnly(bReadOnly);
1180 void OGroupsSortingDialog::checkButtons(sal_Int32 _nRow)
1182 sal_Int32 nGroupCount = m_xGroups->getCount();
1183 sal_Int32 nRowCount = m_pFieldExpression->GetRowCount();
1184 bool bEnabled = nGroupCount > 1;
1186 if (bEnabled && _nRow > 0 )
1188 m_pToolBox->EnableItem(m_nMoveUpId);
1190 else
1192 m_pToolBox->EnableItem(m_nMoveUpId, false);
1194 if (bEnabled && _nRow < (nRowCount - 1) )
1196 m_pToolBox->EnableItem(m_nMoveDownId);
1198 else
1200 m_pToolBox->EnableItem(m_nMoveDownId, false);
1203 sal_Int32 nGroupPos = m_pFieldExpression->getGroupPosition(_nRow);
1204 if ( nGroupPos != NO_GROUP )
1206 bool bEnableDelete = nGroupCount > 0;
1207 m_pToolBox->EnableItem(m_nDeleteId, bEnableDelete);
1209 else
1211 m_pToolBox->EnableItem(m_nDeleteId, false);
1215 } // rptui
1217 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */