1
0
Fork 0
libreoffice/sfx2/source/control/listview.cxx
Daniel Baumann 8e63e14cf6
Adding upstream version 4:25.2.3.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
2025-06-22 16:20:04 +02:00

445 lines
14 KiB
C++

/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
* This file is part of the LibreOffice project.
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
#include <sfx2/listview.hxx>
#include <sfx2/sfxresid.hxx>
#include <tools/urlobj.hxx>
#include <tools/datetime.hxx>
#include <sfx2/strings.hrc>
#include <osl/file.hxx>
#include <osl/time.h>
#include <comphelper/fileurl.hxx>
#include <svtools/svtresid.hxx>
#include <svtools/strings.hrc>
#include <unotools/localedatawrapper.hxx>
#include <unotools/collatorwrapper.hxx>
#include <unotools/syslocale.hxx>
#include <unotools/intlwrapper.hxx>
#include <vcl/wintypes.hxx>
#include <bitmaps.hlst>
#include <rtl/math.hxx>
#include <sfx2/templatelocalview.hxx>
#define COLUMN_IMG_ISDEFAULT 0
#define COLUMN_NAME 1
#define COLUMN_CATEGORY 2
#define COLUMN_APPLICATION 3
#define COLUMN_MODIFIED 4
#define COLUMN_SIZE 5
#define NUMBER_OF_COLUMNS 6
static sal_uInt64 getFileSize(const OUString& rURL);
static sal_uInt32 getFileModifyTime(const OUString& rURL);
static OUString getDisplayFileSize(const OUString& rURL);
static OUString getDisplayFileModifyTime(const OUString& rURL);
static OUString getApplication(std::u16string_view rURL);
ListView::ListView(std::unique_ptr<weld::TreeView> xTreeView)
: mxTreeView(std::move(xTreeView))
, mnSortColumn(-2)
{
auto nDigitWidth = mxTreeView->get_approximate_digit_width();
std::vector<int> aWidths{
static_cast<int>(nDigitWidth * 5), /* Icon Column */
static_cast<int>(nDigitWidth * 24), /* Name Column */
static_cast<int>(nDigitWidth * 22), /* Category Column */
static_cast<int>(nDigitWidth * 15), /* Application Column */
static_cast<int>(nDigitWidth * 18) /* Modify Column */
};
// tdf#151143 Make the size of ListView and ThumbnailView the same
mxTreeView->set_size_request(TEMPLATE_ITEM_MAX_WIDTH * 5, TEMPLATE_ITEM_MAX_HEIGHT_SUB * 3);
mxTreeView->set_column_fixed_widths(aWidths);
mxTreeView->set_selection_mode(SelectionMode::Multiple);
mxTreeView->connect_query_tooltip(LINK(this, ListView, QueryTooltipHdl));
}
ListView::~ListView() {}
void ListView::AppendItem(const OUString& rId, const OUString& rTitle, const OUString& rSubtitle,
const OUString& rPath, bool bDefault)
{
INetURLObject aUrl(rPath, INetProtocol::File);
std::unique_ptr<ListViewItem> pItem(new ListViewItem);
pItem->maId = rId;
pItem->maTitle = rTitle;
pItem->maSubtitle = rSubtitle;
pItem->maApplication = getApplication(rPath);
pItem->maPath = rPath;
pItem->mbDefault = bDefault;
pItem->mnModify = getFileModifyTime(rPath);
pItem->mnSize = getFileSize(rPath);
pItem->maDisplayModify = getDisplayFileModifyTime(rPath);
pItem->maDisplaySize = getDisplayFileSize(rPath);
pItem->maDisplayPath = aUrl.getFSysPath(FSysStyle::Detect);
OUString sImage(u""_ustr);
if (pItem->mbDefault)
sImage = BMP_DEFAULT;
AppendRow(sImage, pItem->maTitle, pItem->maSubtitle, pItem->maApplication,
pItem->maDisplayModify, pItem->maDisplaySize, pItem->maId);
mListViewItems.push_back(std::move(pItem));
}
void ListView::AppendRow(const OUString& rImage, const OUString& rTitle, const OUString& rSubtitle,
const OUString& rApplication, const OUString& rModify,
const OUString& rSize, const OUString& rId)
{
std::unique_ptr<weld::TreeIter> xIter(mxTreeView->make_iterator());
mxTreeView->append(xIter.get());
mxTreeView->set_image(*xIter, rImage, COLUMN_IMG_ISDEFAULT);
mxTreeView->set_text(*xIter, rTitle, COLUMN_NAME);
mxTreeView->set_text(*xIter, rSubtitle, COLUMN_CATEGORY);
mxTreeView->set_text(*xIter, rApplication, COLUMN_APPLICATION);
mxTreeView->set_text(*xIter, rModify, COLUMN_MODIFIED);
mxTreeView->set_text(*xIter, rSize, COLUMN_SIZE);
mxTreeView->set_id(*xIter, rId);
}
void ListView::UpdateRow(int nIndex, const OUString& rImage, const OUString& rTitle,
const OUString& rSubtitle, const OUString& rApplication,
const OUString& rModify, const OUString& rSize, const OUString& rId)
{
mxTreeView->set_image(nIndex, rImage, COLUMN_IMG_ISDEFAULT);
mxTreeView->set_text(nIndex, rTitle, COLUMN_NAME);
mxTreeView->set_text(nIndex, rSubtitle, COLUMN_CATEGORY);
mxTreeView->set_text(nIndex, rApplication, COLUMN_APPLICATION);
mxTreeView->set_text(nIndex, rModify, COLUMN_MODIFIED);
mxTreeView->set_text(nIndex, rSize, COLUMN_SIZE);
mxTreeView->set_id(nIndex, rId);
}
void ListView::ReloadRows()
{
OUString sCursorId = get_id(get_cursor_index());
mxTreeView->clear();
for (const auto& pItem : mListViewItems)
{
OUString sImage(u""_ustr);
if (pItem->mbDefault)
sImage = BMP_DEFAULT;
AppendRow(sImage, pItem->maTitle, pItem->maSubtitle, pItem->maApplication,
pItem->maDisplayModify, pItem->maDisplaySize, pItem->maId);
}
unselect_all();
if (!sCursorId.isEmpty())
{
select_id(sCursorId);
set_cursor(get_selected_index());
}
}
bool ListView::UpdateRows()
{
if (static_cast<int>(mListViewItems.size()) != mxTreeView->n_children())
return false;
OUString sCursorId = get_id(get_cursor_index());
int nIndex = 0;
for (const auto& pItem : mListViewItems)
{
OUString sImage(u""_ustr);
if (pItem->mbDefault)
sImage = BMP_DEFAULT;
UpdateRow(nIndex, sImage, pItem->maTitle, pItem->maSubtitle, pItem->maApplication,
pItem->maDisplayModify, pItem->maDisplaySize, pItem->maId);
++nIndex;
}
unselect_all();
if (!sCursorId.isEmpty())
{
select_id(sCursorId);
set_cursor(get_selected_index());
}
return true;
}
IMPL_LINK(ListView, ColumnClickedHdl, const int, col, void)
{
if (col <= 0 || col > NUMBER_OF_COLUMNS)
return;
if (mnSortColumn >= 0 && mnSortColumn != col)
mxTreeView->set_sort_indicator(TriState::TRISTATE_INDET, mnSortColumn);
mxTreeView->set_sort_indicator((mxTreeView->get_sort_indicator(col) == TriState::TRISTATE_TRUE
? TriState::TRISTATE_FALSE
: TriState::TRISTATE_TRUE),
col);
sortColumn(col);
}
void ListView::sortColumn(const int col)
{
if (col <= 0 || col > NUMBER_OF_COLUMNS)
return;
bool isAscending = mxTreeView->get_sort_indicator(col) != TriState::TRISTATE_FALSE;
auto comp = [&](std::unique_ptr<ListViewItem> const& pItemA,
std::unique_ptr<ListViewItem> const& pItemB) {
sal_Int32 res = 0;
IntlWrapper aIntlWrapper(SvtSysLocale().GetUILanguageTag());
const CollatorWrapper* pCollatorWrapper = aIntlWrapper.getCollator();
switch (col)
{
case COLUMN_NAME:
{
OUString sNameA = pItemA->maTitle;
OUString sNameB = pItemB->maTitle;
res = pCollatorWrapper->compareString(sNameA, sNameB);
}
break;
case COLUMN_CATEGORY:
{
OUString sCategoryA = pItemA->maSubtitle;
OUString sCategoryB = pItemB->maSubtitle;
res = pCollatorWrapper->compareString(sCategoryA, sCategoryB);
}
break;
case COLUMN_MODIFIED:
{
sal_uInt32 nModA, nModB;
nModA = pItemA->mnModify;
nModB = pItemB->mnModify;
if (nModA < nModB)
res = -1;
else if (nModA > nModB)
res = 1;
}
break;
case COLUMN_SIZE:
{
sal_uInt64 nSizeA, nSizeB;
nSizeA = pItemA->mnSize;
nSizeB = pItemB->mnSize;
if (nSizeA < nSizeB)
res = -1;
else if (nSizeA > nSizeB)
res = 1;
}
break;
case COLUMN_APPLICATION:
{
OUString sPathA = pItemA->maApplication;
OUString sPathB = pItemB->maApplication;
res = pCollatorWrapper->compareString(sPathA, sPathB);
}
break;
}
return isAscending ? (res > 0) : (res < 0);
};
std::stable_sort(mListViewItems.begin(), mListViewItems.end(), comp);
if (!UpdateRows())
ReloadRows();
mnSortColumn = col;
}
void ListView::sort() { sortColumn(mnSortColumn); }
void ListView::refreshDefaultColumn()
{
for (const auto& pItem : mListViewItems)
{
bool bDefault = TemplateLocalView::IsDefaultTemplate(pItem->maPath);
if (pItem->mbDefault != bDefault)
{
pItem->mbDefault = bDefault;
OUString sImage(u""_ustr);
if (bDefault)
sImage = BMP_DEFAULT;
mxTreeView->set_image(mxTreeView->find_id(pItem->maId), sImage, COLUMN_IMG_ISDEFAULT);
}
}
}
void ListView::rename(const OUString& rId, const OUString& rTitle)
{
mxTreeView->set_text(mxTreeView->find_id(rId), rTitle, COLUMN_NAME);
for (const auto& pItem : mListViewItems)
if (pItem->maId == rId)
{
pItem->maTitle = rTitle;
break;
}
}
void ListView::clearListView()
{
mxTreeView->clear();
mListViewItems.clear();
}
IMPL_LINK(ListView, QueryTooltipHdl, const weld::TreeIter&, rIter, OUString)
{
OUString sId = mxTreeView->get_id(rIter);
for (const auto& pItem : mListViewItems)
{
if (pItem->maId == sId)
return pItem->maDisplayPath;
}
return OUString();
}
sal_uInt16 ListView::get_nId(int pos) const
{
return static_cast<sal_uInt16>(mxTreeView->get_id(pos).toInt32());
}
static sal_uInt32 getFileModifyTime(const OUString& rURL)
{
sal_uInt32 nModify = 0;
if (!comphelper::isFileUrl(rURL))
return nModify;
osl::DirectoryItem aItem;
if (osl::DirectoryItem::get(rURL, aItem) != osl::DirectoryItem::E_None)
return nModify;
osl::FileStatus aStatus(osl_FileStatus_Mask_ModifyTime);
if (aItem.getFileStatus(aStatus) != osl::DirectoryItem::E_None)
return nModify;
TimeValue systemTimeValue = aStatus.getModifyTime();
nModify = systemTimeValue.Seconds;
return nModify;
}
static OUString getDisplayFileModifyTime(const OUString& rURL)
{
if (!comphelper::isFileUrl(rURL))
return OUString();
osl::DirectoryItem aItem;
if (osl::DirectoryItem::get(rURL, aItem) != osl::DirectoryItem::E_None)
return OUString();
osl::FileStatus aStatus(osl_FileStatus_Mask_ModifyTime);
if (aItem.getFileStatus(aStatus) != osl::DirectoryItem::E_None)
return OUString();
TimeValue systemTimeValue = aStatus.getModifyTime();
if (systemTimeValue.Seconds == 0)
return OUString();
TimeValue localTimeValue;
osl_getLocalTimeFromSystemTime(&systemTimeValue, &localTimeValue);
const SvtSysLocale aSysLocale;
const LocaleDataWrapper& rLocaleWrapper = aSysLocale.GetLocaleData();
DateTime aDateTime = DateTime::CreateFromUnixTime(localTimeValue.Seconds);
OUString aDisplayDateTime
= rLocaleWrapper.getDate(aDateTime) + ", " + rLocaleWrapper.getTime(aDateTime, false);
return aDisplayDateTime;
}
static OUString getDisplayFileSize(const OUString& rURL)
{
if (!comphelper::isFileUrl(rURL))
return OUString();
osl::DirectoryItem aItem;
if (osl::DirectoryItem::get(rURL, aItem) != osl::DirectoryItem::E_None)
return OUString();
osl::FileStatus aStatus(osl_FileStatus_Mask_FileSize);
if (aItem.getFileStatus(aStatus) != osl::DirectoryItem::E_None)
return OUString();
sal_uInt64 nSize = aStatus.getFileSize();
double fSize(static_cast<double>(nSize));
sal_uInt32 nDec;
sal_uInt64 nMega = 1024 * 1024;
sal_uInt64 nGiga = nMega * 1024;
OUString aUnitStr(' ');
if (nSize < 10000)
{
aUnitStr += SvtResId(STR_SVT_BYTES);
nDec = 0;
}
else if (nSize < nMega)
{
fSize /= 1024;
aUnitStr += SvtResId(STR_SVT_KB);
nDec = 1;
}
else if (nSize < nGiga)
{
fSize /= nMega;
aUnitStr += SvtResId(STR_SVT_MB);
nDec = 2;
}
else
{
fSize /= nGiga;
aUnitStr += SvtResId(STR_SVT_GB);
nDec = 3;
}
OUString aSizeStr
= ::rtl::math::doubleToUString(fSize, rtl_math_StringFormat_F, nDec,
SvtSysLocale().GetLocaleData().getNumDecimalSep()[0])
+ aUnitStr;
return aSizeStr;
}
static sal_uInt64 getFileSize(const OUString& rURL)
{
sal_uInt64 nSize = 0;
if (!comphelper::isFileUrl(rURL))
return nSize;
osl::DirectoryItem aItem;
if (osl::DirectoryItem::get(rURL, aItem) != osl::DirectoryItem::E_None)
return nSize;
osl::FileStatus aStatus(osl_FileStatus_Mask_FileSize);
if (aItem.getFileStatus(aStatus) != osl::DirectoryItem::E_None)
return nSize;
nSize = aStatus.getFileSize();
return nSize;
}
static OUString getApplication(std::u16string_view rURL)
{
INetURLObject aUrl(rURL);
OUString aExt = aUrl.getExtension();
if (aExt == "ott" || aExt == "stw" || aExt == "oth" || aExt == "dot" || aExt == "dotx")
{
return SfxResId(STR_DOCUMENT);
}
else if (aExt == "ots" || aExt == "stc" || aExt == "xlt" || aExt == "xltm" || aExt == "xltx")
{
return SfxResId(STR_SPREADSHEET);
}
else if (aExt == "otp" || aExt == "sti" || aExt == "pot" || aExt == "potm" || aExt == "potx")
{
return SfxResId(STR_PRESENTATION);
}
else if (aExt == "otg" || aExt == "std")
{
return SfxResId(STR_DRAWING);
}
return OUString();
}
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */