Bump version to 24.04.3.4
[LibreOffice.git] / sfx2 / source / control / listview.cxx
blob579e7463611ee03b5d9b10af7b3fc4c03e8a3df9
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/.
8 */
10 #include <sfx2/listview.hxx>
12 #include <sfx2/sfxresid.hxx>
13 #include <tools/urlobj.hxx>
14 #include <tools/datetime.hxx>
15 #include <sfx2/strings.hrc>
16 #include <osl/file.hxx>
17 #include <osl/time.h>
18 #include <comphelper/fileurl.hxx>
20 #include <svtools/svtresid.hxx>
21 #include <svtools/strings.hrc>
22 #include <unotools/localedatawrapper.hxx>
23 #include <unotools/collatorwrapper.hxx>
24 #include <unotools/syslocale.hxx>
25 #include <unotools/intlwrapper.hxx>
26 #include <vcl/wintypes.hxx>
28 #include <bitmaps.hlst>
29 #include <rtl/math.hxx>
31 #include <sfx2/templatelocalview.hxx>
33 #define COLUMN_IMG_ISDEFAULT 0
34 #define COLUMN_NAME 1
35 #define COLUMN_CATEGORY 2
36 #define COLUMN_APPLICATION 3
37 #define COLUMN_MODIFIED 4
38 #define COLUMN_SIZE 5
39 #define NUMBER_OF_COLUMNS 6
41 static sal_uInt64 getFileSize(const OUString& rURL);
42 static sal_uInt32 getFileModifyTime(const OUString& rURL);
43 static OUString getDisplayFileSize(const OUString& rURL);
44 static OUString getDisplayFileModifyTime(const OUString& rURL);
45 static OUString getApplication(std::u16string_view rURL);
47 ListView::ListView(std::unique_ptr<weld::TreeView> xTreeView)
48 : mxTreeView(std::move(xTreeView))
49 , mnSortColumn(-2)
51 auto nDigitWidth = mxTreeView->get_approximate_digit_width();
52 std::vector<int> aWidths{
53 static_cast<int>(nDigitWidth * 5), /* Icon Column */
54 static_cast<int>(nDigitWidth * 24), /* Name Column */
55 static_cast<int>(nDigitWidth * 22), /* Category Column */
56 static_cast<int>(nDigitWidth * 15), /* Application Column */
57 static_cast<int>(nDigitWidth * 18) /* Modify Column */
60 // tdf#151143 Make the size of ListView and ThumbnailView the same
61 mxTreeView->set_size_request(TEMPLATE_ITEM_MAX_WIDTH * 5, TEMPLATE_ITEM_MAX_HEIGHT_SUB * 3);
63 mxTreeView->set_column_fixed_widths(aWidths);
64 mxTreeView->set_selection_mode(SelectionMode::Multiple);
65 mxTreeView->connect_query_tooltip(LINK(this, ListView, QueryTooltipHdl));
67 ListView::~ListView() {}
69 void ListView::AppendItem(const OUString& rId, const OUString& rTitle, const OUString& rSubtitle,
70 const OUString& rPath, bool bDefault)
72 INetURLObject aUrl(rPath, INetProtocol::File);
73 OUString sPath = aUrl.getFSysPath(FSysStyle::Detect);
75 std::unique_ptr<ListViewItem> pItem(new ListViewItem);
76 pItem->maId = rId;
77 pItem->maTitle = rTitle;
78 pItem->maSubtitle = rSubtitle;
79 pItem->maApplication = getApplication(rPath);
80 pItem->maPath = rPath;
81 pItem->mbDefault = bDefault;
82 pItem->mnModify = getFileModifyTime(rPath);
83 pItem->mnSize = getFileSize(rPath);
84 pItem->maDisplayModify = getDisplayFileModifyTime(rPath);
85 pItem->maDisplaySize = getDisplayFileSize(rPath);
86 pItem->maDisplayPath = sPath;
88 OUString sImage("");
89 if (pItem->mbDefault)
90 sImage = BMP_DEFAULT;
92 AppendRow(sImage, pItem->maTitle, pItem->maSubtitle, pItem->maApplication,
93 pItem->maDisplayModify, pItem->maDisplaySize, pItem->maId);
95 mListViewItems.push_back(std::move(pItem));
98 void ListView::AppendRow(const OUString& rImage, const OUString& rTitle, const OUString& rSubtitle,
99 const OUString& rApplication, const OUString& rModify,
100 const OUString& rSize, const OUString& rId)
102 std::unique_ptr<weld::TreeIter> xIter(mxTreeView->make_iterator());
103 mxTreeView->append(xIter.get());
104 mxTreeView->set_image(*xIter, rImage, COLUMN_IMG_ISDEFAULT);
105 mxTreeView->set_text(*xIter, rTitle, COLUMN_NAME);
106 mxTreeView->set_text(*xIter, rSubtitle, COLUMN_CATEGORY);
107 mxTreeView->set_text(*xIter, rApplication, COLUMN_APPLICATION);
108 mxTreeView->set_text(*xIter, rModify, COLUMN_MODIFIED);
109 mxTreeView->set_text(*xIter, rSize, COLUMN_SIZE);
110 mxTreeView->set_id(*xIter, rId);
113 void ListView::UpdateRow(int nIndex, const OUString& rImage, const OUString& rTitle,
114 const OUString& rSubtitle, const OUString& rApplication,
115 const OUString& rModify, const OUString& rSize, const OUString& rId)
117 mxTreeView->set_image(nIndex, rImage, COLUMN_IMG_ISDEFAULT);
118 mxTreeView->set_text(nIndex, rTitle, COLUMN_NAME);
119 mxTreeView->set_text(nIndex, rSubtitle, COLUMN_CATEGORY);
120 mxTreeView->set_text(nIndex, rApplication, COLUMN_APPLICATION);
121 mxTreeView->set_text(nIndex, rModify, COLUMN_MODIFIED);
122 mxTreeView->set_text(nIndex, rSize, COLUMN_SIZE);
123 mxTreeView->set_id(nIndex, rId);
126 void ListView::ReloadRows()
128 OUString sCursorId = get_id(get_cursor_index());
129 mxTreeView->clear();
130 for (const auto& pItem : mListViewItems)
132 OUString sImage("");
133 if (pItem->mbDefault)
134 sImage = BMP_DEFAULT;
135 AppendRow(sImage, pItem->maTitle, pItem->maSubtitle, pItem->maApplication,
136 pItem->maDisplayModify, pItem->maDisplaySize, pItem->maId);
138 unselect_all();
139 if (!sCursorId.isEmpty())
141 select_id(sCursorId);
142 set_cursor(get_selected_index());
146 bool ListView::UpdateRows()
148 if (static_cast<int>(mListViewItems.size()) != mxTreeView->n_children())
149 return false;
150 OUString sCursorId = get_id(get_cursor_index());
151 int nIndex = 0;
152 for (const auto& pItem : mListViewItems)
154 OUString sImage("");
155 if (pItem->mbDefault)
156 sImage = BMP_DEFAULT;
157 UpdateRow(nIndex, sImage, pItem->maTitle, pItem->maSubtitle, pItem->maApplication,
158 pItem->maDisplayModify, pItem->maDisplaySize, pItem->maId);
159 ++nIndex;
161 unselect_all();
162 if (!sCursorId.isEmpty())
164 select_id(sCursorId);
165 set_cursor(get_selected_index());
167 return true;
170 IMPL_LINK(ListView, ColumnClickedHdl, const int, col, void)
172 if (col <= 0 || col > NUMBER_OF_COLUMNS)
173 return;
175 if (mnSortColumn >= 0 && mnSortColumn != col)
176 mxTreeView->set_sort_indicator(TriState::TRISTATE_INDET, mnSortColumn);
178 mxTreeView->set_sort_indicator((mxTreeView->get_sort_indicator(col) == TriState::TRISTATE_TRUE
179 ? TriState::TRISTATE_FALSE
180 : TriState::TRISTATE_TRUE),
181 col);
182 sortColumn(col);
185 void ListView::sortColumn(const int col)
187 if (col <= 0 || col > NUMBER_OF_COLUMNS)
188 return;
190 bool isAscending = mxTreeView->get_sort_indicator(col) != TriState::TRISTATE_FALSE;
192 auto comp = [&](std::unique_ptr<ListViewItem> const& pItemA,
193 std::unique_ptr<ListViewItem> const& pItemB) {
194 sal_Int32 res = 0;
195 IntlWrapper aIntlWrapper(SvtSysLocale().GetUILanguageTag());
196 const CollatorWrapper* pCollatorWrapper = aIntlWrapper.getCollator();
197 switch (col)
199 case COLUMN_NAME:
201 OUString sNameA = pItemA->maTitle;
202 OUString sNameB = pItemB->maTitle;
203 res = pCollatorWrapper->compareString(sNameA, sNameB);
205 break;
206 case COLUMN_CATEGORY:
208 OUString sCategoryA = pItemA->maSubtitle;
209 OUString sCategoryB = pItemB->maSubtitle;
210 res = pCollatorWrapper->compareString(sCategoryA, sCategoryB);
212 break;
213 case COLUMN_MODIFIED:
215 sal_uInt32 nModA, nModB;
216 nModA = pItemA->mnModify;
217 nModB = pItemB->mnModify;
219 if (nModA < nModB)
220 res = -1;
221 else if (nModA > nModB)
222 res = 1;
224 break;
225 case COLUMN_SIZE:
227 sal_uInt64 nSizeA, nSizeB;
228 nSizeA = pItemA->mnSize;
229 nSizeB = pItemB->mnSize;
231 if (nSizeA < nSizeB)
232 res = -1;
233 else if (nSizeA > nSizeB)
234 res = 1;
236 break;
237 case COLUMN_APPLICATION:
239 OUString sPathA = pItemA->maApplication;
240 OUString sPathB = pItemB->maApplication;
241 res = pCollatorWrapper->compareString(sPathA, sPathB);
243 break;
245 return isAscending ? (res > 0) : (res < 0);
247 std::stable_sort(mListViewItems.begin(), mListViewItems.end(), comp);
249 if (!UpdateRows())
250 ReloadRows();
251 mnSortColumn = col;
254 void ListView::sort() { sortColumn(mnSortColumn); }
256 void ListView::refreshDefaultColumn()
258 for (const auto& pItem : mListViewItems)
260 bool bDefault = TemplateLocalView::IsDefaultTemplate(pItem->maPath);
261 if (pItem->mbDefault != bDefault)
263 pItem->mbDefault = bDefault;
264 OUString sImage("");
265 if (bDefault)
266 sImage = BMP_DEFAULT;
267 mxTreeView->set_image(mxTreeView->find_id(pItem->maId), sImage, COLUMN_IMG_ISDEFAULT);
272 void ListView::rename(const OUString& rId, const OUString& rTitle)
274 mxTreeView->set_text(mxTreeView->find_id(rId), rTitle, COLUMN_NAME);
275 for (const auto& pItem : mListViewItems)
276 if (pItem->maId == rId)
278 pItem->maTitle = rTitle;
279 break;
283 void ListView::clearListView()
285 mxTreeView->clear();
286 mListViewItems.clear();
289 IMPL_LINK(ListView, QueryTooltipHdl, const weld::TreeIter&, rIter, OUString)
291 OUString sId = mxTreeView->get_id(rIter);
292 for (const auto& pItem : mListViewItems)
294 if (pItem->maId == sId)
295 return pItem->maDisplayPath;
297 return OUString();
300 sal_uInt16 ListView::get_nId(int pos) const
302 return static_cast<sal_uInt16>(mxTreeView->get_id(pos).toInt32());
305 static sal_uInt32 getFileModifyTime(const OUString& rURL)
307 sal_uInt32 nModify = 0;
308 if (!comphelper::isFileUrl(rURL))
309 return nModify;
311 osl::DirectoryItem aItem;
312 if (osl::DirectoryItem::get(rURL, aItem) != osl::DirectoryItem::E_None)
313 return nModify;
315 osl::FileStatus aStatus(osl_FileStatus_Mask_ModifyTime);
316 if (aItem.getFileStatus(aStatus) != osl::DirectoryItem::E_None)
317 return nModify;
319 TimeValue systemTimeValue = aStatus.getModifyTime();
321 nModify = systemTimeValue.Seconds;
322 return nModify;
324 static OUString getDisplayFileModifyTime(const OUString& rURL)
326 if (!comphelper::isFileUrl(rURL))
327 return OUString();
329 osl::DirectoryItem aItem;
330 if (osl::DirectoryItem::get(rURL, aItem) != osl::DirectoryItem::E_None)
331 return OUString();
333 osl::FileStatus aStatus(osl_FileStatus_Mask_ModifyTime);
334 if (aItem.getFileStatus(aStatus) != osl::DirectoryItem::E_None)
335 return OUString();
337 TimeValue systemTimeValue = aStatus.getModifyTime();
338 if (systemTimeValue.Seconds == 0)
339 return OUString();
340 TimeValue localTimeValue;
341 osl_getLocalTimeFromSystemTime(&systemTimeValue, &localTimeValue);
342 const SvtSysLocale aSysLocale;
343 const LocaleDataWrapper& rLocaleWrapper = aSysLocale.GetLocaleData();
344 DateTime aDateTime = DateTime::CreateFromUnixTime(localTimeValue.Seconds);
345 OUString aDisplayDateTime
346 = rLocaleWrapper.getDate(aDateTime) + ", " + rLocaleWrapper.getTime(aDateTime, false);
347 return aDisplayDateTime;
350 static OUString getDisplayFileSize(const OUString& rURL)
352 if (!comphelper::isFileUrl(rURL))
353 return OUString();
355 osl::DirectoryItem aItem;
356 if (osl::DirectoryItem::get(rURL, aItem) != osl::DirectoryItem::E_None)
357 return OUString();
359 osl::FileStatus aStatus(osl_FileStatus_Mask_FileSize);
360 if (aItem.getFileStatus(aStatus) != osl::DirectoryItem::E_None)
361 return OUString();
363 sal_uInt64 nSize = aStatus.getFileSize();
364 double fSize(static_cast<double>(nSize));
365 sal_uInt32 nDec;
367 sal_uInt64 nMega = 1024 * 1024;
368 sal_uInt64 nGiga = nMega * 1024;
370 OUString aUnitStr(' ');
372 if (nSize < 10000)
374 aUnitStr += SvtResId(STR_SVT_BYTES);
375 nDec = 0;
377 else if (nSize < nMega)
379 fSize /= 1024;
380 aUnitStr += SvtResId(STR_SVT_KB);
381 nDec = 1;
383 else if (nSize < nGiga)
385 fSize /= nMega;
386 aUnitStr += SvtResId(STR_SVT_MB);
387 nDec = 2;
389 else
391 fSize /= nGiga;
392 aUnitStr += SvtResId(STR_SVT_GB);
393 nDec = 3;
396 OUString aSizeStr
397 = ::rtl::math::doubleToUString(fSize, rtl_math_StringFormat_F, nDec,
398 SvtSysLocale().GetLocaleData().getNumDecimalSep()[0])
399 + aUnitStr;
401 return aSizeStr;
404 static sal_uInt64 getFileSize(const OUString& rURL)
406 sal_uInt64 nSize = 0;
407 if (!comphelper::isFileUrl(rURL))
408 return nSize;
410 osl::DirectoryItem aItem;
411 if (osl::DirectoryItem::get(rURL, aItem) != osl::DirectoryItem::E_None)
412 return nSize;
414 osl::FileStatus aStatus(osl_FileStatus_Mask_FileSize);
415 if (aItem.getFileStatus(aStatus) != osl::DirectoryItem::E_None)
416 return nSize;
418 nSize = aStatus.getFileSize();
419 return nSize;
422 static OUString getApplication(std::u16string_view rURL)
424 INetURLObject aUrl(rURL);
425 OUString aExt = aUrl.getExtension();
427 if (aExt == "ott" || aExt == "stw" || aExt == "oth" || aExt == "dot" || aExt == "dotx")
429 return SfxResId(STR_DOCUMENT);
431 else if (aExt == "ots" || aExt == "stc" || aExt == "xlt" || aExt == "xltm" || aExt == "xltx")
433 return SfxResId(STR_SPREADSHEET);
435 else if (aExt == "otp" || aExt == "sti" || aExt == "pot" || aExt == "potm" || aExt == "potx")
437 return SfxResId(STR_PRESENTATION);
439 else if (aExt == "otg" || aExt == "std")
441 return SfxResId(STR_DRAWING);
443 return OUString();
446 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */