diff --git a/far/changelog b/far/changelog index f1dd71e700..a5a75625e6 100644 --- a/far/changelog +++ b/far/changelog @@ -1,4 +1,14 @@ -drkns 26.03.2016 01:03:37 +0200 - build 4602 +drkns 26.03.2016 21:16:07 +0200 - build 4603 + +1. Продолжим начатое в 4602. Запрашиваем дополнительную информацию о файлах тоже по мере необходимости. Это относится к: + - количество жёстких ссылок + - количество потоков + - размер потоков + - владелец + - content data + Это значит, что включение всего этого хозяйства не должно замедлять открытие папки, кроме случаев, когда оно является критерием сортировки. + +drkns 26.03.2016 01:03:37 +0200 - build 4602 1. Раскрашиваем файлы в панели не все сразу, а по мере необходимости. Должно дать заметный эффект при большом количестве групп и/или файлов. diff --git a/far/common.hpp b/far/common.hpp index 334b90126c..9b49e4c3ad 100644 --- a/far/common.hpp +++ b/far/common.hpp @@ -238,6 +238,4 @@ namespace \ #define SIGN_UTF8 0xBFBBEF #define EOL_STR L"\r\n" -typedef std::wstring string; - #endif // COMMON_HPP_1BD5AB87_3379_4AFE_9F63_DB850DCF72B4 diff --git a/far/common/preprocessor.hpp b/far/common/preprocessor.hpp index 5e369145ea..6fe72638ae 100644 --- a/far/common/preprocessor.hpp +++ b/far/common/preprocessor.hpp @@ -93,9 +93,12 @@ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. Type(const Type&) = delete; \ Type& operator=(const Type&) = delete; \ +#define COPY_AND_SWAP(Type, ...) \ +Type& operator=(__VA_ARGS__ rhs) { Type Tmp(rhs); using std::swap; swap(*this, Tmp); return *this; } + #define TRIVIALLY_COPYABLE(Type) \ Type(const Type&) = default; \ -Type& operator=(const Type& rhs) { Type Tmp(rhs); using std::swap; swap(*this, Tmp); return *this; } +COPY_AND_SWAP(Type, const Type&) #define TRIVIALLY_MOVABLE(Type) \ Type(Type&&) = default; \ diff --git a/far/filelist.cpp b/far/filelist.cpp index 9493128e6c..f5d80dc7f9 100644 --- a/far/filelist.cpp +++ b/far/filelist.cpp @@ -98,6 +98,7 @@ static panel_mode ListPanelMode(panel_mode::NORMAL_PANEL); static int ListNumericSort,ListCaseSensitiveSort; static PluginHandle* hSortPlugin; + enum SELECT_MODES { SELECT_INVERT, @@ -115,10 +116,13 @@ enum SELECT_MODES namespace custom_sort { + static FileList* FileListPtr; -static void FileListToSortingPanelItem(const FileListItem *arr, int index, SortingPanelItem& pi) +static void FileListToSortingPanelItem(const FileListItem *arr, int index, SortingPanelItem* ppi) { - const FileListItem& fi = arr[index]; + const auto& fi = arr[index]; + auto& pi = *ppi; + pi.FileName = fi.strName.data(); //! CHANGED pi.AlternateFileName = fi.strShortName.data(); //! CHANGED pi.FileSize=fi.FileSize; @@ -128,7 +132,7 @@ static void FileListToSortingPanelItem(const FileListItem *arr, int index, Sorti pi.CreationTime=fi.CreationTime; pi.LastAccessTime=fi.AccessTime; pi.ChangeTime=fi.ChangeTime; - pi.NumberOfLinks=fi.NumberOfLinks; + pi.NumberOfLinks = fi.NumberOfLinks(FileListPtr); pi.Flags=fi.UserFlags; if (fi.Selected) @@ -144,9 +148,9 @@ static void FileListToSortingPanelItem(const FileListItem *arr, int index, Sorti pi.CRC32=fi.CRC32; pi.Position=fi.Position; //! CHANGED pi.SortGroup=fi.SortGroup - DEFAULT_SORT_GROUP; //! CHANGED - pi.Owner = EmptyToNull(fi.strOwner.data()); - pi.NumberOfStreams=fi.NumberOfStreams; - pi.StreamsSize=fi.StreamsSize; + pi.Owner = EmptyToNull(fi.Owner(FileListPtr).data()); + pi.NumberOfStreams=fi.NumberOfStreams(FileListPtr); + pi.StreamsSize=fi.StreamsSize(FileListPtr); } struct CustomSort @@ -154,7 +158,7 @@ struct CustomSort unsigned int *Positions; const FileListItem *Items; size_t ItemsCount; - decltype(FileListToSortingPanelItem)* FileListToPluginItem; + void(*FileListToPluginItem)(const FileListItem*, int, SortingPanelItem*); int ListSortGroups; int ListSelectedFirst; int ListDirectoriesFirst; @@ -193,6 +197,90 @@ bool CanSort(int SortMode) }; +FileListItem::FileListItem() +{ + ClearStruct(static_cast(*this)); + m_Owner.assign(1, values::uninitialised(wchar_t())); +} + +inline static string GetItemFullName(const FileListItem& Item, const FileList* Owner) +{ + return Owner->GetCurDir() + L"\\"s + (TestParentFolderName(Item.strName) ? L""s : Item.strName); +} + +DWORD FileListItem::NumberOfLinks(const FileList* Owner) const +{ + if (m_NumberOfLinks == values::uninitialised(m_NumberOfLinks)) + { + if (FileAttr & FILE_ATTRIBUTE_DIRECTORY || !Owner->HardlinksSupported()) + { + m_NumberOfLinks = 1; + } + else + { + SCOPED_ACTION(elevation::suppress); + auto Value = GetNumberOfLinks(GetItemFullName(*this, Owner), true); + m_NumberOfLinks = Value < 0 ? values::unknown(m_NumberOfLinks) : Value; + } + } + return m_NumberOfLinks; +} + +static void GetStreamsCountAndSize(const FileList* Owner, const FileListItem& Item, uint64_t& StreamsSize, DWORD& NumberOfStreams, bool Supported) +{ + if (!Supported) + { + StreamsSize = Item.FileSize; + NumberOfStreams = 1; + } + else + { + SCOPED_ACTION(elevation::suppress); + + if (!EnumStreams(GetItemFullName(Item, Owner), StreamsSize, NumberOfStreams)) + { + StreamsSize = FileListItem::values::unknown(StreamsSize); + NumberOfStreams = FileListItem::values::unknown(NumberOfStreams); + } + } +} + +DWORD FileListItem::NumberOfStreams(const FileList* Owner) const +{ + if (m_NumberOfStreams == values::uninitialised(m_NumberOfStreams)) + { + GetStreamsCountAndSize(Owner, *this, m_StreamsSize, m_NumberOfStreams, Owner->StreamsSupported()); + } + return m_NumberOfStreams; +} + +unsigned long long FileListItem::StreamsSize(const FileList* Owner) const +{ + if (m_StreamsSize == values::uninitialised(m_StreamsSize)) + { + GetStreamsCountAndSize(Owner, *this, m_StreamsSize, m_NumberOfStreams, Owner->StreamsSupported()); + } + return m_StreamsSize; +} + +const string& FileListItem::Owner(const FileList* Owner) const +{ + if (m_Owner.size() == 1 && m_Owner.front() == values::uninitialised(wchar_t())) + { + GetFileOwner(Owner->GetComputerName(), GetItemFullName(*this, Owner), m_Owner); + } + return m_Owner; +} + +const content_data_ptr& FileListItem::ContentData(const FileList* Owner) const +{ + if (!m_ContentData) + { + m_ContentData = Owner->GetContentData(GetItemFullName(*this, Owner)); + } + return m_ContentData; +} + struct FileList::PrevDataItem { NONCOPYABLE(PrevDataItem); @@ -249,7 +337,9 @@ FileList::FileList(private_tag, window_ptr Owner): CacheSelClearIndex(-1), CacheSelClearPos(0), CustomSortIndicator(), - m_CachedOpenPanelInfo() + m_CachedOpenPanelInfo(), + m_HardlinksSupported(), + m_StreamsSupported() { _OT(SysLog(L"[%p] FileList::FileList()", this)); { @@ -375,8 +465,10 @@ void FileList::CorrectPosition() m_CurTopFile=m_CurFile-m_Columns*m_Height+1; } -static struct list_less +class list_less { +public: + list_less(const FileList* Owner): m_Owner(Owner) {} bool operator()(const FileListItem& a, const FileListItem& b) const { const auto less_opt = [](bool less) @@ -429,8 +521,8 @@ static struct list_less if (hSortPlugin) { PluginPanelItem pi1, pi2; - FileList::FileListToPluginItem(a, pi1); - FileList::FileListToPluginItem(b, pi2); + m_Owner->FileListToPluginItem(a, pi1); + m_Owner->FileListToPluginItem(b, pi2); pi1.Flags = a.Selected? PPIF_SELECTED : 0; pi2.Flags = b.Selected? PPIF_SELECTED : 0; RetCode = Global->CtrlObject->Plugins->Compare(hSortPlugin, &pi1, &pi2, static_cast(ListSortMode) + (SM_UNSORTED - static_cast(panel_sort::UNSORTED))); @@ -532,7 +624,7 @@ static struct list_less break; case panel_sort::BY_OWNER: - RetCode = StrCmpI(a.strOwner, b.strOwner); + RetCode = StrCmpI(a.Owner(m_Owner), b.Owner(m_Owner)); if (RetCode) return less_opt(RetCode < 0); break; @@ -543,19 +635,28 @@ static struct list_less break; case panel_sort::BY_NUMLINKS: - if (a.NumberOfLinks != b.NumberOfLinks) - return less_opt(a.NumberOfLinks < b.NumberOfLinks); - break; + { + const auto aValue{ a.NumberOfLinks(m_Owner) }, bValue{ b.NumberOfLinks(m_Owner) }; + if (aValue != bValue) + return less_opt(aValue < bValue); + } + break; case panel_sort::BY_NUMSTREAMS: - if (a.NumberOfStreams != b.NumberOfStreams) - return less_opt(a.NumberOfStreams < b.NumberOfStreams); - break; + { + const auto aValue{ a.NumberOfStreams(m_Owner) }, bValue{ b.NumberOfStreams(m_Owner) }; + if (aValue != bValue) + return less_opt(aValue < bValue); + } + break; case panel_sort::BY_STREAMSSIZE: - if (a.StreamsSize != b.StreamsSize) - return less_opt(a.StreamsSize < b.StreamsSize); - break; + { + const auto aValue{ a.StreamsSize(m_Owner) }, bValue{ b.StreamsSize(m_Owner) }; + if (aValue != bValue) + return less_opt(aValue < bValue); + } + break; case panel_sort::BY_FULLNAME: UseReverseNameSort = true; @@ -649,8 +750,11 @@ static struct list_less return UseReverseNameSort? less_opt(NameCmp < 0) : NameCmp < 0; } -} -ListLess; + +private: + const FileList* const m_Owner; +}; + void FileList::SortFileList(int KeepPosition) { @@ -683,11 +787,12 @@ void FileList::SortFileList(int KeepPosition) if (m_SortMode < panel_sort::COUNT) { - std::sort(ALL_RANGE(m_ListData), ListLess); + std::sort(ALL_RANGE(m_ListData), list_less(this)); } else { custom_sort::CustomSort cs; + custom_sort::FileListPtr = this; std::vector Positions(m_ListData.size()); std::iota(ALL_RANGE(Positions), 0); cs.Positions = Positions.data(); @@ -3612,10 +3717,14 @@ bool FileList::GetPlainString(string& Dest, int ListPos) const case PACKED_COLUMN: case STREAMSSIZE_COLUMN: { + const auto SizeToDisplay = (ColumnType == PACKED_COLUMN) + ? m_ListData[ListPos].AllocationSize + : (ColumnType == STREAMSSIZE_COLUMN) + ? m_ListData[ListPos].StreamsSize() + : m_ListData[ListPos].FileSize; + Dest.append(FormatStr_Size( - m_ListData[ListPos].FileSize, - m_ListData[ListPos].AllocationSize, - m_ListData[ListPos].StreamsSize, + SizeToDisplay, m_ListData[ListPos].strName, m_ListData[ListPos].FileAttr, m_ListData[ListPos].ShowFolderSize, @@ -5455,7 +5564,7 @@ int FileList::FileNameToPluginItem(const string& Name,PluginPanelItem& pi) } -void FileList::FileListToPluginItem(const FileListItem& fi, PluginPanelItem& pi) +void FileList::FileListToPluginItem(const FileListItem& fi, PluginPanelItem& pi) const { pi.FileName = DuplicateString(fi.strName.data()); pi.AlternateFileName = DuplicateString(fi.strShortName.data()); @@ -5466,7 +5575,7 @@ void FileList::FileListToPluginItem(const FileListItem& fi, PluginPanelItem& pi) pi.CreationTime=fi.CreationTime; pi.LastAccessTime=fi.AccessTime; pi.ChangeTime=fi.ChangeTime; - pi.NumberOfLinks=fi.NumberOfLinks; + pi.NumberOfLinks=fi.NumberOfLinks(this); pi.Flags=fi.UserFlags; if (fi.Selected) @@ -5481,10 +5590,10 @@ void FileList::FileListToPluginItem(const FileListItem& fi, PluginPanelItem& pi) pi.CRC32=fi.CRC32; pi.Reserved[0]=pi.Reserved[1]=0; - pi.Owner = EmptyToNull(fi.strOwner.data()); + pi.Owner = EmptyToNull(fi.Owner(this).data()); } -size_t FileList::FileListToPluginItem2(const FileListItem& fi,FarGetPluginPanelItem* gpi) +size_t FileList::FileListToPluginItem2(const FileListItem& fi,FarGetPluginPanelItem* gpi) const { size_t size = aligned_sizeof::value, offset = size; size+=fi.CustomColumnNumber*sizeof(wchar_t*); @@ -5492,7 +5601,7 @@ size_t FileList::FileListToPluginItem2(const FileListItem& fi,FarGetPluginPanelI size+=sizeof(wchar_t)*(fi.strShortName.size()+1); size+=std::accumulate(fi.CustomColumnData, fi.CustomColumnData + fi.CustomColumnNumber, size_t(0), [](size_t size, const wchar_t* i) { return size + (i? (wcslen(i) + 1) * sizeof(wchar_t) : 0); }); size+=fi.DizText?sizeof(wchar_t)*(wcslen(fi.DizText)+1):0; - size+=fi.strOwner.empty()?0:sizeof(wchar_t)*(fi.strOwner.size()+1); + size += fi.Owner(this).empty()? 0 : sizeof(wchar_t) * (fi.Owner(this).size() + 1); if (gpi) { @@ -5507,7 +5616,7 @@ size_t FileList::FileListToPluginItem2(const FileListItem& fi,FarGetPluginPanelI gpi->Item->CreationTime=fi.CreationTime; gpi->Item->LastAccessTime=fi.AccessTime; gpi->Item->ChangeTime=fi.ChangeTime; - gpi->Item->NumberOfLinks=fi.NumberOfLinks; + gpi->Item->NumberOfLinks = fi.NumberOfLinks(this); gpi->Item->Flags=fi.UserFlags; if (fi.Selected) gpi->Item->Flags|=PPIF_SELECTED; @@ -5551,74 +5660,74 @@ size_t FileList::FileListToPluginItem2(const FileListItem& fi,FarGetPluginPanelI } - if (fi.strOwner.empty()) + if (fi.Owner(this).empty()) { gpi->Item->Owner=nullptr; } else { - gpi->Item->Owner=wcscpy((wchar_t*)data,fi.strOwner.data()); + gpi->Item->Owner = wcscpy((wchar_t*)data, fi.Owner(this).data()); } } } return size; } -void FileList::PluginToFileListItem(const PluginPanelItem& pi,FileListItem& fi) +FileListItem::FileListItem(const PluginPanelItem& pi) { - fi.strName = NullToEmpty(pi.FileName); - fi.strShortName = NullToEmpty(pi.AlternateFileName); - fi.strOwner = NullToEmpty(pi.Owner); + strName = NullToEmpty(pi.FileName); + strShortName = NullToEmpty(pi.AlternateFileName); + m_Owner = NullToEmpty(pi.Owner); if (pi.Description) { auto Str = new wchar_t[wcslen(pi.Description)+1]; wcscpy(Str, pi.Description); - fi.DizText = Str; + DizText = Str; } else { - fi.DizText = nullptr; + DizText = nullptr; } - fi.FileSize=pi.FileSize; - fi.AllocationSize=pi.AllocationSize; - fi.FileAttr=pi.FileAttributes; - fi.WriteTime=pi.LastWriteTime; - fi.CreationTime=pi.CreationTime; - fi.AccessTime=pi.LastAccessTime; - fi.ChangeTime = pi.ChangeTime; - fi.NumberOfLinks=pi.NumberOfLinks; - fi.NumberOfStreams=1; - fi.UserFlags=pi.Flags; + FileSize = pi.FileSize; + AllocationSize = pi.AllocationSize; + FileAttr = pi.FileAttributes; + WriteTime = pi.LastWriteTime; + CreationTime = pi.CreationTime; + AccessTime = pi.LastAccessTime; + ChangeTime = pi.ChangeTime; + m_NumberOfLinks = pi.NumberOfLinks; + m_NumberOfStreams = 1; + UserFlags = pi.Flags; - fi.UserData=pi.UserData.Data; - fi.Callback=pi.UserData.FreeData; + UserData = pi.UserData.Data; + Callback = pi.UserData.FreeData; if (pi.CustomColumnNumber>0) { - fi.CustomColumnData=new wchar_t*[pi.CustomColumnNumber]; + CustomColumnData = new wchar_t*[pi.CustomColumnNumber]; for (size_t I=0; IIsEnabledOnPanel(); - std::vector ContentNames, ContentValues; - std::vector ContentPlugins; { + m_ContentPlugins.clear(); + m_ContentNames.clear(); + m_ContentNamesPtrs.clear(); + m_ContentValues.clear(); + std::unordered_set ColumnsSet; const std::vector* ColumnsContainers[] = { &m_ViewSettings.PanelColumns, &m_ViewSettings.StatusColumns }; @@ -6672,15 +6776,19 @@ void FileList::ReadFileNames(int KeepSelection, int UpdateEvenIfPanelInvisible, if ((Column.type & 0xff) == CUSTOM_COLUMN0) { if (ColumnsSet.emplace(Column.title).second) - ContentNames.emplace_back(Column.title.data()); + { + m_ContentNames.emplace_back(Column.title); + } } } } - if (!ContentNames.empty()) + if (!m_ContentNames.empty()) { - ContentPlugins = Global->CtrlObject->Plugins->GetContentPlugins(ContentNames); - ContentValues.resize(ContentNames.size()); + m_ContentNamesPtrs.reserve(m_ContentNames.size()); + std::transform(ALL_CONST_RANGE(m_ContentNames), std::back_inserter(m_ContentNamesPtrs), [](const auto& i) { return i.data(); }); + m_ContentPlugins = Global->CtrlObject->Plugins->GetContentPlugins(m_ContentNamesPtrs); + m_ContentValues.resize(m_ContentNames.size()); } } @@ -6706,7 +6814,6 @@ void FileList::ReadFileNames(int KeepSelection, int UpdateEvenIfPanelInvisible, NewItem.strName = fdata.strFileName; NewItem.strShortName = fdata.strAlternateFileName; NewItem.Position = m_ListData.size(); - NewItem.NumberOfLinks = 1; if (fdata.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) { @@ -6715,38 +6822,10 @@ void FileList::ReadFileNames(int KeepSelection, int UpdateEvenIfPanelInvisible, if (!(fdata.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) { TotalFileSize += NewItem.FileSize; - - if (ReadNumLinks) - NewItem.NumberOfLinks = GetNumberOfLinks(fdata.strFileName, true); - } - else - { - NewItem.AllocationSize = 0; } NewItem.SortGroup = DEFAULT_SORT_GROUP; - if (ReadOwners) - { - string strOwner; - GetFileOwner(strComputerName, NewItem.strName, strOwner); - NewItem.strOwner = strOwner; - } - - NewItem.NumberOfStreams = NewItem.FileAttr&FILE_ATTRIBUTE_DIRECTORY ? 0 : 1; - NewItem.StreamsSize = NewItem.FileSize; - - if (ReadNumStreams || ReadStreamsSize) - { - EnumStreams(TestParentFolderName(fdata.strFileName) ? m_CurDir : fdata.strFileName, NewItem.StreamsSize, NewItem.NumberOfStreams); - } - - if (!ContentPlugins.empty()) - { - NewItem.ContentData = std::make_unique(); - Global->CtrlObject->Plugins->GetContentData(ContentPlugins, NewItem.strName, ContentNames, ContentValues, *NewItem.ContentData.get()); - } - m_ListData.emplace_back(std::move(NewItem)); } @@ -6806,17 +6885,11 @@ void FileList::ReadFileNames(int KeepSelection, int UpdateEvenIfPanelInvisible, if ((Global->Opt->ShowDotsInRoot || !bCurDirRoot) || (NetRoot && Global->CtrlObject->Plugins->FindPlugin(Global->Opt->KnownIDs.Network.Id))) // NetWork Plugin { - string TwoDotsOwner; - if (ReadOwners) - { - GetFileOwner(strComputerName,m_CurDir,TwoDotsOwner); - } - FILETIME TwoDotsTimes[4]={}; os::GetFileTimeSimple(m_CurDir,&TwoDotsTimes[0],&TwoDotsTimes[1],&TwoDotsTimes[2],&TwoDotsTimes[3]); FileListItem NewItem; - FillParentPoint(NewItem, m_ListData.size() + 1, TwoDotsTimes, TwoDotsOwner); + FillParentPoint(NewItem, m_ListData.size() + 1, TwoDotsTimes); m_ListData.emplace_back(std::move(NewItem)); } @@ -6840,7 +6913,7 @@ void FileList::ReadFileNames(int KeepSelection, int UpdateEvenIfPanelInvisible, auto PluginPtr = PanelData; for (auto& i: make_range(m_ListData.begin() + OldSize, m_ListData.end())) { - PluginToFileListItem(*PluginPtr, i); + i = *PluginPtr; i.Position = Position; TotalFileSize += PluginPtr->FileSize; i.PrevSelected = i.Selected=0; @@ -7124,8 +7197,7 @@ void FileList::UpdatePlugin(int KeepSelection, int UpdateEvenIfPanelInvisible) if (!Global->Opt->ShowHidden && (PanelData[i].FileAttributes & (FILE_ATTRIBUTE_HIDDEN|FILE_ATTRIBUTE_SYSTEM))) continue; - FileListItem NewItem; - PluginToFileListItem(PanelData[i], NewItem); + FileListItem NewItem = PanelData[i]; NewItem.Position = i; NewItem.SortGroup = (m_CachedOpenPanelInfo.Flags & OPIF_DISABLESORTGROUPS)? DEFAULT_SORT_GROUP : Global->CtrlObject->HiFiles->GetGroup(&NewItem); @@ -7325,7 +7397,7 @@ void FileList::ReadSortGroups(bool UpdateFilterCurrentTime) } // занести предопределенные данные для каталога ".." -void FileList::FillParentPoint(FileListItem& Item, size_t CurFilePos, const FILETIME* Times, const string& Owner) +void FileList::FillParentPoint(FileListItem& Item, size_t CurFilePos, const FILETIME* Times) { Item.FileAttr = FILE_ATTRIBUTE_DIRECTORY; Item.strName = L".."; @@ -7339,7 +7411,6 @@ void FileList::FillParentPoint(FileListItem& Item, size_t CurFilePos, const FILE Item.ChangeTime = Times[3]; } - Item.strOwner = Owner; Item.Position = CurFilePos; } @@ -8259,7 +8330,7 @@ void FileList::ShowList(int ShowStatus,int StartColumn) if (!ColumnData) { - const auto& ContentMapPtr = m_ListData[ListPos].ContentData; + const auto& ContentMapPtr = m_ListData[ListPos].ContentData(this); if (ContentMapPtr) { const auto Iterator = ContentMapPtr->find(Columns[K].title); @@ -8477,10 +8548,14 @@ void FileList::ShowList(int ShowStatus,int StartColumn) case PACKED_COLUMN: case STREAMSSIZE_COLUMN: { + const auto SizeToDisplay = (ColumnType == PACKED_COLUMN) + ? m_ListData[ListPos].AllocationSize + : (ColumnType == STREAMSSIZE_COLUMN) + ? m_ListData[ListPos].StreamsSize(this) + : m_ListData[ListPos].FileSize; + Text(FormatStr_Size( - m_ListData[ListPos].FileSize, - m_ListData[ListPos].AllocationSize, - m_ListData[ListPos].StreamsSize, + SizeToDisplay, m_ListData[ListPos].strName, m_ListData[ListPos].FileAttr, m_ListData[ListPos].ShowFolderSize, @@ -8555,11 +8630,15 @@ void FileList::ShowList(int ShowStatus,int StartColumn) case OWNER_COLUMN: { - const wchar_t* Owner=m_ListData[ListPos].strOwner.data(); + auto Owner = m_ListData[ListPos].Owner(this).data(); - if (!(Columns[K].type & COLUMN_FULLOWNER) && m_PanelMode != panel_mode::PLUGIN_PANEL) + if (!*Owner) { - const auto SlashPos = FindSlash(m_ListData[ListPos].strOwner); + Owner = L"?"; + } + else if (!(Columns[K].type & COLUMN_FULLOWNER) && m_PanelMode != panel_mode::PLUGIN_PANEL) + { + const auto SlashPos = FindSlash(m_ListData[ListPos].Owner(this)); if (SlashPos != string::npos) { Owner += SlashPos + 1; @@ -8588,17 +8667,21 @@ void FileList::ShowList(int ShowStatus,int StartColumn) case NUMLINK_COLUMN: { - int nlink = m_ListData[ListPos].NumberOfLinks; - if (nlink >= 0) - Global->FS << fmt::ExactWidth(ColumnWidth) << nlink; - else + const auto Value = m_ListData[ListPos].NumberOfLinks(this); + if (Value == FileListItem::values::unknown(Value)) Global->FS << fmt::ExactWidth(ColumnWidth) << L"?"; + else + Global->FS << fmt::ExactWidth(ColumnWidth) << Value; break; } case NUMSTREAMS_COLUMN: { - Global->FS << fmt::ExactWidth(ColumnWidth)<FS << fmt::ExactWidth(ColumnWidth) << L"?"; + else + Global->FS << fmt::ExactWidth(ColumnWidth) << Value; break; } @@ -8691,3 +8774,14 @@ bool FileList::IsColumnDisplayed(int Type) { return IsColumnDisplayed([&Type](const column& i) {return static_cast(i.type & 0xff) == Type;}); } + +content_data_ptr FileList::GetContentData(const string& Item) const +{ + content_data_ptr Result; + if (!m_ContentPlugins.empty()) + { + Result = std::make_unique(); + Global->CtrlObject->Plugins->GetContentData(m_ContentPlugins, Item, m_ContentNamesPtrs, m_ContentValues, *Result.get()); + } + return Result; +} diff --git a/far/filelist.hpp b/far/filelist.hpp index 451f16dd82..c51cbab4dc 100644 --- a/far/filelist.hpp +++ b/far/filelist.hpp @@ -54,15 +54,12 @@ namespace detail unsigned long long FileSize; unsigned long long AllocationSize; - unsigned long long StreamsSize; UINT64 UserFlags; void* UserData; DWORD FileAttr; DWORD ReparseTag; - DWORD NumberOfLinks; - DWORD NumberOfStreams; mutable const HighlightFiles::highlight_item* Colors; FARPANELITEMFREECALLBACK Callback; @@ -82,20 +79,40 @@ namespace detail }; } -struct FileListItem: public detail::FileListItemPod +typedef std::unique_ptr> content_data_ptr; + +class FileListItem: public detail::FileListItemPod { +public: NONCOPYABLE(FileListItem); TRIVIALLY_MOVABLE(FileListItem); + FileListItem(); + FileListItem(const PluginPanelItem& pi); + + DWORD NumberOfLinks(const FileList* Owner) const; + DWORD NumberOfStreams(const FileList* Owner) const; + unsigned long long StreamsSize(const FileList* Owner) const; + const string& Owner(const FileList* Owner) const; + const content_data_ptr& ContentData(const FileList* Owner) const; + string strName; string strShortName; - string strOwner; - std::unique_ptr> ContentData; - FileListItem() + struct values { - ClearStruct(static_cast(*this)); - } + template + static constexpr T uninitialised(T) { return -2; } + template + static constexpr T unknown(T) { return -1; } + }; + +private: + mutable string m_Owner; + mutable DWORD m_NumberOfLinks = values::uninitialised(m_NumberOfLinks); + mutable DWORD m_NumberOfStreams = values::uninitialised(m_NumberOfStreams); + mutable uint64_t m_StreamsSize = values::uninitialised(m_StreamsSize); + mutable content_data_ptr m_ContentData; }; struct PluginsListItem @@ -229,10 +246,9 @@ class FileList:public Panel void ResetLastUpdateTime() {LastUpdateTime = 0;} string GetPluginPrefix() const; - static size_t FileListToPluginItem2(const FileListItem& fi,FarGetPluginPanelItem* pi); + size_t FileListToPluginItem2(const FileListItem& fi,FarGetPluginPanelItem* pi) const; static int FileNameToPluginItem(const string& Name,PluginPanelItem& pi); - static void FileListToPluginItem(const FileListItem& fi,PluginPanelItem& pi); - static void PluginToFileListItem(const PluginPanelItem& pi,FileListItem& fi); + void FileListToPluginItem(const FileListItem& fi,PluginPanelItem& pi) const; static bool IsModeFullScreen(int Mode); struct PrevDataItem; @@ -241,6 +257,12 @@ class FileList:public Panel virtual void ClearAllItem() override; private: + friend class FileListItem; + bool HardlinksSupported() const { return m_HardlinksSupported; } + bool StreamsSupported() const { return m_StreamsSupported; } + const string& GetComputerName() const { return m_ComputerName; } + content_data_ptr GetContentData(const string& Item) const; + virtual void SetSelectedFirstMode(bool Mode) override; virtual void DisplayObject() override; virtual int GetCurName(string &strName, string &strShortName) const override; @@ -299,7 +321,7 @@ class FileList:public Panel bool IsColumnDisplayed(std::function Compare); static void DeletePluginItemList(std::vector &ItemList); - static void FillParentPoint(FileListItem& Item, size_t CurFilePos, const FILETIME* Times = nullptr, const string& Owner = string()); + static void FillParentPoint(FileListItem& Item, size_t CurFilePos, const FILETIME* Times = nullptr); std::unique_ptr m_Filter; DizList Diz; @@ -350,6 +372,14 @@ class FileList:public Panel wchar_t CustomSortIndicator[2]; mutable OpenPanelInfo m_CachedOpenPanelInfo; + + bool m_HardlinksSupported; + bool m_StreamsSupported; + string m_ComputerName; + std::vector m_ContentNames; + std::vector m_ContentNamesPtrs; + mutable std::vectorm_ContentValues; + std::vector m_ContentPlugins; }; #endif // FILELIST_HPP_825FE8AE_1E34_4DFD_B167_2D6A121B1777 diff --git a/far/findfile.cpp b/far/findfile.cpp index 75c4869e5d..397e8884ca 100644 --- a/far/findfile.cpp +++ b/far/findfile.cpp @@ -2022,10 +2022,16 @@ void FindFiles::AddMenuRecord(Dialog* Dlg,const string& FullName, string& strLas StreamsCount=GetNumberOfLinks(FindData.strFileName); } + const auto SizeToDisplay = (CurColumnType == SIZE_COLUMN) + ? FindData.nFileSize + : (CurColumnType == PACKED_COLUMN) + ? FindData.nAllocationSize + : (CurColumnType == STREAMSSIZE_COLUMN) + ? StreamsSize + : StreamsCount; // ??? + MenuText << FormatStr_Size( - FindData.nFileSize, - FindData.nAllocationSize, - (CurColumnType == NUMSTREAMS_COLUMN || CurColumnType == NUMLINK_COLUMN)?StreamsCount:StreamsSize, + SizeToDisplay, DisplayName, FindData.dwFileAttributes, 0, diff --git a/far/headers.hpp b/far/headers.hpp index a79e17c805..8d050926d3 100644 --- a/far/headers.hpp +++ b/far/headers.hpp @@ -163,6 +163,10 @@ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #endif // __GNUC__ //---------------------------------------------------------------------------- + +using string = std::wstring; +using namespace std::string_literals; + #include "disable_warnings_in_std_end.hpp" #include "sdk.hpp" diff --git a/far/hilight.hpp b/far/hilight.hpp index db134c3ff1..33486eb089 100644 --- a/far/hilight.hpp +++ b/far/hilight.hpp @@ -38,7 +38,7 @@ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. class VMenu2; class FileFilterParams; class FileList; -struct FileListItem; +class FileListItem; class HighlightFiles: noncopyable { diff --git a/far/macro.cpp b/far/macro.cpp index 2ac1c75131..2ff766eff6 100644 --- a/far/macro.cpp +++ b/far/macro.cpp @@ -1477,14 +1477,14 @@ static std::vector parseParams(size_t Count, FarMacroCall* Data) const auto argNum = std::min(Data->Count, Count); std::vector Params; Params.reserve(Count); - std::transform(Data->Values, Data->Values + argNum, std::back_inserter(Params), [](const auto& i) -> TVar + std::transform(Data->Values, Data->Values + argNum, std::back_inserter(Params), [](const auto& i) { switch (i.Type) { - case FMVT_INTEGER: return i.Integer; - case FMVT_BOOLEAN: return i.Boolean; - case FMVT_DOUBLE: return i.Double; - case FMVT_STRING: return i.String; + case FMVT_INTEGER: return TVar(i.Integer); + case FMVT_BOOLEAN: return TVar(i.Boolean); + case FMVT_DOUBLE: return TVar(i.Double); + case FMVT_STRING: return TVar(i.String); default: return TVar(); } }); @@ -3157,7 +3157,7 @@ static bool menushowFunc(FarMacroCall* Data) if (strItems.back() != L'\n') strItems.append(L"\n"); - TVar Result = -1; + TVar Result(-1); int BoxType = (Flags & 0x7)?(Flags & 0x7)-1:3; bool bResultAsIndex = (Flags & 0x08) != 0; bool bMultiSelect = (Flags & 0x010) != 0; @@ -3408,14 +3408,14 @@ static bool menushowFunc(FarMacroCall* Data) if (bResultAsIndex) { _i64tow(i+1,temp,10); - Result+=temp; + Result += TVar(temp); } else - Result += Menu->at(i).strName.data() + nLeftShift; - Result+=L"\n"; + Result += TVar(Menu->at(i).strName.data() + nLeftShift); + Result += TVar(L"\n"); } } - if(Result==L"") + if(Result == TVar(L"")) { if (bResultAsIndex) { @@ -4574,7 +4574,7 @@ static bool panelitemFunc(FarMacroCall* Data) PassBoolean(filelistItem->Selected, Data); return false; case 9: // NumberOfLinks - PassNumber(filelistItem->NumberOfLinks, Data); + PassNumber(filelistItem->NumberOfLinks(fileList.get()), Data); return false; case 10: // SortGroup PassBoolean(filelistItem->SortGroup, Data); @@ -4583,7 +4583,7 @@ static bool panelitemFunc(FarMacroCall* Data) Ret=TVar((const wchar_t *)filelistItem->DizText); break; case 12: // Owner - Ret=TVar(filelistItem->strOwner); + Ret = TVar(filelistItem->Owner(fileList.get())); break; case 13: // CRC32 PassNumber(filelistItem->CRC32, Data); @@ -4601,10 +4601,10 @@ static bool panelitemFunc(FarMacroCall* Data) PassInteger(FileTimeToUI64(filelistItem->WriteTime), Data); return false; case 18: // NumberOfStreams - PassNumber(filelistItem->NumberOfStreams, Data); + PassNumber(filelistItem->NumberOfStreams(fileList.get()), Data); return false; case 19: // StreamsSize - PassInteger(filelistItem->StreamsSize, Data); + PassInteger(filelistItem->StreamsSize(fileList.get()), Data); return false; case 20: // ChangeTime ConvertDate(filelistItem->ChangeTime,strDate,strTime,8,FALSE,FALSE,TRUE); @@ -4776,7 +4776,7 @@ static bool absFunc(FarMacroCall* Data) auto Params = parseParams(1, Data); TVar& tmpVar(Params[0]); - if (tmpVar < 0ll) + if (tmpVar < TVar(0)) tmpVar=-tmpVar; PassValue(tmpVar, Data); diff --git a/far/panelmix.cpp b/far/panelmix.cpp index 621dc58acc..1689aa1257 100644 --- a/far/panelmix.cpp +++ b/far/panelmix.cpp @@ -661,7 +661,7 @@ const string FormatStr_DateTime(const FILETIME *FileTime,int ColumnType,unsigned return strResult; } -const string FormatStr_Size(__int64 FileSize, __int64 AllocationSize, __int64 StreamsSize, const string& strName, +const string FormatStr_Size(__int64 Size, const string& strName, DWORD FileAttributes,DWORD ShowFolderSize,DWORD ReparseTag,int ColumnType, unsigned __int64 Flags,int Width,const wchar_t *CurDir) { @@ -678,7 +678,7 @@ const string FormatStr_Size(__int64 FileSize, __int64 AllocationSize, __int64 St bool dir = (0 != (FileAttributes & FILE_ATTRIBUTE_DIRECTORY)); bool rpt = (0 != (FileAttributes & FILE_ATTRIBUTE_REPARSE_POINT)); - bool have_size = !dir && (!rpt || ReparseTag==IO_REPARSE_TAG_DEDUP || FileSize > 0); + bool have_size = !dir && (!rpt || ReparseTag==IO_REPARSE_TAG_DEDUP || Size > 0); if (!Streams && !Packed && !have_size && !ShowFolderSize) { @@ -791,7 +791,7 @@ const string FormatStr_Size(__int64 FileSize, __int64 AllocationSize, __int64 St else { string strOutStr; - strResult<& Destination); diff --git a/far/print.cpp b/far/print.cpp index f9a66d47df..f397e496f6 100644 --- a/far/print.cpp +++ b/far/print.cpp @@ -212,7 +212,7 @@ void PrintFiles(FileList* SrcPanel) if (const auto ListItem = SrcPanel->GetLastSelectedItem()) { PluginPanelItem PanelItem; - FileList::FileListToPluginItem(*ListItem, PanelItem); + SrcPanel->FileListToPluginItem(*ListItem, PanelItem); if (Global->CtrlObject->Plugins->GetFile(hPlugin,&PanelItem,strTempDir,strTempName,OPM_SILENT)) FileName = strTempName; diff --git a/far/tvar.hpp b/far/tvar.hpp index 3d6662535a..0112a91aed 100644 --- a/far/tvar.hpp +++ b/far/tvar.hpp @@ -59,12 +59,19 @@ class TVar TRIVIALLY_COPYABLE(TVar); TRIVIALLY_MOVABLE(TVar); - TVar(); - TVar(long long); - TVar(const string&); - TVar(const wchar_t*); - TVar(int); - TVar(double); + explicit TVar(); + explicit TVar(int); + explicit TVar(long long); + explicit TVar(const string&); + explicit TVar(const wchar_t*); + explicit TVar(double); + + COPY_AND_SWAP(TVar, long long); + COPY_AND_SWAP(TVar, const string&); + COPY_AND_SWAP(TVar, const wchar_t*); + COPY_AND_SWAP(TVar, int); + COPY_AND_SWAP(TVar, double); + TVar& operator+=(const TVar& b) { return *this = *this + b; } TVar operator-() const; diff --git a/far/vbuild.m4 b/far/vbuild.m4 index d233faeef7..555dbd4eaf 100644 --- a/far/vbuild.m4 +++ b/far/vbuild.m4 @@ -1 +1 @@ -m4_define(BUILD,4602)m4_dnl +m4_define(BUILD,4603)m4_dnl