/* Закрасить прямоугольник символом Ch и цветом Color */ void ScreenBuf::FillRect(int X1,int Y1,int X2,int Y2,WCHAR Ch,const FarColor& Color) { SCOPED_ACTION(CriticalSectionLock)(CS); int Width=X2-X1+1; int Height=Y2-Y1+1; int I, J; FAR_CHAR_INFO CI,*PtrBuf; CI.Attributes=Color; SetVidChar(CI,Ch); for (I=0; I < Height; I++) { for (PtrBuf = Buf.data() + (Y1 + I)*BufX + X1, J = 0; J < Width; J++, ++PtrBuf) *PtrBuf=CI; } SBFlags.Clear(SBFLAGS_FLUSHED); #ifdef DIRECT_SCREEN_OUT Flush(); #elif defined(DIRECT_RT) if (Global->DirectRT) Flush(); #endif }
/* Записать Text в виртуальный буфер */ void ScreenBuf::Write(int X,int Y,const FAR_CHAR_INFO *Text, size_t Size) { SCOPED_ACTION(CriticalSectionLock)(CS); if (X<0) { Text-=X; Size = std::max(0, static_cast<int>(Size) + X); X=0; } if (X>=BufX || Y>=BufY || !Size || Y<0) return; if (X+Size >= static_cast<size_t>(BufX)) Size=BufX-X; //?? FAR_CHAR_INFO *PtrBuf=Buf.data()+Y*BufX+X; for (size_t i=0; i < Size; i++) { SetVidChar(PtrBuf[i],Text[i].Char); PtrBuf[i].Attributes=Text[i].Attributes; } SBFlags.Clear(SBFLAGS_FLUSHED); #ifdef DIRECT_SCREEN_OUT Flush(); #elif defined(DIRECT_RT) if (Global->DirectRT) Flush(); #endif }
void ConsoleTitle::SetFarTitle(const string& Title) { SCOPED_ACTION(CriticalSectionLock)(TitleCS); string strOldFarTitle; Global->Console->GetTitle(strOldFarTitle); if (!GetUserTitle().empty()) { FarTitle() = GetUserTitle(); } else { FarTitle() = Title; FarTitle() += GetFarTitleAddons(); } TitleModified=true; if (strOldFarTitle != FarTitle() && !Global->ScrBuf->GetLockCount()) { Global->Console->SetTitle(FarTitle()); TitleModified=true; } }
void SQLiteDb::Initialize(initialiser Initialiser, string_view const DbName, bool Local, bool WAL) { assign(m_Name, DbName); os::mutex m(os::make_name<os::mutex>(Local? Global->Opt->LocalProfilePath : Global->Opt->ProfilePath, m_Name)); SCOPED_ACTION(std::lock_guard<os::mutex>)(m); const auto& OpenAndInitialise = [&](string_view const Name) { return Open(Name, Local, WAL) && Initialiser(db_initialiser(this)); }; if (!OpenAndInitialise(m_Name)) { Close(); ++init_status; const auto in_memory = Global->Opt->ReadOnlyConfig || !(os::fs::move_file(m_Path, m_Path + L".bad"sv, MOVEFILE_REPLACE_EXISTING) && OpenAndInitialise(m_Name)); if (in_memory) { Close(); ++init_status; OpenAndInitialise(MemoryDbName); } } }
int SimpleModal::ReadInput(INPUT_RECORD *GetReadRec) { if (GetReadRec) ClearStruct(*GetReadRec); if (m_WriteKey>=0) { m_ReadKey=m_WriteKey; m_WriteKey=-1; } else { m_ReadKey=GetInputRecord(&m_ReadRec); if (GetReadRec) { *GetReadRec=m_ReadRec; } } if (m_ReadKey == KEY_CONSOLE_BUFFER_RESIZE) { SCOPED_ACTION(LockScreen); Hide(); Show(); } if (Global->CloseFARMenu) { SetExitCode(-1); } return m_ReadKey; }
/* Читать блок из виртуального буфера. */ void ScreenBuf::Read(int X1,int Y1,int X2,int Y2,FAR_CHAR_INFO *Text, size_t Size) { SCOPED_ACTION(CriticalSectionLock)(CS); size_t Width=X2-X1+1; size_t Height=Y2-Y1+1; for (size_t Idx = 0, I = 0; I < Height; I++, Idx+=Width) std::copy(Buf.data() + (Y1 + I)*BufX + X1, Buf.data() + (Y1 + I)*BufX + X1 + std::min(Width, Size), Text + Idx); }
/* Функция TestFolder возвращает одно состояний тестируемого каталога: TSTFLD_NOTEMPTY (2) - не пусто TSTFLD_EMPTY (1) - пусто TSTFLD_NOTFOUND (0) - нет такого TSTFLD_NOTACCESS (-1) - нет доступа TSTFLD_ERROR (-2) - ошибка (кривые параметры или не хватило памяти для выделения промежуточных буферов) */ int TestFolder(const string& Path) { if (Path.empty()) return TSTFLD_ERROR; string strFindPath = Path; // сообразим маску для поиска. AddEndSlash(strFindPath); strFindPath += L"*"; // первая проверка - че-нить считать можем? api::fs::enum_file Find(strFindPath); if (Find.begin() != Find.end()) { return TSTFLD_NOTEMPTY; } Global->CatchError(); DWORD LastError = Global->CaughtError(); if (LastError == ERROR_FILE_NOT_FOUND || LastError == ERROR_NO_MORE_FILES) return TSTFLD_EMPTY; if (LastError == ERROR_PATH_NOT_FOUND) return TSTFLD_NOTFOUND; // собственно... не факт, что диск не читаем, т.к. на чистом диске в корне нету даже "." // поэтому посмотрим на Root GetPathRoot(Path,strFindPath); if (strFindPath == Path) { // проверка атрибутов гарантировано скажет - это бага BugZ#743 или пустой корень диска. if (api::fs::exists(strFindPath)) { if (LastError == ERROR_ACCESS_DENIED) return TSTFLD_NOTACCESS; return TSTFLD_EMPTY; } } strFindPath = Path; if (CheckShortcutFolder(strFindPath,FALSE,TRUE)) { if (strFindPath != Path) return TSTFLD_NOTFOUND; } { SCOPED_ACTION(elevation::suppress); if (api::fs::is_file(strFindPath)) return TSTFLD_ERROR; } return TSTFLD_NOTACCESS; }
bool SetOwnerInternal(const string& Object, const string& Owner) { bool Result = false; PSID Sid = nullptr; SCOPE_EXIT { LocalFree(Sid); }; if(!ConvertStringSidToSid(Owner.data(), &Sid)) { SID_NAME_USE Use; DWORD cSid=0, ReferencedDomain=0; LookupAccountName(nullptr, Owner.data(), nullptr, &cSid, nullptr, &ReferencedDomain, &Use); if(cSid) { Sid = LocalAlloc(LMEM_FIXED, cSid); if(Sid) { std::vector<wchar_t> ReferencedDomainName(ReferencedDomain); if(LookupAccountName(nullptr, Owner.data(), Sid, &cSid, ReferencedDomainName.data(), &ReferencedDomain, &Use)) { ; } } } } if(Sid) { SCOPED_ACTION(Privilege)(SE_TAKE_OWNERSHIP_NAME); SCOPED_ACTION(Privilege)(SE_RESTORE_NAME); DWORD dwResult = SetNamedSecurityInfo(const_cast<LPWSTR>(Object.data()), SE_FILE_OBJECT, OWNER_SECURITY_INFORMATION, Sid, nullptr, nullptr, nullptr); if(dwResult == ERROR_SUCCESS) { Result = true; } else { SetLastError(dwResult); } } return Result; }
/* Заполнение виртуального буфера значением из консоли. */ void ScreenBuf::FillBuf() { SCOPED_ACTION(CriticalSectionLock)(CS); COORD BufferSize={BufX, BufY}, BufferCoord={}; SMALL_RECT ReadRegion={0, 0, static_cast<SHORT>(BufX-1), static_cast<SHORT>(BufY-1)}; Global->Console->ReadOutput(Buf.data(), BufferSize, BufferCoord, ReadRegion); std::copy(ALL_CONST_RANGE(Buf), Shadow.begin()); SBFlags.Set(SBFLAGS_USESHADOW); COORD CursorPosition; Global->Console->GetCursorPosition(CursorPosition); CurX=CursorPosition.X; CurY=CursorPosition.Y; }
// used in block selection void ScreenBuf::ApplyColor(int X1,int Y1,int X2,int Y2,const FarColor& Color, bool PreserveExFlags) { SCOPED_ACTION(CriticalSectionLock)(CS); if(X1<=ScrX && Y1<=ScrY && X2>=0 && Y2>=0) { X1=std::max(0,X1); X2=std::min(static_cast<int>(ScrX),X2); Y1=std::max(0,Y1); Y2=std::min(static_cast<int>(ScrY),Y2); int Width=X2-X1+1; int Height=Y2-Y1+1; int I, J; FAR_CHAR_INFO *PtrBuf; if(PreserveExFlags) { for (I=0; I < Height; I++) { PtrBuf = Buf.data() + (Y1 + I)*BufX + X1; for (J=0; J < Width; J++, ++PtrBuf) { FARCOLORFLAGS ExFlags = PtrBuf->Attributes.Flags&FCF_EXTENDEDFLAGS; PtrBuf->Attributes=Color; PtrBuf->Attributes.Flags = (PtrBuf->Attributes.Flags&~FCF_EXTENDEDFLAGS)|ExFlags; } } } else { for (I=0; I < Height; I++) { PtrBuf = Buf.data() + (Y1 + I)*BufX + X1; for (J=0; J < Width; J++, ++PtrBuf) { PtrBuf->Attributes=Color; } } } #ifdef DIRECT_SCREEN_OUT Flush(); #elif defined(DIRECT_RT) if (Global->DirectRT) Flush(); #endif } }
ConsoleTitle::~ConsoleTitle() { SCOPED_ACTION(CriticalSectionLock)(TitleCS); const string &strTitleAddons = GetFarTitleAddons(); size_t OldLen = strOldTitle.size(); size_t AddonsLen = strTitleAddons.size(); if (AddonsLen <= OldLen) { if (!StrCmpI(strOldTitle.data()+OldLen-AddonsLen, strTitleAddons.data())) strOldTitle.resize(OldLen-AddonsLen); } SetFarTitle(strOldTitle); }
void Panel::DragMessage(int X,int Y,int Move) { const auto SelCount = SrcDragPanel->GetSelCount(); if (!SelCount) return; string strSelName; if (SelCount == 1) { os::fs::find_data Data; if (!SrcDragPanel->get_first_selected(Data)) return; assign(strSelName, PointToName(Data.FileName)); QuoteSpace(strSelName); } else { strSelName = format(msg(lng::MDragFiles), SelCount); } auto strDragMsg = format(msg(Move? lng::MDragMove : lng::MDragCopy), strSelName); auto Length = static_cast<int>(strDragMsg.size()); int MsgX = X; if (Length + X > ScrX) { MsgX=ScrX-Length; if (MsgX<0) { MsgX=0; TruncStrFromEnd(strDragMsg,ScrX); Length=(int)strDragMsg.size(); } } SCOPED_ACTION(ChangePriority)(THREAD_PRIORITY_NORMAL); // Important - the old one must be deleted before creating a new one, not after DragSaveScr.reset(); DragSaveScr = std::make_unique<SaveScreen>(MsgX, Y, MsgX + Length - 1, Y); GotoXY(MsgX,Y); SetColor(COL_PANELDRAGTEXT); Text(strDragMsg); }
bool message_manager::dispatch() { bool Result = false; message_queue::value_type EventData; while (m_Messages.try_pop(EventData)) { SCOPED_ACTION(std::shared_lock<mutex_type>)(m_RWLock); const auto RelevantListeners = m_Handlers.equal_range(EventData.first); std::for_each(RelevantListeners.first, RelevantListeners.second, [&](const handlers_map::value_type& i) { std::invoke(*i.second, EventData.second); }); Result = Result || RelevantListeners.first != RelevantListeners.second; } m_Window->Check(); return Result; }
void ScreenBuf::AllocBuf(int X,int Y) { SCOPED_ACTION(CriticalSectionLock)(CS); if (X==BufX && Y==BufY) return; size_t Cnt=X*Y; // don't call vector.resize() here: // - it's never shrink // - we don't care about old content resize_nomove(Buf, Cnt); resize_nomove(Shadow, Cnt); BufX=X; BufY=Y; }
/* Преобразует Src в полный РЕАЛЬНЫЙ путь с учетом reparse point. Note that Src can be partially non-existent. */ string ConvertNameToReal(string_view const Object) { SCOPED_ACTION(elevation::suppress); // Получим сначала полный путь до объекта обычным способом const auto FullPath = ConvertNameToFull(Object); auto strDest = FullPath; string Path = FullPath; os::fs::file File; for (;;) { if (File.Open(Path, 0, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, nullptr, OPEN_EXISTING)) break; if (IsRootPath(Path)) break; Path = ExtractFilePath(Path); } if (File) { string FinalFilePath; File.GetFinalPathName(FinalFilePath); File.Close(); //assert(!FinalFilePath.empty()); if (!FinalFilePath.empty()) { // append non-existent path part (if present) DeleteEndSlash(Path); if (FullPath.size() > Path.size() + 1) path::append(FinalFilePath, string_view(FullPath).substr(Path.size() + 1)); FinalFilePath = TryConvertVolumeGuidToDrivePath(FinalFilePath); strDest = FinalFilePath; } } return strDest; }
void FileSystemWatcher::Watch(bool got_focus, bool check_time) { PropagateException(); SCOPED_ACTION(elevation::suppress); if(!m_RegistrationThread) m_RegistrationThread = os::thread(&os::thread::join, &FileSystemWatcher::Register, this); if (got_focus) { if (!m_IsFatFilesystem.second) { const auto strRoot = GetPathRoot(m_Directory); if (!strRoot.empty()) { string strFileSystem; if (os::fs::GetVolumeInformation(strRoot, nullptr, nullptr, nullptr, nullptr, &strFileSystem)) m_IsFatFilesystem.first = starts_with(strFileSystem, L"FAT"sv); } m_IsFatFilesystem.second = true; } if (m_IsFatFilesystem.first) { // emulate FAT folder time change // otherwise changes missed (FAT folder time is NOT modified) // the price is directory reload on each GOT_FOCUS event check_time = false; m_PreviousLastWriteTime = m_CurrentLastWriteTime - 1s; } } if (check_time) { if (!os::fs::GetFileTimeSimple(m_Directory, nullptr, nullptr, &m_CurrentLastWriteTime, nullptr)) { m_PreviousLastWriteTime = {}; m_CurrentLastWriteTime = {}; } } }
void Language::init(const string& Path, int CountNeed) { SCOPED_ACTION(GuardLastError); uintptr_t nCodePage = CP_OEMCP; string strLangName = Global->Opt->strLanguage.Get(); api::File LangFile; if (!OpenLangFile(LangFile, Path, LangFileMask, Global->Opt->strLanguage, m_FileName, nCodePage, false, &strLangName)) { throw std::runtime_error("Cannot find language data"); } GetFileString GetStr(LangFile, nCodePage); if (CountNeed != -1) { reserve(CountNeed); } string Buffer; while (GetStr.GetString(Buffer)) { RemoveExternalSpaces(Buffer); if (Buffer.empty() || Buffer.front() != L'\"') continue; if (Buffer.size() > 1 && Buffer.back() == L'\"') { Buffer.pop_back(); } add(ConvertString(Buffer.data() + 1, Buffer.size() - 1)); } // Проведем проверку на количество строк в LNG-файлах if (CountNeed != -1 && CountNeed != static_cast<int>(size())) { throw std::runtime_error("Language data is incorrect or damaged"); } }
void FileSystemWatcher::Watch(bool got_focus, bool check_time) { SCOPED_ACTION(elevation::suppress); if(!bOpen) { bOpen = true; Done.Reset(); DoneDone.Reset(); WatchRegistered.Reset(); Thread WatchThread; WatchThread.Start(&FileSystemWatcher::WatchRegister, this); } if (got_focus) { bool isFAT = false; string strRoot, strFileSystem; GetPathRoot(Directory, strRoot); if (!strRoot.empty()) { if (api::GetVolumeInformation(strRoot, nullptr, nullptr, nullptr, nullptr, &strFileSystem)) isFAT = (strFileSystem.substr(0,3) == L"FAT"); } if (isFAT) // emulate FAT folder time change { // otherwise changes missed (FAT folder time is NOT modified) check_time = false; // the price is directory reload on each GOT_FOCUS event PreviousLastWriteTime.dwLowDateTime = CurrentLastWriteTime.dwLowDateTime - 1; } } if (check_time) { if (!api::GetFileTimeSimple(Directory,nullptr,nullptr,&CurrentLastWriteTime,nullptr)) { PreviousLastWriteTime.dwLowDateTime = 0; PreviousLastWriteTime.dwHighDateTime = 0; CurrentLastWriteTime.dwLowDateTime = 0; CurrentLastWriteTime.dwHighDateTime = 0; } } }
/* Изменить значение цветовых атрибутов в соответствии с маской (применяется для "создания" тени) */ void ScreenBuf::ApplyShadow(int X1,int Y1,int X2,int Y2) { SCOPED_ACTION(CriticalSectionLock)(CS); int Width=X2-X1+1; int Height=Y2-Y1+1; int I, J; for (I=0; I < Height; I++) { FAR_CHAR_INFO *PtrBuf = Buf.data() + (Y1 + I)*BufX + X1; for (J=0; J < Width; J++, ++PtrBuf) { PtrBuf->Attributes.BackgroundColor = 0; if(PtrBuf->Attributes.Flags&FCF_FG_4BIT) { PtrBuf->Attributes.ForegroundColor&=~0x8; if(!COLORVALUE(PtrBuf->Attributes.ForegroundColor)) { PtrBuf->Attributes.ForegroundColor=0x8; } } else { PtrBuf->Attributes.ForegroundColor&=~0x808080; if(!COLORVALUE(PtrBuf->Attributes.ForegroundColor)) { PtrBuf->Attributes.ForegroundColor = 0x808080; } } } } #ifdef DIRECT_SCREEN_OUT Flush(); #elif defined(DIRECT_RT) if (Global->DirectRT) Flush(); #endif }
static bool SetREPARSE_DATA_BUFFER(const string& Object, REPARSE_DATA_BUFFER* rdb) { if (!IsReparseTagValid(rdb->ReparseTag)) return false; SCOPED_ACTION(os::security::privilege){ SE_CREATE_SYMBOLIC_LINK_NAME }; const auto Attributes = os::fs::get_file_attributes(Object); if(Attributes&FILE_ATTRIBUTE_READONLY) { os::fs::set_file_attributes(Object, Attributes&~FILE_ATTRIBUTE_READONLY); } SCOPE_EXIT { if (Attributes&FILE_ATTRIBUTE_READONLY) os::fs::set_file_attributes(Object, Attributes); }; const auto& SetBuffer = [&](bool ForceElevation) { const os::fs::file fObject(Object, GetDesiredAccessForReparsePointChange(), 0, nullptr, OPEN_EXISTING, FILE_FLAG_OPEN_REPARSE_POINT, nullptr, ForceElevation); DWORD dwBytesReturned; return fObject && fObject.IoControl(FSCTL_SET_REPARSE_POINT, rdb, rdb->ReparseDataLength + REPARSE_DATA_BUFFER_HEADER_SIZE, nullptr, 0, &dwBytesReturned); }; if (SetBuffer(false)) return true; if (ElevationRequired(ELEVATION_MODIFY_REQUEST)) { // Open() succeeded, but IoControl() failed. We can't handle this automatically :( return SetBuffer(true); } return false; }
// used in stream selection void ScreenBuf::ApplyColor(int X1,int Y1,int X2,int Y2,const FarColor& Color,const FarColor& ExceptColor, bool ForceExFlags) { SCOPED_ACTION(CriticalSectionLock)(CS); if(X1<=ScrX && Y1<=ScrY && X2>=0 && Y2>=0) { X1=std::max(0,X1); X2=std::min(static_cast<int>(ScrX),X2); Y1=std::max(0,Y1); Y2=std::min(static_cast<int>(ScrY),Y2); for (int I = 0; I < Y2-Y1+1; I++) { FAR_CHAR_INFO* PtrBuf = Buf.data() + (Y1 + I)*BufX + X1; for (int J = 0; J < X2-X1+1; J++, ++PtrBuf) { if (PtrBuf->Attributes.ForegroundColor != ExceptColor.ForegroundColor || PtrBuf->Attributes.BackgroundColor != ExceptColor.BackgroundColor) { PtrBuf->Attributes=Color; } else if (ForceExFlags) { PtrBuf->Attributes.Flags = (PtrBuf->Attributes.Flags&~FCF_EXTENDEDFLAGS)|(Color.Flags&FCF_EXTENDEDFLAGS); } } } #ifdef DIRECT_SCREEN_OUT Flush(); #elif defined(DIRECT_RT) if (Global->DirectRT) Flush(); #endif } }
// Косметические преобразования строки пути. // CheckFullPath используется в FCTL_SET[ANOTHER]PANELDIR void PrepareDiskPath(string &strPath, bool CheckFullPath) { // elevation not required during cosmetic operation SCOPED_ACTION(elevation::suppress); if (!strPath.empty()) { if (strPath.size() > 1 && (strPath[1]==L':' || (IsSlash(strPath[0]) && IsSlash(strPath[1])))) { ReplaceSlashToBackslash(strPath); bool DoubleSlash = strPath[1]==L'\\'; while(ReplaceStrings(strPath, L"\\\\"sv, L"\\"sv)) ; if(DoubleSlash) { strPath = L'\\' + strPath; } if (CheckFullPath) { strPath = ConvertNameToFull(strPath); size_t DirOffset = 0; const auto Type = ParsePath(strPath, &DirOffset); if (Type == root_type::unknown && HasPathPrefix(strPath)) { DirOffset = 4; } size_t StartPos = DirOffset; if (StartPos < strPath.size()) { string TmpStr; TmpStr.reserve(strPath.size()); size_t LastPos = StartPos; const auto EndsWithSlash = IsSlash(strPath.back()); for (size_t i = StartPos; i <= strPath.size(); ++i) { if ((i < strPath.size() && IsSlash(strPath[i])) || (i == strPath.size() && !EndsWithSlash)) { TmpStr.assign(strPath, 0, i); os::fs::find_data fd; if (os::fs::get_find_data(TmpStr, fd)) { strPath.replace(LastPos, i - LastPos, fd.FileName); i += fd.FileName.size() - (i - LastPos); } if (i != strPath.size()) { LastPos = i + 1; } } } } } if (ParsePath(strPath) == root_type::drive_letter) { strPath[0] = upper(strPath[0]); } } } }
static int MainProcess( const string& EditName, const string& ViewName, const string& DestName1, const string& DestName2, int StartLine, int StartChar ) { SCOPED_ACTION(ChangePriority)(THREAD_PRIORITY_NORMAL); FarColor InitAttributes={}; console.GetTextAttributes(InitAttributes); SetRealColor(colors::PaletteColorToFarColor(COL_COMMANDLINEUSERSCREEN)); string ename(EditName),vname(ViewName), apanel(DestName1),ppanel(DestName2); if (ConfigProvider().ShowProblems()) { ename.clear(); vname.clear(); StartLine = StartChar = -1; apanel = Global->Opt->ProfilePath; ppanel = Global->Opt->LocalProfilePath; } if (!ename.empty() || !vname.empty()) { Global->OnlyEditorViewerUsed = true; _tran(SysLog(L"create dummy panels")); Global->CtrlObject->CreateDummyFilePanels(); Global->WindowManager->PluginCommit(); Global->CtrlObject->Plugins->LoadPlugins(); Global->CtrlObject->Macro.LoadMacros(true, true); if (!ename.empty()) { const auto ShellEditor = FileEditor::create(ename, CP_DEFAULT, FFILEEDIT_CANNEWFILE | FFILEEDIT_ENABLEF6, StartLine, StartChar); _tran(SysLog(L"make shelleditor %p",ShellEditor)); if (!ShellEditor->GetExitCode()) // ???????????? { Global->WindowManager->ExitMainLoop(0); } } // TODO: Этот else убрать только после разборок с возможностью задавать несколько /e и /v в ком.строке else if (!vname.empty()) { const auto ShellViewer = FileViewer::create(vname, true); if (!ShellViewer->GetExitCode()) { Global->WindowManager->ExitMainLoop(0); } _tran(SysLog(L"make shellviewer, %p",ShellViewer)); } Global->WindowManager->EnterMainLoop(); } else { int DirCount=0; // воспользуемся тем, что ControlObject::Init() создает панели // юзая Global->Opt->* const auto& SetupPanel = [&](bool active) { ++DirCount; string strPath = active? apanel : ppanel; if (os::fs::is_file(strPath)) { CutToParent(strPath); } bool Root = false; const auto Type = ParsePath(strPath, nullptr, &Root); if(Root && (Type == root_type::drive_letter || Type == root_type::unc_drive_letter || Type == root_type::volume)) { AddEndSlash(strPath); } auto& CurrentPanelOptions = (Global->Opt->LeftFocus == active)? Global->Opt->LeftPanel : Global->Opt->RightPanel; CurrentPanelOptions.m_Type = static_cast<int>(panel_type::FILE_PANEL); // сменим моду панели CurrentPanelOptions.Visible = true; // и включим ее CurrentPanelOptions.Folder = strPath; }; if (!apanel.empty()) { SetupPanel(true); if (!ppanel.empty()) { SetupPanel(false); } } // теперь все готово - создаем панели! Global->CtrlObject->Init(DirCount); // а теперь "провалимся" в каталог или хост-файл (если получится ;-) if (!apanel.empty()) // активная панель { const auto ActivePanel = Global->CtrlObject->Cp()->ActivePanel(); const auto AnotherPanel = Global->CtrlObject->Cp()->PassivePanel(); if (!ppanel.empty()) // пассивная панель { FarChDir(AnotherPanel->GetCurDir()); if (IsPluginPrefixPath(ppanel)) { AnotherPanel->Parent()->SetActivePanel(AnotherPanel); execute_info Info; Info.Command = ppanel; Global->CtrlObject->CmdLine()->ExecString(Info); ActivePanel->Parent()->SetActivePanel(ActivePanel); } else { const auto strPath = PointToName(ppanel); if (!strPath.empty()) { if (AnotherPanel->GoToFile(strPath)) AnotherPanel->ProcessKey(Manager::Key(KEY_CTRLPGDN)); } } } FarChDir(ActivePanel->GetCurDir()); if (IsPluginPrefixPath(apanel)) { execute_info Info; Info.Command = apanel; Global->CtrlObject->CmdLine()->ExecString(Info); } else { const auto strPath = PointToName(apanel); if (!strPath.empty()) { if (ActivePanel->GoToFile(strPath)) ActivePanel->ProcessKey(Manager::Key(KEY_CTRLPGDN)); } } // !!! ВНИМАНИЕ !!! // Сначала редравим пассивную панель, а потом активную! AnotherPanel->Redraw(); ActivePanel->Redraw(); } Global->WindowManager->EnterMainLoop(); } TreeList::FlushCache(); // очистим за собой! SetScreen(0,0,ScrX,ScrY,L' ',colors::PaletteColorToFarColor(COL_COMMANDLINEUSERSCREEN)); console.SetTextAttributes(InitAttributes); Global->ScrBuf->ResetLockCount(); Global->ScrBuf->Flush(); return 0; }
void language::load(const string& Path, const string& Language, int CountNeed) { SCOPED_ACTION(GuardLastError); auto Data = m_Data->create(); const auto LangFileData = OpenLangFile(Path, LangFileMask, Language); const auto& LangFile = std::get<0>(LangFileData); const auto LangFileCodePage = std::get<2>(LangFileData); if (!LangFile) { throw MAKE_EXCEPTION(exception, L"Cannot find language data"sv); } Data->m_FileName = LangFile.GetName(); if (CountNeed != -1) { Data->reserve(CountNeed); } std::unordered_map<string, size_t> id_map; string label, text; for (const auto& i: enum_file_lines(LangFile, LangFileCodePage)) { bool have_text; parse_lng_line(trim(i.Str), label, text, have_text); if (have_text) { auto idx = Data->size(); Data->add(ConvertString(text)); if (!label.empty()) { id_map[label] = idx; label.clear(); } } } // Проведем проверку на количество строк в LNG-файлах if (CountNeed != -1 && CountNeed != static_cast<int>(Data->size())) { throw MAKE_EXCEPTION(exception, Data->m_FileName + L": language data is incorrect or damaged"sv); } // try to load Far<LNG>.lng.custom file(s) // if (!id_map.empty()) { const auto& LoadStrings = [&](const string& FileName) { const os::fs::file CustomFile(FileName, FILE_READ_DATA, FILE_SHARE_READ, nullptr, OPEN_EXISTING); if (!CustomFile) return; const auto CustomFileCodepage = GetFileCodepage(CustomFile, encoding::codepage::oem(), nullptr, false); label.clear(); for (const auto& i: enum_file_lines(CustomFile, CustomFileCodepage)) { bool have_text; parse_lng_line(trim(i.Str), label, text, have_text); if (have_text && !label.empty()) { const auto found = id_map.find(label); if (found != id_map.end()) { Data->set_at(found->second, ConvertString(text)); } label.clear(); } } }; const auto CustomLngInSameDir = Data->m_FileName + L".custom"sv; const auto CustomLngInProfileDir = concat(Global->Opt->ProfilePath, L'\\', ExtractFileName(CustomLngInSameDir)); LoadStrings(CustomLngInSameDir); LoadStrings(CustomLngInProfileDir); } m_Data = std::move(Data); }
void PrintFiles(FileList* SrcPanel) { _ALGO(CleverSysLog clv(L"Alt-F5 (PrintFiles)")); string strPrinterName; DWORD Needed = 0, Returned; DWORD FileAttr; string strSelName; size_t DirsCount=0; size_t SelCount=SrcPanel->GetSelCount(); if (!SelCount) { _ALGO(SysLog(L"Error: !SelCount")); return; } // проверка каталогов _ALGO(SysLog(L"Check for FILE_ATTRIBUTE_DIRECTORY")); SrcPanel->GetSelName(nullptr,FileAttr); while (SrcPanel->GetSelName(&strSelName,FileAttr)) { if (TestParentFolderName(strSelName) || (FileAttr & FILE_ATTRIBUTE_DIRECTORY)) DirsCount++; } if (DirsCount==SelCount) return; EnumPrinters(PRINTER_ENUM_LOCAL | PRINTER_ENUM_CONNECTIONS, nullptr, PRINTER_INFO_LEVEL, nullptr, 0, &Needed, &Returned); if (!Needed) return; block_ptr<PRINTER_INFO> pi(Needed); if (!EnumPrinters(PRINTER_ENUM_LOCAL|PRINTER_ENUM_CONNECTIONS,nullptr,PRINTER_INFO_LEVEL,(LPBYTE)pi.get(),Needed,&Needed,&Returned)) { Global->CatchError(); Message(MSG_WARNING|MSG_ERRORTYPE,1,MSG(MPrintTitle),MSG(MCannotEnumeratePrinters),MSG(MOk)); return; } { _ALGO(CleverSysLog clv2(L"Show Menu")); LangString strTitle; string strName; if (SelCount==1) { SrcPanel->GetSelName(nullptr,FileAttr); SrcPanel->GetSelName(&strName,FileAttr); strSelName = TruncStr(strName,50); strTitle = MPrintTo; strTitle << InsertQuote(strSelName); } else { _ALGO(SysLog(L"Correct: SelCount-=DirsCount")); SelCount-=DirsCount; strTitle = MPrintFilesTo; strTitle << SelCount; } VMenu2 PrinterList(strTitle,nullptr,0,ScrY-4); PrinterList.SetFlags(VMENU_WRAPMODE|VMENU_SHOWAMPERSAND); PrinterList.SetPosition(-1,-1,0,0); AddToPrintersMenu(&PrinterList,pi.get(),Returned); if (PrinterList.Run()<0) { _ALGO(SysLog(L"ESC")); return; } strPrinterName = NullToEmpty(static_cast<const wchar_t*>(PrinterList.GetUserData(nullptr, 0))); } HANDLE hPrinter; if (!OpenPrinter(UNSAFE_CSTR(strPrinterName), &hPrinter,nullptr)) { Global->CatchError(); Message(MSG_WARNING|MSG_ERRORTYPE,1,MSG(MPrintTitle),MSG(MCannotOpenPrinter), strPrinterName.data(),MSG(MOk)); _ALGO(SysLog(L"Error: Cannot Open Printer")); return; } { _ALGO(CleverSysLog clv3(L"Print selected Files")); SCOPED_ACTION(SaveScreen); auto PR_PrintMsg = [](){ Message(0, 0, MSG(MPrintTitle), MSG(MPreparingForPrinting)); }; SCOPED_ACTION(TPreRedrawFuncGuard)(std::make_unique<PreRedrawItem>(PR_PrintMsg)); SetCursorType(false, 0); PR_PrintMsg(); auto hPlugin=SrcPanel->GetPluginHandle(); int PluginMode=SrcPanel->GetMode()==PLUGIN_PANEL && !Global->CtrlObject->Plugins->UseFarCommand(hPlugin,PLUGIN_FARGETFILE); SrcPanel->GetSelName(nullptr,FileAttr); while (SrcPanel->GetSelName(&strSelName,FileAttr)) { if (TestParentFolderName(strSelName) || (FileAttr & FILE_ATTRIBUTE_DIRECTORY)) continue; int Success=FALSE; string FileName; string strTempDir, strTempName; if (PluginMode) { if (FarMkTempEx(strTempDir)) { api::CreateDirectory(strTempDir,nullptr); auto ListItem = SrcPanel->GetLastSelectedItem(); if (ListItem) { PluginPanelItem PanelItem; FileList::FileListToPluginItem(*ListItem, &PanelItem); if (Global->CtrlObject->Plugins->GetFile(hPlugin,&PanelItem,strTempDir,strTempName,OPM_SILENT)) FileName = strTempName; else api::RemoveDirectory(strTempDir); FreePluginPanelItem(PanelItem); } } } else FileName = strSelName; api::File SrcFile; if(SrcFile.Open(FileName, GENERIC_READ, FILE_SHARE_READ|FILE_SHARE_WRITE, nullptr, OPEN_EXISTING)) { DOC_INFO_1 di1 = {UNSAFE_CSTR(FileName)}; if (StartDocPrinter(hPrinter,1,(LPBYTE)&di1)) { char Buffer[8192]; DWORD Read,Written; Success=TRUE; while (SrcFile.Read(Buffer, sizeof(Buffer), Read) && Read > 0) if (!WritePrinter(hPrinter,Buffer,Read,&Written)) { Global->CatchError(); Success=FALSE; break; } EndDocPrinter(hPrinter); } SrcFile.Close(); } if (!strTempName.empty()) { DeleteFileWithFolder(strTempName); } if (Success) SrcPanel->ClearLastGetSelection(); else { if (Message(MSG_WARNING|MSG_ERRORTYPE,2,MSG(MPrintTitle),MSG(MCannotPrint), strSelName.data(),MSG(MSkip),MSG(MCancel))) break; } } ClosePrinter(hPrinter); } SrcPanel->Redraw(); }
/* "Сбросить" виртуальный буфер на консоль */ void ScreenBuf::Flush(bool SuppressIndicators) { SCOPED_ACTION(CriticalSectionLock)(CS); if (!LockCount) { if (!SuppressIndicators) { if(Global->CtrlObject && (Global->CtrlObject->Macro.IsRecording() || (Global->CtrlObject->Macro.IsExecuting() && Global->Opt->Macro.ShowPlayIndicator)) ) { MacroChar=Buf[0]; MacroCharUsed=true; if(Global->CtrlObject->Macro.IsRecording()) { Buf[0].Char=L'R'; Buf[0].Attributes = Colors::ConsoleColorToFarColor(B_LIGHTRED|F_WHITE); } else { Buf[0].Char=L'P'; Buf[0].Attributes = Colors::ConsoleColorToFarColor(B_GREEN|F_WHITE); } } if(Global->Elevation->Elevated()) { ElevationChar=Buf[BufX*BufY-1]; ElevationCharUsed=true; Buf[BufX*BufY-1].Char=L'A'; Buf[BufX*BufY-1].Attributes = Colors::ConsoleColorToFarColor(B_LIGHTRED|F_WHITE); } } if (!SBFlags.Check(SBFLAGS_FLUSHEDCURTYPE) && !CurVisible) { CONSOLE_CURSOR_INFO cci={CurSize,CurVisible}; Global->Console->SetCursorInfo(cci); SBFlags.Set(SBFLAGS_FLUSHEDCURTYPE); } if (!SBFlags.Check(SBFLAGS_FLUSHED)) { SBFlags.Set(SBFLAGS_FLUSHED); if (Global->WaitInMainLoop && Global->Opt->Clock && !Global->ProcessShowClock) { ShowTime(FALSE); } std::list<SMALL_RECT>WriteList; bool Changes=false; if (SBFlags.Check(SBFLAGS_USESHADOW)) { FAR_CHAR_INFO* PtrBuf = Buf.data(), *PtrShadow = Shadow.data(); if (Global->Opt->ClearType) { //Для полного избавления от артефактов ClearType будем перерисовывать на всю ширину. //Чревато тормозами/миганием в зависимости от конфигурации системы. SMALL_RECT WriteRegion={0,0,static_cast<SHORT>(BufX-1),0}; for (SHORT I=0; I<BufY; I++, PtrBuf+=BufX, PtrShadow+=BufX) { WriteRegion.Top=I; WriteRegion.Bottom=I-1; while (I<BufY && memcmp(PtrBuf,PtrShadow,BufX*sizeof(FAR_CHAR_INFO))!=0) { I++; PtrBuf+=BufX; PtrShadow+=BufX; WriteRegion.Bottom++; } if (WriteRegion.Bottom >= WriteRegion.Top) { WriteList.emplace_back(WriteRegion); Changes=true; } } } else { bool Started=false; SMALL_RECT WriteRegion={static_cast<SHORT>(BufX-1),static_cast<SHORT>(BufY-1),0,0}; for (SHORT I=0; I<BufY; I++) { for (SHORT J=0; J<BufX; J++,++PtrBuf,++PtrShadow) { if (memcmp(PtrBuf,PtrShadow,sizeof(FAR_CHAR_INFO))!=0) { WriteRegion.Left=std::min(WriteRegion.Left,J); WriteRegion.Top=std::min(WriteRegion.Top,I); WriteRegion.Right=std::max(WriteRegion.Right,J); WriteRegion.Bottom=std::max(WriteRegion.Bottom,I); Changes=true; Started=true; } else if (Started && I>WriteRegion.Bottom && J>=WriteRegion.Left) { //BUGBUG: при включенном СlearType-сглаживании на экране остаётся "мусор" - тонкие вертикальные полосы // кстати, и при выключенном тоже (но реже). // баг, конечно, не наш, но что делать. // расширяем область прорисовки влево-вправо на 1 символ: WriteRegion.Left=std::max(static_cast<SHORT>(0),static_cast<SHORT>(WriteRegion.Left-1)); WriteRegion.Right=std::min(static_cast<SHORT>(WriteRegion.Right+1),static_cast<SHORT>(BufX-1)); bool Merge=false; if (!WriteList.empty()) { SMALL_RECT& Last=WriteList.back(); const int MAX_DELTA = 5; if (WriteRegion.Top-1==Last.Bottom && ((WriteRegion.Left>=Last.Left && WriteRegion.Left-Last.Left<MAX_DELTA) || (Last.Right>=WriteRegion.Right && Last.Right-WriteRegion.Right<MAX_DELTA))) { Last.Bottom=WriteRegion.Bottom; Last.Left=std::min(Last.Left,WriteRegion.Left); Last.Right=std::max(Last.Right,WriteRegion.Right); Merge=true; } } if (!Merge) WriteList.emplace_back(WriteRegion); WriteRegion.Left=BufX-1; WriteRegion.Top=BufY-1; WriteRegion.Right=0; WriteRegion.Bottom=0; Started=false; } } } if (Started) { WriteList.emplace_back(WriteRegion); } } } else { Changes=true; SMALL_RECT WriteRegion={0,0,static_cast<SHORT>(BufX-1),static_cast<SHORT>(BufY-1)}; WriteList.emplace_back(WriteRegion); } if (Changes) { std::for_each(CONST_RANGE(WriteList, i) { COORD BufferSize={BufX, BufY}, BufferCoord={i.Left, i.Top}; SMALL_RECT WriteRegion = i; Global->Console->WriteOutput(Buf.data(), BufferSize, BufferCoord, WriteRegion); }); Global->Console->Commit(); std::copy(ALL_CONST_RANGE(Buf), Shadow.begin()); }
void DizList::Read(const string& Path, const string* DizName) { Reset(); struct DizPreRedrawItem : public PreRedrawItem { DizPreRedrawItem() : PreRedrawItem(PR_ReadingMsg) {} }; SCOPED_ACTION(TPreRedrawFuncGuard)(std::make_unique<DizPreRedrawItem>()); const wchar_t *NamePtr=Global->Opt->Diz.strListNames.data(); for (;;) { if (DizName) { strDizFileName = *DizName; } else { strDizFileName = Path; if (!PathCanHoldRegularFile(strDizFileName)) break; string strArgName; NamePtr = GetCommaWord(NamePtr, strArgName); if (!NamePtr) break; AddEndSlash(strDizFileName); strDizFileName += strArgName; } os::fs::file DizFile; if (DizFile.Open(strDizFileName,GENERIC_READ, FILE_SHARE_READ, nullptr, OPEN_EXISTING)) { clock_t StartTime=clock(); uintptr_t CodePage=CP_DEFAULT; bool bSigFound=false; if (!GetFileFormat(DizFile,CodePage,&bSigFound,false) || !bSigFound) CodePage = Global->Opt->Diz.AnsiByDefault ? CP_ACP : CP_OEMCP; GetFileString GetStr(DizFile, CodePage); auto LastAdded = DizData.end(); string DizText; while (GetStr.GetString(DizText)) { if (!(DizData.size() & 127) && clock() - StartTime > CLOCKS_PER_SEC) { SetCursorType(false, 0); PR_ReadingMsg(); if (CheckForEsc()) break; } RemoveTrailingSpaces(DizText); if (!DizText.empty()) { if(!IsSpace(DizText.front())) { LastAdded = AddRecord(DizText); } else { if (LastAdded != DizData.end()) { LastAdded->second.emplace_back(DizText); } } } } OrigCodePage=CodePage; Modified=false; DizFile.Close(); return; } if (DizName) break; } Modified=false; strDizFileName.clear(); }
void FileList::ReadFileNames(int KeepSelection, int UpdateEvenIfPanelInvisible, int DrawMessage) { SCOPED_ACTION(TPreRedrawFuncGuard)(std::make_unique<FileListPreRedrawItem>()); SCOPED_ACTION(TaskBar)(false); strOriginalCurDir = strCurDir; if (!IsVisible() && !UpdateEvenIfPanelInvisible) { UpdateRequired=TRUE; UpdateRequiredMode=KeepSelection; return; } UpdateRequired=FALSE; AccessTimeUpdateRequired=FALSE; DizRead=FALSE; api::FAR_FIND_DATA fdata; decltype(ListData) OldData; string strCurName, strNextCurName; StopFSWatcher(); if (this!=Global->CtrlObject->Cp()->LeftPanel && this!=Global->CtrlObject->Cp()->RightPanel) return; string strSaveDir; api::GetCurrentDirectory(strSaveDir); { string strOldCurDir(strCurDir); if (!SetCurPath()) { FlushInputBuffer(); // Очистим буффер ввода, т.к. мы уже можем быть в другом месте... if (strCurDir == strOldCurDir) //?? i?? { GetPathRoot(strOldCurDir,strOldCurDir); if (!api::IsDiskInDrive(strOldCurDir)) IfGoHome(strOldCurDir.front()); /* При смене каталога путь не изменился */ } return; } } SortGroupsRead=FALSE; if (GetFocus()) Global->CtrlObject->CmdLine->SetCurDir(strCurDir); LastCurFile=-1; Panel *AnotherPanel=Global->CtrlObject->Cp()->GetAnotherPanel(this); AnotherPanel->QViewDelTempName(); size_t PrevSelFileCount=SelFileCount; SelFileCount=0; SelFileSize=0; TotalFileCount=0; TotalFileSize=0; CacheSelIndex=-1; CacheSelClearIndex=-1; FreeDiskSize = -1; if (Global->Opt->ShowPanelFree) { api::GetDiskSize(strCurDir, nullptr, nullptr, &FreeDiskSize); } if (!ListData.empty()) { strCurName = ListData[CurFile].strName; if (ListData[CurFile].Selected && !ReturnCurrentFile) { for (size_t i=CurFile+1; i < ListData.size(); i++) { if (!ListData[i].Selected) { strNextCurName = ListData[i].strName; break; } } } } if (KeepSelection || PrevSelFileCount>0) { OldData.swap(ListData); } else DeleteListData(ListData); DWORD FileSystemFlags = 0; string PathRoot; GetPathRoot(strCurDir, PathRoot); api::GetVolumeInformation(PathRoot, nullptr, nullptr, nullptr, &FileSystemFlags, nullptr); ListData.clear(); bool ReadOwners = IsColumnDisplayed(OWNER_COLUMN); bool ReadNumLinks = IsColumnDisplayed(NUMLINK_COLUMN); bool ReadNumStreams = IsColumnDisplayed(NUMSTREAMS_COLUMN); bool ReadStreamsSize = IsColumnDisplayed(STREAMSSIZE_COLUMN); if (!(FileSystemFlags&FILE_SUPPORTS_HARD_LINKS) && IsWindows7OrGreater()) { ReadNumLinks = false; } if(!(FileSystemFlags&FILE_NAMED_STREAMS)) { ReadNumStreams = false; ReadStreamsSize = false; } string strComputerName; if (ReadOwners) { string strTemp; CurPath2ComputerName(strCurDir, strComputerName, strTemp); } SetLastError(ERROR_SUCCESS); // сформируем заголовок вне цикла string Title = MakeSeparator(X2-X1-1, 9, nullptr); BOOL IsShowTitle=FALSE; BOOL NeedHighlight=Global->Opt->Highlight && PanelMode != PLUGIN_PANEL; if (!Filter) Filter = std::make_unique<FileFilter>(this,FFT_PANEL); //Рефреш текущему времени для фильтра перед началом операции Filter->UpdateCurrentTime(); Global->CtrlObject->HiFiles->UpdateCurrentTime(); bool bCurDirRoot = false; ParsePath(strCurDir, nullptr, &bCurDirRoot); PATH_TYPE Type = ParsePath(strCurDir, nullptr, &bCurDirRoot); bool NetRoot = bCurDirRoot && (Type == PATH_REMOTE || Type == PATH_REMOTEUNC); string strFind(strCurDir); AddEndSlash(strFind); strFind+=L'*'; api::FindFile Find(strFind, true); DWORD FindErrorCode = ERROR_SUCCESS; bool UseFilter=Filter->IsEnabledOnPanel(); bool ReadCustomData=IsColumnDisplayed(CUSTOM_COLUMN0)!=0; DWORD StartTime = GetTickCount(); std::all_of(CONST_RANGE(Find, fdata) -> bool { Global->CatchError(); FindErrorCode = Global->CaughtError(); if ((Global->Opt->ShowHidden || !(fdata.dwFileAttributes & (FILE_ATTRIBUTE_HIDDEN|FILE_ATTRIBUTE_SYSTEM))) && (!UseFilter || Filter->FileInFilter(fdata, nullptr, &fdata.strFileName))) { if (ListData.size() == ListData.capacity()) ListData.reserve(ListData.size() + 4096); ListData.emplace_back(VALUE_TYPE(ListData)()); auto& NewItem = ListData.back(); NewItem.FileAttr = fdata.dwFileAttributes; NewItem.CreationTime = fdata.ftCreationTime; NewItem.AccessTime = fdata.ftLastAccessTime; NewItem.WriteTime = fdata.ftLastWriteTime; NewItem.ChangeTime = fdata.ftChangeTime; NewItem.FileSize = fdata.nFileSize; NewItem.AllocationSize = fdata.nAllocationSize; NewItem.strName = fdata.strFileName; NewItem.strShortName = fdata.strAlternateFileName; NewItem.Position = ListData.size() - 1; NewItem.NumberOfLinks=1; if (fdata.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) { NewItem.ReparseTag=fdata.dwReserved0; //MSDN } 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)? strCurDir : fdata.strFileName, NewItem.StreamsSize, NewItem.NumberOfStreams); } if (ReadCustomData) NewItem.strCustomData = Global->CtrlObject->Plugins->GetCustomData(NewItem.strName); if (!(fdata.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) TotalFileCount++; DWORD CurTime = GetTickCount(); if (CurTime - StartTime > (DWORD)Global->Opt->RedrawTimeout) { StartTime = CurTime; if (IsVisible()) { if (!IsShowTitle) { if (!DrawMessage) { Text(X1+1,Y1,ColorIndexToColor(COL_PANELBOX),Title); IsShowTitle=TRUE; SetColor(Focus ? COL_PANELSELECTEDTITLE:COL_PANELTITLE); } } LangString strReadMsg(MReadingFiles); strReadMsg << ListData.size(); if (DrawMessage) { ReadFileNamesMsg(strReadMsg); } else { TruncStr(strReadMsg,static_cast<int>(Title.size())-2); int MsgLength=(int)strReadMsg.size(); GotoXY(X1+1+(static_cast<int>(Title.size())-MsgLength-1)/2,Y1); Global->FS << L" "<<strReadMsg<<L" "; } } Global->CtrlObject->Macro.SuspendMacros(true); bool check = CheckForEsc(); Global->CtrlObject->Macro.SuspendMacros(false); if (check) { // break loop return false; } } } return true; });
ShellDelete::ShellDelete(Panel *SrcPanel,bool Wipe): ReadOnlyDeleteMode(-1), m_SkipMode(-1), SkipWipeMode(-1), SkipFoldersMode(-1), ProcessedItems(0) { SCOPED_ACTION(ChangePriority)(Global->Opt->DelThreadPriority); SCOPED_ACTION(TPreRedrawFuncGuard)(std::make_unique<DelPreRedrawItem>()); os::FAR_FIND_DATA FindData; string strDeleteFilesMsg; string strSelName; string strSelShortName; string strDizName; DWORD FileAttr; size_t SelCount; int UpdateDiz; int DizPresent; int Ret; BOOL NeedUpdate=TRUE, NeedSetUpADir=FALSE; bool Opt_DeleteToRecycleBin=Global->Opt->DeleteToRecycleBin; /*& 31.05.2001 OT Запретить перерисовку текущего окна*/ auto WindowFromLaunched = Global->WindowManager->GetCurrentWindow(); WindowFromLaunched->Lock(); bool DeleteAllFolders=!Global->Opt->Confirm.DeleteFolder; UpdateDiz=(Global->Opt->Diz.UpdateMode==DIZ_UPDATE_ALWAYS || (SrcPanel->IsDizDisplayed() && Global->Opt->Diz.UpdateMode==DIZ_UPDATE_IF_DISPLAYED)); SCOPE_EXIT { Global->Opt->DeleteToRecycleBin=Opt_DeleteToRecycleBin; // Разрешить перерисовку окна WindowFromLaunched->Unlock(); if (NeedUpdate) { ShellUpdatePanels(SrcPanel,NeedSetUpADir); } }; if (!(SelCount=SrcPanel->GetSelCount())) return; // Удаление в корзину только для FIXED-дисков { string strRoot; SrcPanel->GetSelName(nullptr,FileAttr); SrcPanel->GetSelName(&strSelName,FileAttr); ConvertNameToFull(strSelName, strRoot); GetPathRoot(strRoot,strRoot); if (Global->Opt->DeleteToRecycleBin && FAR_GetDriveType(strRoot) != DRIVE_FIXED) Global->Opt->DeleteToRecycleBin=0; } if (SelCount==1) { SrcPanel->GetSelName(nullptr,FileAttr); SrcPanel->GetSelName(&strSelName,FileAttr); if (TestParentFolderName(strSelName) || strSelName.empty()) { NeedUpdate=FALSE; return; } strDeleteFilesMsg = strSelName; QuoteLeadingSpace(strDeleteFilesMsg); } else { // в зависимости от числа ставим нужное окончание const wchar_t *Ends; FormatString StrItems; StrItems << SelCount; Ends=MSG(MAskDeleteItemsA); size_t LenItems = StrItems.size(); if (LenItems > 0) { if ((LenItems >= 2 && StrItems[LenItems-2] == L'1') || StrItems[LenItems-1] >= L'5' || StrItems[LenItems-1] == L'0') Ends=MSG(MAskDeleteItemsS); else if (StrItems[LenItems-1] == L'1') Ends=MSG(MAskDeleteItems0); } strDeleteFilesMsg = LangString(MAskDeleteItems) << SelCount << Ends; } Ret=1; // Обработка "удаления" линков if ((FileAttr & FILE_ATTRIBUTE_REPARSE_POINT) && SelCount==1) { string strJuncName; ConvertNameToFull(strSelName,strJuncName); if (GetReparsePointInfo(strJuncName, strJuncName)) // ? SelName ? { NormalizeSymlinkName(strJuncName); string strAskDeleteLink=MSG(MAskDeleteLink); os::fs::file_status Status(strJuncName); if (os::fs::exists(Status)) { strAskDeleteLink+=L" "; strAskDeleteLink += MSG(is_directory(Status)? MAskDeleteLinkFolder : MAskDeleteLinkFile); } Ret=Message(0,2,MSG(MDeleteLinkTitle), strDeleteFilesMsg.data(), strAskDeleteLink.data(), strJuncName.data(), MSG(MDeleteLinkDelete), MSG(MCancel)); if (Ret) return; } } if (Ret && Global->Opt->Confirm.Delete) { LNGID mTitle = Wipe ? MDeleteWipeTitle : MDeleteTitle; LNGID mDText; string tText; LNGID mDBttn = Wipe ? MDeleteWipe : Global->Opt->DeleteToRecycleBin ? MDeleteRecycle : MDelete; bool bHilite = Global->Opt->DelOpt.HighlightSelected; int mshow = std::min(std::max((int)Global->Opt->DelOpt.ShowSelected, 1), ScrY/2); std::vector<string> items; items.push_back(strDeleteFilesMsg); if (SelCount == 1) { bool folder = (FileAttr & FILE_ATTRIBUTE_DIRECTORY) != 0; if (Wipe && !(FileAttr & FILE_ATTRIBUTE_REPARSE_POINT)) mDText = folder ? MAskWipeFolder : MAskWipeFile; else { if (Global->Opt->DeleteToRecycleBin) mDText = folder ? MAskDeleteRecycleFolder : MAskDeleteRecycleFile; else mDText = folder ? MAskDeleteFolder : MAskDeleteFile; } if (bHilite) { string name, sname; SrcPanel->GetCurName(name, sname); QuoteLeadingSpace(name); bHilite = strDeleteFilesMsg != name; } } else { if (Wipe) { mDText = MAskWipe; mTitle = MDeleteWipeTitle; } else mDText = Global->Opt->DeleteToRecycleBin ? MAskDeleteRecycle : MAskDelete; if (mshow > 1) { tText = MSG(mDText) + string(L" ") + strDeleteFilesMsg; items.clear(); DWORD attr; string name; SrcPanel->GetSelName(nullptr, attr); for (size_t i = 0; i < SelCount; ++i) { if (i == (size_t)mshow-1 && i+1 < SelCount) { items.push_back(L"..."); break; } SrcPanel->GetSelName(&name, attr); QuoteLeadingSpace(name); items.push_back(name); } } } intptr_t start_hilite = 0, end_hilite = 0; DialogBuilder Builder(mTitle, nullptr, [&](Dialog* Dlg, intptr_t Msg, intptr_t Param1, void* Param2) -> intptr_t { if (bHilite && Msg == DN_CTLCOLORDLGITEM && Param1 >= start_hilite && Param1 <= end_hilite) { auto Colors = static_cast<FarDialogItemColors*>(Param2); Colors->Colors[0] = Colors->Colors[1]; } return Dlg->DefProc(Msg, Param1, Param2); }); if (tText.empty()) tText = MSG(mDText); Builder.AddText(tText.data())->Flags = DIF_CENTERTEXT; if (bHilite || (mshow > 1 && SelCount > 1)) Builder.AddSeparator(); std::for_each(RANGE(items, i) { TruncStrFromCenter(i, ScrX+1-6*2); auto dx = Builder.AddText(i.data()); dx->Flags = (SelCount <= 1 || mshow <= 1 ? DIF_CENTERTEXT : 0) | DIF_SHOWAMPERSAND; size_t index = Builder.GetLastID(); end_hilite = index; if (!start_hilite) start_hilite = index; });
/* $ 06.07.2001 + Используем filemasks вместо GetCommaWord, этим самым добиваемся того, что можно использовать маски исключения - Убрал непонятный мне запрет на использование маски файлов типа "*.*" (был когда-то, вроде, такой баг-репорт) */ bool ProcessLocalFileTypes(const string& Name, const string& ShortName, FILETYPE_MODE Mode, bool AlwaysWaitFinish) { string strCommand, strDescription, strMask; { const auto TypesMenu = VMenu2::create(MSG(MSelectAssocTitle), nullptr, 0, ScrY - 4); TypesMenu->SetHelp(L"FileAssoc"); TypesMenu->SetMenuFlags(VMENU_WRAPMODE); TypesMenu->SetId(SelectAssocMenuId); int ActualCmdCount=0; // отображаемых ассоциаций в меню filemasks FMask; // для работы с масками файлов int CommandCount=0; DWORD Index=0; unsigned __int64 id; string FileName = PointToName(Name); while (ConfigProvider().AssocConfig()->EnumMasksForType(Mode,Index++,&id,strMask)) { strCommand.clear(); if (FMask.Set(strMask,FMF_SILENT)) { if (FMask.Compare(FileName)) { ConfigProvider().AssocConfig()->GetCommand(id,Mode,strCommand); if (!strCommand.empty()) { ConfigProvider().AssocConfig()->GetDescription(id,strDescription); CommandCount++; } } if (strCommand.empty()) continue; } string strCommandText = strCommand; SubstFileName(nullptr,strCommandText,Name, ShortName,nullptr,nullptr,nullptr,nullptr,TRUE); // все "подставлено", теперь проверим условия "if exist" if (!ExtractIfExistCommand(strCommandText)) continue; ActualCmdCount++; if (!strDescription.empty()) SubstFileName(nullptr,strDescription, Name, ShortName, nullptr, nullptr, nullptr, nullptr, TRUE); else strDescription = strCommandText; MenuItemEx TypesMenuItem(strDescription); TypesMenuItem.SetSelect(Index==1); TypesMenuItem.UserData = strCommand; TypesMenu->AddItem(TypesMenuItem); } if (!CommandCount) return false; if (!ActualCmdCount) return true; int ExitCode=0; if (ActualCmdCount>1) { ExitCode=TypesMenu->Run(); if (ExitCode<0) return true; } strCommand = *TypesMenu->GetUserDataPtr<string>(ExitCode); } string strListName, strAnotherListName, strShortListName, strAnotherShortListName; const string* ListNames[] = { &strListName, &strAnotherListName, &strShortListName, &strAnotherShortListName }; int PreserveLFN=SubstFileName(nullptr,strCommand, Name, ShortName, &strListName, &strAnotherListName, &strShortListName, &strAnotherShortListName); const auto ListFileUsed = !std::all_of(ALL_CONST_RANGE(ListNames), std::mem_fn(&string::empty)); // Снова все "подставлено", теперь проверим условия "if exist" if (ExtractIfExistCommand(strCommand)) { SCOPED_ACTION(PreserveLongName)(ShortName, PreserveLFN); RemoveExternalSpaces(strCommand); if (!strCommand.empty()) { Global->CtrlObject->CmdLine()->ExecString(strCommand,AlwaysWaitFinish, false, false, ListFileUsed, false, Mode == FILETYPE_VIEW || Mode == FILETYPE_ALTVIEW || Mode == FILETYPE_EDIT || Mode == FILETYPE_ALTEDIT); if (!(Global->Opt->ExcludeCmdHistory&EXCLUDECMDHISTORY_NOTFARASS) && !AlwaysWaitFinish) //AN { const auto curDir = Global->CtrlObject->CmdLine()->GetCurDir(); Global->CtrlObject->CmdHistory->AddToHistory(strCommand, HR_DEFAULT, nullptr, nullptr, curDir.data()); } } } std::for_each(CONST_RANGE(ListNames, i) { if (!i->empty()) os::DeleteFile(*i); });