1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3  * This file is part of the LibreOffice project.
4  *
5  * This Source Code Form is subject to the terms of the Mozilla Public
6  * License, v. 2.0. If a copy of the MPL was not distributed with this
7  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8  *
9  * This file incorporates work covered by the following license notice:
10  */
11 
12 #include <memory>
13 #include <PivotLayoutTreeListData.hxx>
14 #include <PivotLayoutDialog.hxx>
15 
16 #include <vcl/event.hxx>
17 #include <pivot.hxx>
18 #include <scabstdlg.hxx>
19 #include <globstr.hrc>
20 #include <scresid.hxx>
21 
22 namespace
23 {
24 
lclGetFunctionMaskName(const PivotFunc nFunctionMask)25 OUString lclGetFunctionMaskName(const PivotFunc nFunctionMask)
26 {
27     const char* pStrId = nullptr;
28     switch (nFunctionMask)
29     {
30         case PivotFunc::Sum:        pStrId = STR_FUN_TEXT_SUM;      break;
31         case PivotFunc::Count:      pStrId = STR_FUN_TEXT_COUNT;    break;
32         case PivotFunc::Average:    pStrId = STR_FUN_TEXT_AVG;      break;
33         case PivotFunc::Median:     pStrId = STR_FUN_TEXT_MEDIAN;   break;
34         case PivotFunc::Max:        pStrId = STR_FUN_TEXT_MAX;      break;
35         case PivotFunc::Min:        pStrId = STR_FUN_TEXT_MIN;      break;
36         case PivotFunc::Product:    pStrId = STR_FUN_TEXT_PRODUCT;  break;
37         case PivotFunc::CountNum:   pStrId = STR_FUN_TEXT_COUNT;    break;
38         case PivotFunc::StdDev:     pStrId = STR_FUN_TEXT_STDDEV;   break;
39         case PivotFunc::StdDevP:    pStrId = STR_FUN_TEXT_STDDEV;   break;
40         case PivotFunc::StdVar:     pStrId = STR_FUN_TEXT_VAR;      break;
41         case PivotFunc::StdVarP:    pStrId = STR_FUN_TEXT_VAR;      break;
42         default:
43             assert(false);
44             break;
45     }
46     if (pStrId)
47         return ScResId(pStrId);
48     else
49         return OUString();
50 }
51 
lclCreateDataItemName(const PivotFunc nFunctionMask,const OUString & rName,const sal_uInt8 nDuplicationCount)52 OUString lclCreateDataItemName(const PivotFunc nFunctionMask, const OUString& rName, const sal_uInt8 nDuplicationCount)
53 {
54     OUString aBuffer = lclGetFunctionMaskName(nFunctionMask) + " - " + rName;
55     if(nDuplicationCount > 0)
56     {
57         aBuffer += " " + OUString::number(nDuplicationCount);
58     }
59     return aBuffer;
60 }
61 
62 } // anonymous namespace
63 
ScPivotLayoutTreeListData(std::unique_ptr<weld::TreeView> xControl)64 ScPivotLayoutTreeListData::ScPivotLayoutTreeListData(std::unique_ptr<weld::TreeView> xControl)
65     : ScPivotLayoutTreeListBase(std::move(xControl))
66 {
67     mxControl->connect_key_press(LINK(this, ScPivotLayoutTreeListData, KeyInputHdl));
68     mxControl->connect_row_activated(LINK(this, ScPivotLayoutTreeListData, DoubleClickHdl));
69 }
70 
~ScPivotLayoutTreeListData()71 ScPivotLayoutTreeListData::~ScPivotLayoutTreeListData()
72 {}
73 
IMPL_LINK_NOARG(ScPivotLayoutTreeListData,DoubleClickHdl,weld::TreeView &,bool)74 IMPL_LINK_NOARG(ScPivotLayoutTreeListData, DoubleClickHdl, weld::TreeView&, bool)
75 {
76     int nEntry = mxControl->get_cursor_index();
77     if (nEntry == -1)
78         return true;
79 
80     ScItemValue* pCurrentItemValue = reinterpret_cast<ScItemValue*>(mxControl->get_id(nEntry).toInt64());
81     ScPivotFuncData& rCurrentFunctionData = pCurrentItemValue->maFunctionData;
82 
83     SCCOL nCurrentColumn = rCurrentFunctionData.mnCol;
84     ScDPLabelData& rCurrentLabelData = mpParent->GetLabelData(nCurrentColumn);
85 
86     ScAbstractDialogFactory* pFactory = ScAbstractDialogFactory::Create();
87 
88     ScopedVclPtr<AbstractScDPFunctionDlg> pDialog(
89         pFactory->CreateScDPFunctionDlg(mxControl.get(), mpParent->GetLabelDataVector(), rCurrentLabelData, rCurrentFunctionData));
90 
91     if (pDialog->Execute() == RET_OK)
92     {
93         rCurrentFunctionData.mnFuncMask = pDialog->GetFuncMask();
94         rCurrentLabelData.mnFuncMask = pDialog->GetFuncMask();
95 
96         rCurrentFunctionData.maFieldRef = pDialog->GetFieldRef();
97 
98         ScDPLabelData& rDFData = mpParent->GetLabelData(rCurrentFunctionData.mnCol);
99 
100         AdjustDuplicateCount(pCurrentItemValue);
101 
102         OUString sDataItemName = lclCreateDataItemName(
103                                     rCurrentFunctionData.mnFuncMask,
104                                     rDFData.maName,
105                                     rCurrentFunctionData.mnDupCount);
106 
107         mxControl->set_text(nEntry, sDataItemName);
108     }
109 
110     return true;
111 }
112 
FillDataField(ScPivotFieldVector & rDataFields)113 void ScPivotLayoutTreeListData::FillDataField(ScPivotFieldVector& rDataFields)
114 {
115     mxControl->clear();
116     maDataItemValues.clear();
117 
118     for (const ScPivotField& rField : rDataFields)
119     {
120         if (rField.nCol == PIVOT_DATA_FIELD)
121             continue;
122 
123         SCCOL nColumn;
124         if (rField.mnOriginalDim >= 0)
125             nColumn = rField.mnOriginalDim;
126         else
127             nColumn = rField.nCol;
128 
129         ScItemValue* pOriginalItemValue = mpParent->GetItem(nColumn);
130         ScItemValue* pItemValue = new ScItemValue(pOriginalItemValue->maName, nColumn, rField.nFuncMask);
131 
132         pItemValue->mpOriginalItemValue = pOriginalItemValue;
133         pItemValue->maFunctionData.mnOriginalDim = rField.mnOriginalDim;
134         pItemValue->maFunctionData.maFieldRef = rField.maFieldRef;
135 
136         AdjustDuplicateCount(pItemValue);
137         OUString sDataItemName = lclCreateDataItemName(pItemValue->maFunctionData.mnFuncMask,
138                                                        pItemValue->maName,
139                                                        pItemValue->maFunctionData.mnDupCount);
140 
141         maDataItemValues.push_back(std::unique_ptr<ScItemValue>(pItemValue));
142         OUString sId(OUString::number(reinterpret_cast<sal_Int64>(pItemValue)));
143         mxControl->append(sId, sDataItemName);
144     }
145 }
146 
PushDataFieldNames(std::vector<ScDPName> & rDataFieldNames)147 void ScPivotLayoutTreeListData::PushDataFieldNames(std::vector<ScDPName>& rDataFieldNames)
148 {
149     std::unique_ptr<weld::TreeIter> xLoopEntry(mxControl->make_iterator());
150     if (!mxControl->get_iter_first(*xLoopEntry))
151         return;
152 
153     do
154     {
155         ScItemValue* pEachItemValue = reinterpret_cast<ScItemValue*>(mxControl->get_id(*xLoopEntry).toInt64());
156         SCCOL nColumn = pEachItemValue->maFunctionData.mnCol;
157 
158         ScDPLabelData& rLabelData = mpParent->GetLabelData(nColumn);
159 
160         if (rLabelData.maName.isEmpty())
161             continue;
162 
163         OUString sLayoutName = rLabelData.maLayoutName;
164         if (sLayoutName.isEmpty())
165         {
166             sLayoutName = lclCreateDataItemName(
167                             pEachItemValue->maFunctionData.mnFuncMask,
168                             pEachItemValue->maName,
169                             pEachItemValue->maFunctionData.mnDupCount);
170         }
171 
172         rDataFieldNames.emplace_back(rLabelData.maName, sLayoutName, rLabelData.mnDupCount);
173     } while (mxControl->iter_next(*xLoopEntry));
174 }
175 
InsertEntryForSourceTarget(weld::TreeView & rSource,int nTarget)176 void ScPivotLayoutTreeListData::InsertEntryForSourceTarget(weld::TreeView& rSource, int nTarget)
177 {
178     ScItemValue* pItemValue = reinterpret_cast<ScItemValue*>(rSource.get_selected_id().toInt64());
179 
180     if (mpParent->IsDataElement(pItemValue->maFunctionData.mnCol))
181         return;
182 
183     if (&rSource == mxControl.get())
184     {
185         OUString sText = mxControl->get_selected_text();
186         OUString sId(OUString::number(reinterpret_cast<sal_Int64>(pItemValue)));
187         mxControl->remove_id(sId);
188         mxControl->insert(nullptr, nTarget, &sText, &sId, nullptr, nullptr, nullptr, false, nullptr);
189     }
190     else
191     {
192         InsertEntryForItem(pItemValue->mpOriginalItemValue, nTarget);
193     }
194 }
195 
InsertEntryForItem(ScItemValue * pItemValue,int nPosition)196 void ScPivotLayoutTreeListData::InsertEntryForItem(ScItemValue* pItemValue, int nPosition)
197 {
198     ScItemValue* pDataItemValue = new ScItemValue(pItemValue);
199     pDataItemValue->mpOriginalItemValue = pItemValue;
200     maDataItemValues.push_back(std::unique_ptr<ScItemValue>(pDataItemValue));
201 
202     ScPivotFuncData& rFunctionData = pDataItemValue->maFunctionData;
203 
204     if (rFunctionData.mnFuncMask == PivotFunc::NONE ||
205         rFunctionData.mnFuncMask == PivotFunc::Auto)
206     {
207         rFunctionData.mnFuncMask = PivotFunc::Sum;
208     }
209 
210     AdjustDuplicateCount(pDataItemValue);
211 
212     OUString sDataName = lclCreateDataItemName(
213                             rFunctionData.mnFuncMask,
214                             pDataItemValue->maName,
215                             rFunctionData.mnDupCount);
216 
217     OUString sId(OUString::number(reinterpret_cast<sal_Int64>(pDataItemValue)));
218     mxControl->insert(nullptr, nPosition, &sDataName, &sId, nullptr, nullptr, nullptr, false, nullptr);
219 }
220 
AdjustDuplicateCount(ScItemValue * pInputItemValue)221 void ScPivotLayoutTreeListData::AdjustDuplicateCount(ScItemValue* pInputItemValue)
222 {
223     ScPivotFuncData& rInputFunctionData = pInputItemValue->maFunctionData;
224 
225     bool bFoundDuplicate = false;
226 
227     rInputFunctionData.mnDupCount = 0;
228     sal_uInt8 nMaxDuplicateCount = 0;
229 
230     std::unique_ptr<weld::TreeIter> xEachEntry(mxControl->make_iterator());
231     if (!mxControl->get_iter_first(*xEachEntry))
232         return;
233     do
234     {
235         ScItemValue* pItemValue = reinterpret_cast<ScItemValue*>(mxControl->get_id(*xEachEntry).toInt64());
236         if (pItemValue == pInputItemValue)
237             continue;
238 
239         ScPivotFuncData& rFunctionData = pItemValue->maFunctionData;
240 
241         if (rFunctionData.mnCol      == rInputFunctionData.mnCol &&
242             rFunctionData.mnFuncMask == rInputFunctionData.mnFuncMask)
243         {
244             bFoundDuplicate = true;
245             if(rFunctionData.mnDupCount > nMaxDuplicateCount)
246                 nMaxDuplicateCount = rFunctionData.mnDupCount;
247         }
248     } while (mxControl->iter_next(*xEachEntry));
249 
250     if(bFoundDuplicate)
251     {
252         rInputFunctionData.mnDupCount = nMaxDuplicateCount + 1;
253     }
254 }
255 
IMPL_LINK(ScPivotLayoutTreeListData,KeyInputHdl,const KeyEvent &,rKeyEvent,bool)256 IMPL_LINK(ScPivotLayoutTreeListData, KeyInputHdl, const KeyEvent&, rKeyEvent, bool)
257 {
258     vcl::KeyCode aCode = rKeyEvent.GetKeyCode();
259     sal_uInt16 nCode = aCode.GetCode();
260 
261     if (nCode == KEY_DELETE)
262     {
263         int nEntry = mxControl->get_cursor_index();
264         if (nEntry != -1)
265             mxControl->remove(nEntry);
266         return true;
267     }
268 
269     return false;
270 }
271 
272 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
273