LibreOffice Module sfx2 (master) 1
listview.cxx
Go to the documentation of this file.
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
10#include <sfx2/listview.hxx>
11
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>
19
20#include <svtools/svtresid.hxx>
21#include <svtools/strings.hrc>
26#include <vcl/wintypes.hxx>
27
28#include <bitmaps.hlst>
29#include <rtl/math.hxx>
30
32
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
40
41static sal_uInt64 getFileSize(const OUString& rURL);
42static sal_uInt32 getFileModifyTime(const OUString& rURL);
43static OUString getDisplayFileSize(const OUString& rURL);
44static OUString getDisplayFileModifyTime(const OUString& rURL);
45static OUString getApplication(std::u16string_view rURL);
46
47ListView::ListView(std::unique_ptr<weld::TreeView> xTreeView)
48 : mxTreeView(std::move(xTreeView))
49 , mnSortColumn(-2)
50{
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 */
58 };
59
60 // tdf#151143 Make the size of ListView and ThumbnailView the same
62
63 mxTreeView->set_column_fixed_widths(aWidths);
64 mxTreeView->set_selection_mode(SelectionMode::Multiple);
65 mxTreeView->connect_query_tooltip(LINK(this, ListView, QueryTooltipHdl));
66}
68
69void ListView::AppendItem(const OUString& rId, const OUString& rTitle, const OUString& rSubtitle,
70 const OUString& rPath, bool bDefault)
71{
72 INetURLObject aUrl(rPath, INetProtocol::File);
73 OUString sPath = aUrl.getFSysPath(FSysStyle::Detect);
74
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;
87
88 OUString sImage("");
89 if (pItem->mbDefault)
90 sImage = BMP_DEFAULT;
91
92 AppendRow(sImage, pItem->maTitle, pItem->maSubtitle, pItem->maApplication,
93 pItem->maDisplayModify, pItem->maDisplaySize, pItem->maId);
94
95 mListViewItems.push_back(std::move(pItem));
96}
97
98void 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)
101{
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);
111}
112
113void 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)
116{
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);
124}
125
127{
128 OUString sCursorId = get_id(get_cursor_index());
129 mxTreeView->clear();
130 for (const auto& pItem : mListViewItems)
131 {
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);
137 }
138 unselect_all();
139 if (!sCursorId.isEmpty())
140 {
141 select_id(sCursorId);
143 }
144}
145
147{
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)
153 {
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;
160 }
161 unselect_all();
162 if (!sCursorId.isEmpty())
163 {
164 select_id(sCursorId);
166 }
167 return true;
168}
169
170IMPL_LINK(ListView, ColumnClickedHdl, const int, col, void)
171{
172 if (col <= 0 || col > NUMBER_OF_COLUMNS)
173 return;
174
175 if (mnSortColumn >= 0 && mnSortColumn != col)
176 mxTreeView->set_sort_indicator(TriState::TRISTATE_INDET, mnSortColumn);
177
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);
183}
184
185void ListView::sortColumn(const int col)
186{
187 if (col <= 0 || col > NUMBER_OF_COLUMNS)
188 return;
189
190 bool isAscending = mxTreeView->get_sort_indicator(col) != TriState::TRISTATE_FALSE;
191
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)
198 {
199 case COLUMN_NAME:
200 {
201 OUString sNameA = pItemA->maTitle;
202 OUString sNameB = pItemB->maTitle;
203 res = pCollatorWrapper->compareString(sNameA, sNameB);
204 }
205 break;
206 case COLUMN_CATEGORY:
207 {
208 OUString sCategoryA = pItemA->maSubtitle;
209 OUString sCategoryB = pItemB->maSubtitle;
210 res = pCollatorWrapper->compareString(sCategoryA, sCategoryB);
211 }
212 break;
213 case COLUMN_MODIFIED:
214 {
215 sal_uInt32 nModA, nModB;
216 nModA = pItemA->mnModify;
217 nModB = pItemB->mnModify;
218
219 if (nModA < nModB)
220 res = -1;
221 else if (nModA > nModB)
222 res = 1;
223 }
224 break;
225 case COLUMN_SIZE:
226 {
227 sal_uInt64 nSizeA, nSizeB;
228 nSizeA = pItemA->mnSize;
229 nSizeB = pItemB->mnSize;
230
231 if (nSizeA < nSizeB)
232 res = -1;
233 else if (nSizeA > nSizeB)
234 res = 1;
235 }
236 break;
238 {
239 OUString sPathA = pItemA->maApplication;
240 OUString sPathB = pItemB->maApplication;
241 res = pCollatorWrapper->compareString(sPathA, sPathB);
242 }
243 break;
244 }
245 return isAscending ? (res > 0) : (res < 0);
246 };
247 std::stable_sort(mListViewItems.begin(), mListViewItems.end(), comp);
248
249 if (!UpdateRows())
250 ReloadRows();
252}
253
255
257{
258 for (const auto& pItem : mListViewItems)
259 {
260 bool bDefault = TemplateLocalView::IsDefaultTemplate(pItem->maPath);
261 if (pItem->mbDefault != bDefault)
262 {
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);
268 }
269 }
270}
271
272void ListView::rename(const OUString& rId, const OUString& rTitle)
273{
274 mxTreeView->set_text(mxTreeView->find_id(rId), rTitle, COLUMN_NAME);
275 for (const auto& pItem : mListViewItems)
276 if (pItem->maId == rId)
277 {
278 pItem->maTitle = rTitle;
279 break;
280 }
281}
282
284{
285 mxTreeView->clear();
286 mListViewItems.clear();
287}
288
289IMPL_LINK(ListView, QueryTooltipHdl, const weld::TreeIter&, rIter, OUString)
290{
291 OUString sId = mxTreeView->get_id(rIter);
292 for (const auto& pItem : mListViewItems)
293 {
294 if (pItem->maId == sId)
295 return pItem->maDisplayPath;
296 }
297 return OUString();
298}
299
300sal_uInt16 ListView::get_nId(int pos) const
301{
302 return static_cast<sal_uInt16>(mxTreeView->get_id(pos).toInt32());
303}
304
305static sal_uInt32 getFileModifyTime(const OUString& rURL)
306{
307 sal_uInt32 nModify = 0;
308 if (!comphelper::isFileUrl(rURL))
309 return nModify;
310
311 osl::DirectoryItem aItem;
312 if (osl::DirectoryItem::get(rURL, aItem) != osl::DirectoryItem::E_None)
313 return nModify;
314
315 osl::FileStatus aStatus(osl_FileStatus_Mask_ModifyTime);
316 if (aItem.getFileStatus(aStatus) != osl::DirectoryItem::E_None)
317 return nModify;
318
319 TimeValue systemTimeValue = aStatus.getModifyTime();
320
321 nModify = systemTimeValue.Seconds;
322 return nModify;
323}
324static OUString getDisplayFileModifyTime(const OUString& rURL)
325{
326 if (!comphelper::isFileUrl(rURL))
327 return OUString();
328
329 osl::DirectoryItem aItem;
330 if (osl::DirectoryItem::get(rURL, aItem) != osl::DirectoryItem::E_None)
331 return OUString();
332
333 osl::FileStatus aStatus(osl_FileStatus_Mask_ModifyTime);
334 if (aItem.getFileStatus(aStatus) != osl::DirectoryItem::E_None)
335 return OUString();
336
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;
348}
349
350static OUString getDisplayFileSize(const OUString& rURL)
351{
352 if (!comphelper::isFileUrl(rURL))
353 return OUString();
354
355 osl::DirectoryItem aItem;
356 if (osl::DirectoryItem::get(rURL, aItem) != osl::DirectoryItem::E_None)
357 return OUString();
358
359 osl::FileStatus aStatus(osl_FileStatus_Mask_FileSize);
360 if (aItem.getFileStatus(aStatus) != osl::DirectoryItem::E_None)
361 return OUString();
362
363 sal_uInt64 nSize = aStatus.getFileSize();
364 double fSize(static_cast<double>(nSize));
365 sal_uInt32 nDec;
366
367 sal_uInt64 nMega = 1024 * 1024;
368 sal_uInt64 nGiga = nMega * 1024;
369
370 OUString aUnitStr(' ');
371
372 if (nSize < 10000)
373 {
374 aUnitStr += SvtResId(STR_SVT_BYTES);
375 nDec = 0;
376 }
377 else if (nSize < nMega)
378 {
379 fSize /= 1024;
380 aUnitStr += SvtResId(STR_SVT_KB);
381 nDec = 1;
382 }
383 else if (nSize < nGiga)
384 {
385 fSize /= nMega;
386 aUnitStr += SvtResId(STR_SVT_MB);
387 nDec = 2;
388 }
389 else
390 {
391 fSize /= nGiga;
392 aUnitStr += SvtResId(STR_SVT_GB);
393 nDec = 3;
394 }
395
396 OUString aSizeStr
397 = ::rtl::math::doubleToUString(fSize, rtl_math_StringFormat_F, nDec,
398 SvtSysLocale().GetLocaleData().getNumDecimalSep()[0])
399 + aUnitStr;
400
401 return aSizeStr;
402}
403
404static sal_uInt64 getFileSize(const OUString& rURL)
405{
406 sal_uInt64 nSize = 0;
407 if (!comphelper::isFileUrl(rURL))
408 return nSize;
409
410 osl::DirectoryItem aItem;
411 if (osl::DirectoryItem::get(rURL, aItem) != osl::DirectoryItem::E_None)
412 return nSize;
413
414 osl::FileStatus aStatus(osl_FileStatus_Mask_FileSize);
415 if (aItem.getFileStatus(aStatus) != osl::DirectoryItem::E_None)
416 return nSize;
417
418 nSize = aStatus.getFileSize();
419 return nSize;
420}
421
422static OUString getApplication(std::u16string_view rURL)
423{
424 INetURLObject aUrl(rURL);
425 OUString aExt = aUrl.getExtension();
426
427 if (aExt == "ott" || aExt == "stw" || aExt == "oth" || aExt == "dot" || aExt == "dotx")
428 {
429 return SfxResId(STR_DOCUMENT);
430 }
431 else if (aExt == "ots" || aExt == "stc" || aExt == "xlt" || aExt == "xltm" || aExt == "xltx")
432 {
433 return SfxResId(STR_SPREADSHEET);
434 }
435 else if (aExt == "otp" || aExt == "sti" || aExt == "pot" || aExt == "potm" || aExt == "potx")
436 {
437 return SfxResId(STR_PRESENTATION);
438 }
439 else if (aExt == "otg" || aExt == "std")
440 {
441 return SfxResId(STR_DRAWING);
442 }
443 return OUString();
444}
445
446/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
sal_Int32 compareString(const OUString &s1, const OUString &s2) const
static DateTime CreateFromUnixTime(const double fSecondsSinceEpoch)
OUString getExtension(sal_Int32 nIndex=LAST_SEGMENT, bool bIgnoreFinalSlash=true, DecodeMechanism eMechanism=DecodeMechanism::ToIUri, rtl_TextEncoding eCharset=RTL_TEXTENCODING_UTF8) const
OUString getFSysPath(FSysStyle eStyle, sal_Unicode *pDelimiter=nullptr) const
const CollatorWrapper * getCollator() const
void rename(const OUString &rId, const OUString &rTitle)
Definition: listview.cxx:272
void UpdateRow(int nIndex, const OUString &rImage, const OUString &rTitle, const OUString &rSubtitle, const OUString &rApplication, const OUString &rModify, const OUString &rSize, const OUString &rId)
Definition: listview.cxx:113
std::vector< std::unique_ptr< ListViewItem > > mListViewItems
Definition: listview.hxx:91
ListView(std::unique_ptr< weld::TreeView > xTreeView)
Definition: listview.cxx:47
int get_selected_index() const
Definition: listview.hxx:67
void ReloadRows()
Definition: listview.cxx:126
OUString get_id(int pos) const
Definition: listview.hxx:73
int mnSortColumn
Definition: listview.hxx:92
void AppendItem(const OUString &rId, const OUString &rTitle, const OUString &rSubtitle, const OUString &rPath, bool bDefault)
Definition: listview.cxx:69
void unselect_all()
Definition: listview.hxx:54
bool UpdateRows()
Definition: listview.cxx:146
std::unique_ptr< weld::TreeView > mxTreeView
Definition: listview.hxx:90
void AppendRow(const OUString &rImage, const OUString &rTitle, const OUString &rSubtitle, const OUString &rApplication, const OUString &rModify, const OUString &rSize, const OUString &rId)
Definition: listview.cxx:98
int get_cursor_index() const
Definition: listview.hxx:77
void clearListView()
Definition: listview.cxx:283
void sort()
Definition: listview.cxx:254
void refreshDefaultColumn()
Definition: listview.cxx:256
sal_uInt16 get_nId(int pos) const
Definition: listview.cxx:300
void select_id(const OUString &sId)
Definition: listview.hxx:65
~ListView()
Definition: listview.cxx:67
void sortColumn(const int col)
Definition: listview.cxx:185
void set_cursor(int pos)
Definition: listview.hxx:75
OUString getDate(const Date &rDate) const
OUString getTime(const tools::Time &rTime, bool bSec=true, bool b100Sec=false) const
const LocaleDataWrapper & GetLocaleData() const
static bool IsDefaultTemplate(const OUString &rPath)
sal_Int32 nIndex
static OUString getApplication(std::u16string_view rURL)
Definition: listview.cxx:422
#define NUMBER_OF_COLUMNS
Definition: listview.cxx:39
static OUString getDisplayFileModifyTime(const OUString &rURL)
Definition: listview.cxx:324
#define COLUMN_APPLICATION
Definition: listview.cxx:36
#define COLUMN_MODIFIED
Definition: listview.cxx:37
#define COLUMN_SIZE
Definition: listview.cxx:38
#define COLUMN_NAME
Definition: listview.cxx:34
static OUString getDisplayFileSize(const OUString &rURL)
Definition: listview.cxx:350
#define COLUMN_IMG_ISDEFAULT
Definition: listview.cxx:33
static sal_uInt32 getFileModifyTime(const OUString &rURL)
Definition: listview.cxx:305
IMPL_LINK(ListView, ColumnClickedHdl, const int, col, void)
Definition: listview.cxx:170
static sal_uInt64 getFileSize(const OUString &rURL)
Definition: listview.cxx:404
#define COLUMN_CATEGORY
Definition: listview.cxx:35
RttiCompleteObjectLocator col
COMPHELPER_DLLPUBLIC bool isFileUrl(std::u16string_view url)
comp
const LocaleDataWrapper & GetLocaleData()
OUString SfxResId(TranslateId aId)
Definition: sfxresid.cxx:22
SVT_DLLPUBLIC OUString SvtResId(TranslateId aId)
#define TEMPLATE_ITEM_MAX_HEIGHT_SUB
#define TEMPLATE_ITEM_MAX_WIDTH
const CollatorWrapper * pCollatorWrapper
OUString sId
size_t pos