1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
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/.
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>
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
35 #define COLUMN_CATEGORY 2
36 #define COLUMN_APPLICATION 3
37 #define COLUMN_MODIFIED 4
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
))
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
);
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
;
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());
130 for (const auto& pItem
: mListViewItems
)
133 if (pItem
->mbDefault
)
134 sImage
= BMP_DEFAULT
;
135 AppendRow(sImage
, pItem
->maTitle
, pItem
->maSubtitle
, pItem
->maApplication
,
136 pItem
->maDisplayModify
, pItem
->maDisplaySize
, pItem
->maId
);
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())
150 OUString sCursorId
= get_id(get_cursor_index());
152 for (const auto& pItem
: mListViewItems
)
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
);
162 if (!sCursorId
.isEmpty())
164 select_id(sCursorId
);
165 set_cursor(get_selected_index());
170 IMPL_LINK(ListView
, ColumnClickedHdl
, const int, col
, void)
172 if (col
<= 0 || col
> NUMBER_OF_COLUMNS
)
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
),
185 void ListView::sortColumn(const int col
)
187 if (col
<= 0 || col
> NUMBER_OF_COLUMNS
)
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
) {
195 IntlWrapper
aIntlWrapper(SvtSysLocale().GetUILanguageTag());
196 const CollatorWrapper
* pCollatorWrapper
= aIntlWrapper
.getCollator();
201 OUString sNameA
= pItemA
->maTitle
;
202 OUString sNameB
= pItemB
->maTitle
;
203 res
= pCollatorWrapper
->compareString(sNameA
, sNameB
);
206 case COLUMN_CATEGORY
:
208 OUString sCategoryA
= pItemA
->maSubtitle
;
209 OUString sCategoryB
= pItemB
->maSubtitle
;
210 res
= pCollatorWrapper
->compareString(sCategoryA
, sCategoryB
);
213 case COLUMN_MODIFIED
:
215 sal_uInt32 nModA
, nModB
;
216 nModA
= pItemA
->mnModify
;
217 nModB
= pItemB
->mnModify
;
221 else if (nModA
> nModB
)
227 sal_uInt64 nSizeA
, nSizeB
;
228 nSizeA
= pItemA
->mnSize
;
229 nSizeB
= pItemB
->mnSize
;
233 else if (nSizeA
> nSizeB
)
237 case COLUMN_APPLICATION
:
239 OUString sPathA
= pItemA
->maApplication
;
240 OUString sPathB
= pItemB
->maApplication
;
241 res
= pCollatorWrapper
->compareString(sPathA
, sPathB
);
245 return isAscending
? (res
> 0) : (res
< 0);
247 std::stable_sort(mListViewItems
.begin(), mListViewItems
.end(), comp
);
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
;
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
;
283 void ListView::clearListView()
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
;
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
))
311 osl::DirectoryItem aItem
;
312 if (osl::DirectoryItem::get(rURL
, aItem
) != osl::DirectoryItem::E_None
)
315 osl::FileStatus
aStatus(osl_FileStatus_Mask_ModifyTime
);
316 if (aItem
.getFileStatus(aStatus
) != osl::DirectoryItem::E_None
)
319 TimeValue systemTimeValue
= aStatus
.getModifyTime();
321 nModify
= systemTimeValue
.Seconds
;
324 static OUString
getDisplayFileModifyTime(const OUString
& rURL
)
326 if (!comphelper::isFileUrl(rURL
))
329 osl::DirectoryItem aItem
;
330 if (osl::DirectoryItem::get(rURL
, aItem
) != osl::DirectoryItem::E_None
)
333 osl::FileStatus
aStatus(osl_FileStatus_Mask_ModifyTime
);
334 if (aItem
.getFileStatus(aStatus
) != osl::DirectoryItem::E_None
)
337 TimeValue systemTimeValue
= aStatus
.getModifyTime();
338 if (systemTimeValue
.Seconds
== 0)
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
))
355 osl::DirectoryItem aItem
;
356 if (osl::DirectoryItem::get(rURL
, aItem
) != osl::DirectoryItem::E_None
)
359 osl::FileStatus
aStatus(osl_FileStatus_Mask_FileSize
);
360 if (aItem
.getFileStatus(aStatus
) != osl::DirectoryItem::E_None
)
363 sal_uInt64 nSize
= aStatus
.getFileSize();
364 double fSize(static_cast<double>(nSize
));
367 sal_uInt64 nMega
= 1024 * 1024;
368 sal_uInt64 nGiga
= nMega
* 1024;
370 OUString
aUnitStr(' ');
374 aUnitStr
+= SvtResId(STR_SVT_BYTES
);
377 else if (nSize
< nMega
)
380 aUnitStr
+= SvtResId(STR_SVT_KB
);
383 else if (nSize
< nGiga
)
386 aUnitStr
+= SvtResId(STR_SVT_MB
);
392 aUnitStr
+= SvtResId(STR_SVT_GB
);
397 = ::rtl::math::doubleToUString(fSize
, rtl_math_StringFormat_F
, nDec
,
398 SvtSysLocale().GetLocaleData().getNumDecimalSep()[0])
404 static sal_uInt64
getFileSize(const OUString
& rURL
)
406 sal_uInt64 nSize
= 0;
407 if (!comphelper::isFileUrl(rURL
))
410 osl::DirectoryItem aItem
;
411 if (osl::DirectoryItem::get(rURL
, aItem
) != osl::DirectoryItem::E_None
)
414 osl::FileStatus
aStatus(osl_FileStatus_Mask_FileSize
);
415 if (aItem
.getFileStatus(aStatus
) != osl::DirectoryItem::E_None
)
418 nSize
= aStatus
.getFileSize();
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
);
446 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */